]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: track intersecting set of supported MTs for each adj
authorChristian Franke <chris@opensourcerouting.org>
Thu, 27 Apr 2017 11:56:41 +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_adjacency.c
isisd/isis_adjacency.h
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_pdu.c

index f55092487437e6163d8b8859cc64830242bbd4ca..c6fc6b008d2c4e881487efca54e29b0d612d70d3 100644 (file)
@@ -148,6 +148,8 @@ isis_delete_adj (void *arg)
   if (adj->ipv6_addrs)
     list_delete (adj->ipv6_addrs);
 
+  adj_mt_finish(adj);
+
   XFREE (MTYPE_ISIS_ADJACENCY, adj);
   return;
 }
@@ -521,3 +523,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list)
 
   return;
 }
+
+int
+isis_adj_usage2levels(enum isis_adj_usage usage)
+{
+  switch (usage)
+    {
+    case ISIS_ADJ_LEVEL1:
+      return IS_LEVEL_1;
+    case ISIS_ADJ_LEVEL2:
+      return IS_LEVEL_2;
+    case ISIS_ADJ_LEVEL1AND2:
+      return IS_LEVEL_1 | IS_LEVEL_2;
+    default:
+      break;
+    }
+  return 0;
+}
index 8539b03d6b9b3b22e1edb1a0c825928e2c506a1d..4f89e309601a077a2b97c9d61fc3b4977208f5b2 100644 (file)
@@ -97,6 +97,8 @@ struct isis_adjacency
   int flaps;                   /* number of adjacency flaps  */
   struct thread *t_expire;     /* expire after hold_time  */
   struct isis_circuit *circuit;        /* back pointer */
+  uint16_t *mt_set;             /* Topologies this adjacency is valid for */
+  unsigned int mt_count;              /* Number of entries in mt_set */
 };
 
 struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb);
@@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread);
 void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);
 void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
 void isis_adj_build_up_list (struct list *adjdb, struct list *list);
+int isis_adj_usage2levels(enum isis_adj_usage usage);
 
 #endif /* ISIS_ADJACENCY_H */
index 6d43fdf03aa34137e9395d6e8f5e2671fa8ebb37..4e36b914333aa338a9cc7f960d66969b899ddc3b 100644 (file)
 #include "isisd/isisd.h"
 #include "isisd/isis_memory.h"
 #include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_tlv.h"
 #include "isisd/isis_mt.h"
 
 DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
+DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
 
 /* MT naming api */
 const char *isis_mtid2str(uint16_t mtid)
 {
+  static char buf[sizeof("65535")];
+
   switch(mtid)
     {
       case ISIS_MT_IPV4_UNICAST:
@@ -47,7 +52,8 @@ const char *isis_mtid2str(uint16_t mtid)
       case ISIS_MT_IPV6_MGMT:
         return "ipv6-mgmt";
       default:
-        return NULL;
+        snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
+        return buf;
     }
 }
 
@@ -355,3 +361,79 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
   *mt_count = count;
   return rv;
 }
+
+static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
+                       uint16_t mtid)
+{
+  if (adj->mt_count < index + 1)
+    {
+      adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
+                             (index + 1) * sizeof(*adj->mt_set));
+      adj->mt_count = index + 1;
+    }
+  adj->mt_set[index] = mtid;
+}
+
+bool
+tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+                   struct isis_adjacency *adj)
+{
+  struct isis_circuit_mt_setting **mt_settings;
+  unsigned int circuit_mt_count;
+
+  unsigned int intersect_count = 0;
+
+  uint16_t *old_mt_set;
+  unsigned int old_mt_count;
+
+  old_mt_count = adj->mt_count;
+  if (old_mt_count)
+    {
+      old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
+      memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
+    }
+
+  mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
+  for (unsigned int i = 0; i < circuit_mt_count; i++)
+    {
+      if (!tlvs->mt_router_info)
+        {
+          /* Other end does not have MT enabled */
+          if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST)
+            adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
+        }
+      else
+        {
+          struct listnode *node;
+          struct mt_router_info *info;
+          for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
+            {
+              if (mt_settings[i]->mtid == info->mtid)
+                adj_mt_set(adj, intersect_count++, info->mtid);
+            }
+        }
+    }
+  adj->mt_count = intersect_count;
+
+  bool changed = false;
+
+  if (adj->mt_count != old_mt_count)
+    changed = true;
+
+  if (!changed && old_mt_count
+      && memcmp(adj->mt_set, old_mt_set,
+                old_mt_count * sizeof(*old_mt_set)))
+    changed = true;
+
+  if (old_mt_count)
+    XFREE(MTYPE_TMP, old_mt_set);
+
+  return changed;
+}
+
+void
+adj_mt_finish(struct isis_adjacency *adj)
+{
+  XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
+  adj->mt_count = 0;
+}
index 6b1711f4c88307fdbef85d43eaea17f0ba4df69a..3ad8c05e4710ff3ebccb0c9fadd23e0c353806f8 100644 (file)
@@ -67,8 +67,10 @@ struct isis_circuit_mt_setting {
 const char *isis_mtid2str(uint16_t mtid);
 uint16_t isis_str2mtid(const char *name);
 
+struct isis_adjacency;
 struct isis_area;
 struct isis_circuit;
+struct tlvs;
 
 struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
                                                     uint16_t mtid);
@@ -102,4 +104,7 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting(
 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);
+bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+                        struct isis_adjacency *adj);
+void adj_mt_finish(struct isis_adjacency *adj);
 #endif
index 8909eb31e0d53b55aeac961b9aa1a484cf861f65..9e90acf2e009278562923f7b7e1ae8b54e41d6f9 100644 (file)
@@ -635,6 +635,8 @@ process_p2p_hello (struct isis_circuit *circuit)
   if (found & TLVFLAG_IPV6_ADDR)
     tlvs_to_adj_ipv6_addrs (&tlvs, adj);
 
+  bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
   /* lets take care of the expiry */
   THREAD_TIMER_OFF (adj->t_expire);
   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -871,6 +873,13 @@ process_p2p_hello (struct isis_circuit *circuit)
       /* down - area mismatch */
       isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
     }
+
+  if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+    {
+      lsp_regenerate_schedule(adj->circuit->area,
+                              isis_adj_usage2levels(adj->adj_usage), 0);
+    }
+
   /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
   /* FIXME - Missing parts */
 
@@ -1226,6 +1235,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
 
   adj->circuit_t = hdr.circuit_t;
 
+  bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
   /* lets take care of the expiry */
   THREAD_TIMER_OFF (adj->t_expire);
   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -1269,6 +1280,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
                            "no LAN Neighbours TLV found");
   }
 
+  if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+    lsp_regenerate_schedule(adj->circuit->area, level, 0);
+
 out:
   if (isis->debugs & DEBUG_ADJ_PACKETS)
     {