]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: announce MT capabilities in IIH and LSP
authorChristian Franke <chris@opensourcerouting.org>
Thu, 27 Apr 2017 11:56:38 +0000 (13:56 +0200)
committerChristian Franke <chris@opensourcerouting.org>
Fri, 28 Apr 2017 10:03:23 +0000 (12:03 +0200)
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
isisd/isis_lsp.c
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_pdu.c
isisd/isis_tlv.c
isisd/isis_tlv.h

index d490bc47cd6112179cc2e782998889708dd94772..d7d76942a6648d3b925c4c798f0dcdd9c628f8b9 100644 (file)
@@ -53,6 +53,7 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 /* staticly assigned vars for printing purposes */
 char lsp_bits_string[200];     /* FIXME: enough ? */
@@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
       expected |= TLVFLAG_TE_IPV4_REACHABILITY;
       expected |= TLVFLAG_TE_ROUTER_ID;
     }
+  expected |= TLVFLAG_MT_ROUTER_INFORMATION;
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV4_INT_REACHABILITY;
   expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
@@ -838,6 +840,7 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
   struct in_addr *ipv4_addr;
   struct te_ipv4_reachability *te_ipv4_reach;
   struct ipv6_reachability *ipv6_reach;
+  struct mt_router_info *mt_router_info;
   struct in6_addr in6;
   u_char buff[BUFSIZ];
   u_char LSPid[255];
@@ -877,6 +880,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
        }
     }
 
+  for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
+    {
+      vty_out (vty, "  MT          : %s%s%s",
+               isis_mtid2str(mt_router_info->mtid),
+               mt_router_info->overload ? " (overload)" : "",
+               VTY_NEWLINE);
+    }
+
   /* for the hostname tlv */
   if (lsp->tlv_data.hostname)
     {
@@ -1344,6 +1355,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
       tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
     }
 
+  if (area_is_mt(area))
+    {
+      lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
+      lsp->tlv_data.mt_router_info = list_new();
+      lsp->tlv_data.mt_router_info->del = free_tlv;
+
+      struct isis_area_mt_setting **mt_settings;
+      unsigned int mt_count;
+
+      mt_settings = area_mt_settings(area, &mt_count);
+      for (unsigned int i = 0; i < mt_count; i++)
+        {
+          struct mt_router_info *info;
+
+          info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+          info->mtid = mt_settings[i]->mtid;
+          info->overload = mt_settings[i]->overload;
+          listnode_add(lsp->tlv_data.mt_router_info, info);
+          lsp_debug("ISIS (%s):   MT %s", area->area_tag, isis_mtid2str(info->mtid));
+        }
+      tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu);
+    }
+  else
+    {
+      lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag);
+    }
   /* Dynamic Hostname */
   if (area->dynhostname)
     {
index 7908fd4bb3b179680408cbb13326e1a7a7463449..6d43fdf03aa34137e9395d6e8f5e2671fa8ebb37 100644 (file)
@@ -182,6 +182,58 @@ area_write_mt_settings(struct isis_area *area, struct vty *vty)
   return written;
 }
 
+bool area_is_mt(struct isis_area *area)
+{
+  struct listnode *node, *node2;
+  struct isis_area_mt_setting *setting;
+  struct isis_circuit *circuit;
+  struct isis_circuit_mt_setting *csetting;
+
+  for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+    {
+      if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
+        return true;
+    }
+  for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+    {
+      for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
+        {
+          if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
+            return true;
+        }
+    }
+
+  return false;
+}
+
+struct isis_area_mt_setting**
+area_mt_settings(struct isis_area *area, unsigned int *mt_count)
+{
+  static unsigned int size = 0;
+  static struct isis_area_mt_setting **rv = NULL;
+
+  unsigned int count = 0;
+  struct listnode *node;
+  struct isis_area_mt_setting *setting;
+
+  for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+    {
+      if (!setting->enabled)
+        continue;
+
+      count++;
+      if (count > size)
+        {
+          rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+          size = count;
+        }
+      rv[count-1] = setting;
+    }
+
+  *mt_count = count;
+  return rv;
+}
+
 /* Circuit specific MT settings api */
 
 struct isis_circuit_mt_setting*
@@ -260,3 +312,46 @@ circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
     }
   return written;
 }
+
+struct isis_circuit_mt_setting**
+circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
+{
+  static unsigned int size = 0;
+  static struct isis_circuit_mt_setting **rv = NULL;
+
+  struct isis_area_mt_setting **area_settings;
+  unsigned int area_count;
+
+  unsigned int count = 0;
+
+  struct listnode *node;
+  struct isis_circuit_mt_setting *setting;
+
+  area_settings = area_mt_settings(circuit->area, &area_count);
+
+  for (unsigned int i = 0; i < area_count; i++)
+    {
+      for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
+        {
+          if (setting->mtid != area_settings[i]->mtid)
+            continue;
+          break;
+        }
+      if (!setting)
+        setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
+
+      if (!setting->enabled)
+        continue;
+
+      count++;
+      if (count > size)
+        {
+          rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+          size = count;
+        }
+      rv[count-1] = setting;
+    }
+
+  *mt_count = count;
+  return rv;
+}
index a6f401357753e90ff7b1b3dfd379cb8d8e2b1ad6..6b1711f4c88307fdbef85d43eaea17f0ba4df69a 100644 (file)
@@ -23,6 +23,9 @@
 #ifndef ISIS_MT_H
 #define ISIS_MT_H
 
+#define ISIS_MT_MASK           0x0fff
+#define ISIS_MT_OL_MASK        0x8000
+
 #define ISIS_MT_IPV4_UNICAST   0
 #define ISIS_MT_IPV4_MGMT      1
 #define ISIS_MT_IPV6_UNICAST   2
@@ -79,6 +82,9 @@ void area_mt_finish(struct isis_area *area);
 struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area,
                                                  uint16_t mtid);
 int area_write_mt_settings(struct isis_area *area, struct vty *vty);
+bool area_is_mt(struct isis_area *area);
+struct isis_area_mt_setting** area_mt_settings(struct isis_area *area,
+                                               unsigned int *mt_count);
 
 struct isis_circuit_mt_setting* circuit_lookup_mt_setting(
                                                 struct isis_circuit *circuit,
@@ -94,4 +100,6 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting(
                                                 struct isis_circuit *circuit,
                                                 uint16_t mtid);
 int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
+struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,
+                                                     unsigned int *mt_count);
 #endif
index 5fbf6c194ea72281d1e7729aa93503d73542e471..8909eb31e0d53b55aeac961b9aa1a484cf861f65 100644 (file)
@@ -53,6 +53,7 @@
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
 #define ISIS_MIN_PDU_LEN           13  /* partial seqnum pdu with id_len=2 */
@@ -471,6 +472,7 @@ process_p2p_hello (struct isis_circuit *circuit)
   expected |= TLVFLAG_NLPID;
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;
+  expected |= TLVFLAG_MT_ROUTER_INFORMATION;
 
   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
@@ -1021,6 +1023,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
   expected |= TLVFLAG_NLPID;
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;
+  expected |= TLVFLAG_MT_ROUTER_INFORMATION;
 
   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
@@ -2337,6 +2340,37 @@ send_hello (struct isis_circuit *circuit, int level)
     if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
       return ISIS_WARNING;
 
+  /*
+   * MT Supported TLV
+   *
+   * TLV gets included if no topology is enabled on the interface,
+   * if one topology other than #0 is enabled, or if multiple topologies
+   * are enabled.
+   */
+  struct isis_circuit_mt_setting **mt_settings;
+  unsigned int mt_count;
+
+  mt_settings = circuit_mt_settings(circuit, &mt_count);
+  if ((mt_count == 0 && area_is_mt(circuit->area))
+      || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
+      || (mt_count > 1))
+    {
+      struct list *mt_info = list_new();
+      mt_info->del = free_tlv;
+
+      for (unsigned int i = 0; i < mt_count; i++)
+        {
+          struct mt_router_info *info;
+
+          info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+          info->mtid = mt_settings[i]->mtid;
+          /* overload info is not valid in IIH, so it's not included here */
+          listnode_add(mt_info, info);
+        }
+      tlv_add_mt_router_info (mt_info, circuit->snd_stream);
+      list_free(mt_info);
+    }
+
   /* IPv6 Interface Address TLV */
   if (circuit->ipv6_router && circuit->ipv6_link &&
       listcount (circuit->ipv6_link) > 0)
index 4192fff9a852e79cbec843c4bcf3cde5b72822c7..14ebed94d31eb94216b9170929e16340e47201c4 100644 (file)
@@ -61,6 +61,8 @@ free_tlvs (struct tlvs *tlvs)
 {
   if (tlvs->area_addrs)
     list_delete (tlvs->area_addrs);
+  if (tlvs->mt_router_info)
+    list_delete (tlvs->mt_router_info);
   if (tlvs->is_neighs)
     list_delete (tlvs->is_neighs);
   if (tlvs->te_is_neighs)
@@ -786,6 +788,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
          pnt += length;
          break;
 
+       case MT_ROUTER_INFORMATION:
+         *found |= TLVFLAG_MT_ROUTER_INFORMATION;
+         if (*expected & TLVFLAG_MT_ROUTER_INFORMATION)
+           {
+             if (!tlvs->mt_router_info)
+               {
+                 tlvs->mt_router_info = list_new();
+                 tlvs->mt_router_info->del = free_tlv;
+               }
+             while (length > value_len)
+               {
+                 uint16_t mt_info;
+                 struct mt_router_info *info;
+
+                 if (value_len + sizeof(mt_info) > length) {
+                   zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag);
+                   pnt += length - value_len;
+                   break;
+                 }
+
+                 memcpy(&mt_info, pnt, sizeof(mt_info));
+                 pnt += sizeof(mt_info);
+                 value_len += sizeof(mt_info);
+
+                 mt_info = ntohs(mt_info);
+                 info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+                 info->mtid = mt_info & ISIS_MT_MASK;
+                 info->overload = mt_info & ISIS_MT_OL_MASK;
+                 listnode_add(tlvs->mt_router_info, info);
+               }
+           }
+         else
+           {
+             pnt += length;
+           }
+         break;
        default:
          zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
                     areatag, type, length);
@@ -825,6 +863,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
   return ISIS_OK;
 }
 
+int
+tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream)
+{
+  struct listnode *node;
+  struct mt_router_info *info;
+
+  uint16_t value[127];
+  uint16_t *pos = value;
+
+  for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info))
+    {
+      uint16_t mt_info;
+
+      mt_info = info->mtid;
+      if (info->overload)
+        mt_info |= ISIS_MT_OL_MASK;
+
+      *pos = htons(mt_info);
+      pos++;
+    }
+
+  return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
+                 (u_char*)value, stream);
+}
+
 int
 tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
 {
index f899b9e9db2f96af3d8128b741e71c4e47de17c1..12025ff73a799585490cf954cf7d385498550eae 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _ZEBRA_ISIS_TLV_H
 #define _ZEBRA_ISIS_TLV_H
 
+#include "isisd/isis_mt.h"
+
 /*
  * The list of TLVs we (should) support.
  * ____________________________________________________________________________
 #define TE_IPV4_REACHABILITY      135
 #define DYNAMIC_HOSTNAME          137
 #define GRACEFUL_RESTART          211
+#define MT_ROUTER_INFORMATION     229
 #define IPV6_ADDR                 232
 #define IPV6_REACHABILITY         236
 #define WAY3_HELLO                240
@@ -250,6 +253,12 @@ struct ipv6_reachability
 
 #define CTRL_INFO_SUBTLVS      0x20
 
+struct mt_router_info
+{
+  ISIS_MT_INFO_FIELDS
+  bool overload;
+};
+
 /*
  * Pointer to each tlv type, filled by parse_tlvs()
  */
@@ -260,6 +269,7 @@ struct tlvs
   struct nlpids *nlpids;
   struct te_router_id *router_id;
   struct list *area_addrs;
+  struct list *mt_router_info;
   struct list *is_neighs;
   struct list *te_is_neighs;
   struct list *es_neighs;
@@ -301,6 +311,7 @@ struct tlvs
 #define TLVFLAG_TE_ROUTER_ID              (1<<19)
 #define TLVFLAG_CHECKSUM                  (1<<20)
 #define TLVFLAG_GRACEFUL_RESTART          (1<<21)
+#define TLVFLAG_MT_ROUTER_INFORMATION     (1<<22)
 
 void init_tlvs (struct tlvs *tlvs, uint32_t expected);
 void free_tlvs (struct tlvs *tlvs);
@@ -310,6 +321,7 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
 int add_tlv (u_char, u_char, u_char *, struct stream *);
 void free_tlv (void *val);
 
+int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream);
 int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
 int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
 int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);