Browse Source

isisd: add Google's changes to IS-IS

Josh Bailey 7 years ago
parent
commit
3f045a0881

+ 10 - 19
isisd/dict.c

@@ -18,17 +18,11 @@
  * $Name$
  */
 
-#include <stdlib.h>
-#include <stddef.h>
 #include "zebra.h"
 #include "zassert.h"
-#define DICT_IMPLEMENTATION
+#include "memory.h"
 #include "dict.h"
 
-#ifdef KAZLIB_RCSID
-static const char rcsid[] = "Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz";
-#endif
-
 /*
  * These macros provide short convenient names for structure members,
  * which are embellished with dict_ prefixes so that they are
@@ -246,7 +240,7 @@ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
 
 dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
 {
-    dict_t *new = malloc(sizeof *new);
+    dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t));
 
     if (new) {
 	new->compare = comp;
@@ -287,7 +281,7 @@ void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
 void dict_destroy(dict_t *dict)
 {
     assert (dict_isempty(dict));
-    free(dict);
+    XFREE(MTYPE_ISIS_DICT, dict);
 }
 
 /*
@@ -310,9 +304,6 @@ void dict_free_nodes(dict_t *dict)
 
 void dict_free(dict_t *dict)
 {
-#ifdef KAZLIB_OBSOLESCENT_DEBUG
-    assert ("call to obsolescent function dict_free()" && 0);
-#endif
     dict_free_nodes(dict);
 }
 
@@ -813,7 +804,7 @@ dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
 
 int dict_alloc_insert(dict_t *dict, const void *key, void *data)
 {
-    dnode_t *node = dict->allocnode(dict->context);
+    dnode_t *node = dict->allocnode (dict->context);
 
     if (node) {
 	dnode_init(node, data);
@@ -949,17 +940,17 @@ int dict_contains(dict_t *dict, dnode_t *node)
 
 static dnode_t *dnode_alloc(void *context)
 {
-    return malloc(sizeof *dnode_alloc(NULL));
+    return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
 }
 
 static void dnode_free(dnode_t *node, void *context)
 {
-    free(node);
+    XFREE(MTYPE_ISIS_DICT_NODE, node);
 }
 
 dnode_t *dnode_create(void *data)
 {
-    dnode_t *new = malloc(sizeof *new);
+    dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
     if (new) {
 	new->data = data;
 	new->parent = NULL;
@@ -981,7 +972,7 @@ dnode_t *dnode_init(dnode_t *dnode, void *data)
 void dnode_destroy(dnode_t *dnode)
 {
     assert (!dnode_is_in_a_dict(dnode));
-    free(dnode);
+    XFREE(MTYPE_ISIS_DICT_NODE, dnode);
 }
 
 void *dnode_get(dnode_t *dnode)
@@ -1235,7 +1226,7 @@ static int comparef(const void *key1, const void *key2)
 static char *dupstring(char *str)
 {
     int sz = strlen(str) + 1;
-    char *new = malloc(sz);
+    char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
     if (new)
 	memcpy(new, str, sz);
     return new;
@@ -1350,7 +1341,7 @@ int main(void)
 	"s                      switch to non-functioning allocator\n"
 	"q                      quit";
 
-    for (i = 0; i < sizeof darray / sizeof *darray; i++)
+    for (i = 0; i < 10; i++)
 	dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
 
     for (;;) {

+ 0 - 21
isisd/dict.h

@@ -22,9 +22,6 @@
 #define DICT_H
 
 #include <limits.h>
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#include "sfx.h"
-#endif
 
 /*
  * Blurb for inclusion into C++ translation units
@@ -44,16 +41,12 @@ typedef unsigned long dictcount_t;
 typedef enum { dnode_red, dnode_black } dnode_color_t;
 
 typedef struct dnode_t {
-    #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
     struct dnode_t *dict_left;
     struct dnode_t *dict_right;
     struct dnode_t *dict_parent;
     dnode_color_t dict_color;
     const void *dict_key;
     void *dict_data;
-    #else
-    int dict_dummy;
-    #endif
 } dnode_t;
 
 typedef int (*dict_comp_t)(const void *, const void *);
@@ -61,7 +54,6 @@ typedef dnode_t *(*dnode_alloc_t)(void *);
 typedef void (*dnode_free_t)(dnode_t *, void *);
 
 typedef struct dict_t {
-    #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
     dnode_t dict_nilnode;
     dictcount_t dict_nodecount;
     dictcount_t dict_maxcount;
@@ -70,20 +62,13 @@ typedef struct dict_t {
     dnode_free_t dict_freenode;
     void *dict_context;
     int dict_dupes;
-    #else
-    int dict_dummmy;
-    #endif
 } dict_t;
 
 typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
 
 typedef struct dict_load_t {
-    #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
     dict_t *dict_dictptr;
     dnode_t dict_nilnode;
-    #else
-    int dict_dummmy;
-    #endif
 } dict_load_t;
 
 extern dict_t *dict_create(dictcount_t, dict_comp_t);
@@ -124,18 +109,12 @@ extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
 extern void dict_load_end(dict_load_t *);
 extern void dict_merge(dict_t *, dict_t *);
 
-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
-#else
 #define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount)
-#endif
 #define dict_count(D) ((D)->dict_nodecount)
 #define dict_isempty(D) ((D)->dict_nodecount == 0)
 #define dnode_get(N) ((N)->dict_data)
 #define dnode_getkey(N) ((N)->dict_key)
 #define dnode_put(N, X) ((N)->dict_data = (X))
-#endif
 
 #ifdef __cplusplus
 }

+ 174 - 139
isisd/isis_adjacency.c

@@ -36,6 +36,7 @@
 #include "isisd/include-netbsd/iso.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_adjacency.h"
@@ -43,6 +44,10 @@
 #include "isisd/isis_dr.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_pdu.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_events.h"
 
 extern struct isis *isis;
 
@@ -73,9 +78,9 @@ isis_new_adj (u_char * id, u_char * snpa, int level,
     }
 
   if (snpa) {
-  memcpy (adj->snpa, snpa, 6);
+    memcpy (adj->snpa, snpa, ETH_ALEN);
   } else {
-      memset (adj->snpa, ' ', 6);
+    memset (adj->snpa, ' ', ETH_ALEN);
   }
 
   adj->circuit = circuit;
@@ -125,37 +130,60 @@ isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
 }
 
 void
-isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
+isis_delete_adj (void *arg)
 {
+  struct isis_adjacency *adj = arg;
+
   if (!adj)
     return;
-  /* When we recieve a NULL list, we will know its p2p. */
-  if (adjdb)
-    listnode_delete (adjdb, adj);
 
-  THREAD_OFF (adj->t_expire);
+  THREAD_TIMER_OFF (adj->t_expire);
+
+  /* remove from SPF trees */
+  spftree_area_adj_del (adj->circuit->area, adj);
 
+  if (adj->area_addrs)
+    list_delete (adj->area_addrs);
   if (adj->ipv4_addrs)
     list_delete (adj->ipv4_addrs);
 #ifdef HAVE_IPV6
   if (adj->ipv6_addrs)
     list_delete (adj->ipv6_addrs);
 #endif
-  
+
   XFREE (MTYPE_ISIS_ADJACENCY, adj);
   return;
 }
 
+static const char *
+adj_state2string (int state)
+{
+
+  switch (state)
+    {
+    case ISIS_ADJ_INITIALIZING:
+      return "Initializing";
+    case ISIS_ADJ_UP:
+      return "Up";
+    case ISIS_ADJ_DOWN:
+      return "Down";
+    default:
+      return "Unknown";
+    }
+
+  return NULL;			/* not reached */
+}
+
 void
-isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
+isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
 		       const char *reason)
 {
   int old_state;
-  int level = adj->level;
+  int level;
   struct isis_circuit *circuit;
 
   old_state = adj->adj_state;
-  adj->adj_state = state;
+  adj->adj_state = new_state;
 
   circuit = adj->circuit;
 
@@ -163,42 +191,103 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
     {
       zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
 		 circuit->area->area_tag,
-		 old_state, state, reason ? reason : "unspecified");
+		 old_state, new_state, reason ? reason : "unspecified");
     }
 
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+  if (circuit->area->log_adj_changes)
     {
-      if (state == ISIS_ADJ_UP)
-	circuit->upadjcount[level - 1]++;
-      if (state == ISIS_ADJ_DOWN)
-	{
-	  isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
-	  circuit->upadjcount[level - 1]--;
-	}
+      const char *adj_name;
+      struct isis_dynhn *dyn;
 
-      list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
-      isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
-				 circuit->u.bc.lan_neighs[level - 1]);
+      dyn = dynhn_find_by_id (adj->sysid);
+      if (dyn)
+	adj_name = (const char *)dyn->name.name;
+      else
+	adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown";
+
+      zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
+		 adj_name,
+		 adj->circuit ? adj->circuit->interface->name : "no circuit",
+		 adj_state2string (old_state),
+		 adj_state2string (new_state),
+		 reason ? reason : "unspecified");
     }
-  else if (state == ISIS_ADJ_UP)
-    {				/* p2p interface */
-      if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
-	send_hello (circuit, 1);
-
-      /* update counter & timers for debugging purposes */
-      adj->last_flap = time (NULL);
-      adj->flaps++;
-
-      /* 7.3.17 - going up on P2P -> send CSNP */
-      /* FIXME: yup, I know its wrong... but i will do it! (for now) */
-      send_csnp (circuit, 1);
-      send_csnp (circuit, 2);
+
+  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+    {
+      for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
+      {
+        if ((adj->level & level) == 0)
+          continue;
+        if (new_state == ISIS_ADJ_UP)
+	  {
+	    circuit->upadjcount[level - 1]++;
+	    isis_event_adjacency_state_change (adj, new_state);
+	    /* update counter & timers for debugging purposes */
+	    adj->last_flap = time (NULL);
+	    adj->flaps++;
+	  }
+        else if (new_state == ISIS_ADJ_DOWN)
+	  {
+	    listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
+	    circuit->upadjcount[level - 1]--;
+	    if (circuit->upadjcount[level - 1] == 0)
+	      {
+		/* Clean lsp_queue when no adj is up. */
+		if (circuit->lsp_queue)
+		  list_delete_all_node (circuit->lsp_queue);
+	      }
+	    isis_event_adjacency_state_change (adj, new_state);
+	    isis_delete_adj (adj);
+	  }
+        list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
+        isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
+                                   circuit->u.bc.lan_neighs[level - 1]);
+
+        /* On adjacency state change send new pseudo LSP if we are the DR */
+        if (circuit->u.bc.is_dr[level - 1])
+          lsp_regenerate_schedule_pseudo (circuit, level);
+      }
     }
-  else if (state == ISIS_ADJ_DOWN)
-    {				/* p2p interface */
-      adj->circuit->u.p2p.neighbor = NULL;
-      isis_delete_adj (adj, NULL);
+  else if (circuit->circ_type == CIRCUIT_T_P2P)
+    {
+      for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
+      {
+        if ((adj->level & level) == 0)
+          continue;
+        if (new_state == ISIS_ADJ_UP)
+	  {
+	    circuit->upadjcount[level - 1]++;
+	    isis_event_adjacency_state_change (adj, new_state);
+
+	    if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
+	      send_hello (circuit, level);
+
+	    /* update counter & timers for debugging purposes */
+	    adj->last_flap = time (NULL);
+	    adj->flaps++;
+
+	    /* 7.3.17 - going up on P2P -> send CSNP */
+	    /* FIXME: yup, I know its wrong... but i will do it! (for now) */
+	    send_csnp (circuit, level);
+	  }
+        else if (new_state == ISIS_ADJ_DOWN)
+	  {
+	    if (adj->circuit->u.p2p.neighbor == adj)
+	      adj->circuit->u.p2p.neighbor = NULL;
+	    circuit->upadjcount[level - 1]--;
+	    if (circuit->upadjcount[level - 1] == 0)
+	      {
+		/* Clean lsp_queue when no adj is up. */
+		if (circuit->lsp_queue)
+		  list_delete_all_node (circuit->lsp_queue);
+	      }
+	    isis_event_adjacency_state_change (adj, new_state);
+	    isis_delete_adj (adj);
+	  }
+      }
     }
+
   return;
 }
 
@@ -225,7 +314,7 @@ isis_adj_print (struct isis_adjacency *adj)
 	      snpa_print (adj->snpa), adj->level, adj->hold_time);
   if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
     {
-      zlog_debug ("IPv4 Addresses:");
+      zlog_debug ("IPv4 Address(es):");
 
       for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
         zlog_debug ("%s", inet_ntoa (*ipv4_addr));
@@ -234,7 +323,7 @@ isis_adj_print (struct isis_adjacency *adj)
 #ifdef HAVE_IPV6
   if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
     {
-      zlog_debug ("IPv6 Addresses:");
+      zlog_debug ("IPv6 Address(es):");
       for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
 	{
 	  inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
@@ -251,14 +340,12 @@ int
 isis_adj_expire (struct thread *thread)
 {
   struct isis_adjacency *adj;
-  int level;
 
   /*
    * Get the adjacency
    */
   adj = THREAD_ARG (thread);
   assert (adj);
-  level = adj->level;
   adj->t_expire = NULL;
 
   /* trigger the adj expire event */
@@ -267,32 +354,12 @@ isis_adj_expire (struct thread *thread)
   return 0;
 }
 
-static const char *
-adj_state2string (int state)
-{
-
-  switch (state)
-    {
-    case ISIS_ADJ_INITIALIZING:
-      return "Initializing";
-    case ISIS_ADJ_UP:
-      return "Up";
-    case ISIS_ADJ_DOWN:
-      return "Down";
-    default:
-      return "Unknown";
-    }
-
-  return NULL;			/* not reached */
-}
-
 /*
- * show clns/isis neighbor (detail)
+ * show isis neighbor [detail]
  */
-static void
-isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
+void
+isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
 {
-
 #ifdef HAVE_IPV6
   struct in6_addr *ipv6_addr;
   u_char ip6[INET6_ADDRSTRLEN];
@@ -335,10 +402,11 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
   if (detail == ISIS_UI_LEVEL_DETAIL)
     {
       level = adj->level;
+      vty_out (vty, "%s", VTY_NEWLINE);
       if (adj->circuit)
-	vty_out (vty, "%s    Interface: %s", VTY_NEWLINE, adj->circuit->interface->name);	/* interface name */
+	vty_out (vty, "    Interface: %s", adj->circuit->interface->name);
       else
-	vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
+	vty_out (vty, "    Interface: NULL circuit");
       vty_out (vty, ", Level: %u", adj->level);	/* level */
       vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
       now = time (NULL);
@@ -347,40 +415,54 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
 		 time2string (adj->last_upd + adj->hold_time - now));
       else
 	vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
-      vty_out (vty, "%s    Adjacency flaps: %u", VTY_NEWLINE, adj->flaps);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "    Adjacency flaps: %u", adj->flaps);
       vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
-      vty_out (vty, "%s    Circuit type: %s",
-	       VTY_NEWLINE, circuit_t2string (adj->circuit_t));
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "    Circuit type: %s", circuit_t2string (adj->circuit_t));
       vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
-      vty_out (vty, "%s    SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa));
-      dyn = dynhn_find_by_id (adj->lanid);
-      if (dyn)
-	vty_out (vty, ", LAN id: %s.%02x",
-		 dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
-      else
-	vty_out (vty, ", LAN id: %s.%02x",
-		 sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
-
-      vty_out (vty, "%s    Priority: %u",
-	       VTY_NEWLINE, adj->prio[adj->level - 1]);
-
-      vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
-	       isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
-				    dis), adj->dischanges[level - 1],
-	       time2string (now -
-			    (adj->dis_record[ISIS_LEVELS + level - 1].
-			     last_dis_change)), VTY_NEWLINE);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "    SNPA: %s", snpa_print (adj->snpa));
+      if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)
+      {
+        dyn = dynhn_find_by_id (adj->lanid);
+        if (dyn)
+          vty_out (vty, ", LAN id: %s.%02x",
+              dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
+        else
+          vty_out (vty, ", LAN id: %s.%02x",
+              sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
+
+        vty_out (vty, "%s", VTY_NEWLINE);
+        vty_out (vty, "    LAN Priority: %u", adj->prio[adj->level - 1]);
+
+        vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
+            isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
+              dis), adj->dischanges[level - 1],
+            time2string (now -
+              (adj->dis_record[ISIS_LEVELS + level - 1].
+               last_dis_change)));
+      }
+      vty_out (vty, "%s", VTY_NEWLINE);
 
+      if (adj->area_addrs && listcount (adj->area_addrs) > 0)
+        {
+          struct area_addr *area_addr;
+          vty_out (vty, "    Area Address(es):%s", VTY_NEWLINE);
+          for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
+            vty_out (vty, "      %s%s", isonet_print (area_addr->area_addr,
+                     area_addr->addr_len), VTY_NEWLINE);
+        }
       if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
 	{
-	  vty_out (vty, "    IPv4 Addresses:%s", VTY_NEWLINE);
+	  vty_out (vty, "    IPv4 Address(es):%s", VTY_NEWLINE);
 	  for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
             vty_out (vty, "      %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
 	}
 #ifdef HAVE_IPV6
       if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
 	{
-	  vty_out (vty, "    IPv6 Addresses:%s", VTY_NEWLINE);
+	  vty_out (vty, "    IPv6 Address(es):%s", VTY_NEWLINE);
 	  for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
 	    {
 	      inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
@@ -394,53 +476,6 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
 }
 
 void
-isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
-{
-  isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
-}
-
-void
-isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
-{
-  isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
-}
-
-void
-isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
-{
-  isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
-}
-
-void
-isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
-{
-  isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
-}
-
-void
-isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
-{
-  isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
-}
-
-void
-isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
-{
-  isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
-}
-
-void
-isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
-						      void *), void *arg)
-{
-  struct listnode *node, *nnode;
-  struct isis_adjacency *adj;
-
-  for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
-    (*func) (adj, arg);
-}
-
-void
 isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
 {
   struct isis_adjacency *adj;

+ 2 - 14
isisd/isis_adjacency.h

@@ -103,25 +103,13 @@ struct isis_adjacency *isis_adj_lookup_snpa (u_char * ssnpa,
 					     struct list *adjdb);
 struct isis_adjacency *isis_new_adj (u_char * id, u_char * snpa, int level,
 				     struct isis_circuit *circuit);
-void isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb);
+void isis_delete_adj (void *adj);
 void isis_adj_state_change (struct isis_adjacency *adj,
 			    enum isis_adj_state state, const char *reason);
 void isis_adj_print (struct isis_adjacency *adj);
 int isis_adj_expire (struct thread *thread);
-void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty);
-void isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty);
-void isis_adj_print_vty_extensive (struct isis_adjacency *adj,
-				   struct vty *vty);
-void isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty);
-void isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj,
-				    struct vty *vty);
-void isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj,
-				       struct vty *vty);
-
+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);
-void isis_adjdb_iterate (struct list *adjdb,
-			 void (*func) (struct isis_adjacency *,
-				       void *), void *arg);
 
 #endif /* ISIS_ADJACENCY_H */

+ 11 - 4
isisd/isis_bpf.c

@@ -301,7 +301,16 @@ int
 isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
 {
   struct ether_header *eth;
-  int written;
+  int written, buflen;
+
+  buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
+  if (buflen > sizeof (sock_buff))
+    {
+      zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than "
+		 "output pdu size %d on circuit %s",
+		 sizeof (sock_buff), buflen, circuit->interface->name);
+      return ISIS_WARNING;
+    }
 
   stream_set_getp (circuit->snd_stream, 0);
 
@@ -328,9 +337,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
 	  stream_get_endp (circuit->snd_stream));
 
   /* now we can send this */
-  written = write (circuit->fd, sock_buff,
-		   stream_get_endp (circuit->snd_stream) 
-		    + LLC_LEN + ETHER_HDR_LEN);
+  written = write (circuit->fd, sock_buff, buflen);
 
   return ISIS_OK;
 }

File diff suppressed because it is too large
+ 1635 - 940
isisd/isis_circuit.c


+ 29 - 28
isisd/isis_circuit.h

@@ -52,8 +52,6 @@ struct isis_bcast_info
   u_char l1_desig_is[ISIS_SYS_ID_LEN + 1];	/* level-1 DR */
   u_char l2_desig_is[ISIS_SYS_ID_LEN + 1];	/* level-2 DR */
   struct thread *t_refresh_pseudo_lsp[2];	/* refresh pseudo-node LSPs */
-  int pad_hellos;		/* add padding to Hello PDUs ? */
-  u_char priority[2];		/* l1/2 IS Priority */
 };
 
 struct isis_p2p_info
@@ -78,31 +76,36 @@ struct isis_circuit
   struct thread *t_send_csnp[2];
   struct thread *t_send_psnp[2];
   struct list *lsp_queue;	/* LSPs to be txed (both levels) */
+  time_t lsp_queue_last_cleared;/* timestamp used to enforce transmit interval;
+                                 * for scalability, use one timestamp per 
+                                 * circuit, instead of one per lsp per circuit
+                                 */
   /* there is no real point in two streams, just for programming kicker */
   int (*rx) (struct isis_circuit * circuit, u_char * ssnpa);
   struct stream *rcv_stream;	/* Stream for receiving */
   int (*tx) (struct isis_circuit * circuit, int level);
   struct stream *snd_stream;	/* Stream for sending */
   int idx;			/* idx in S[RM|SN] flags */
-#define CIRCUIT_T_BROADCAST  0
-#define CIRCUIT_T_P2P        1
-#define CIRCUIT_T_STATIC_IN  2
-#define CIRCUIT_T_STATIC_OUT 3
-#define CIRCUIT_T_DA         4
+#define CIRCUIT_T_UNKNOWN    0
+#define CIRCUIT_T_BROADCAST  1
+#define CIRCUIT_T_P2P        2
+#define CIRCUIT_T_LOOPBACK   3
   int circ_type;		/* type of the physical interface */
+  int circ_type_config;		/* config type of the physical interface */
   union
   {
     struct isis_bcast_info bc;
     struct isis_p2p_info p2p;
   } u;
+  u_char priority[2];		/* l1/2 IS configured priority */
+  int pad_hellos;		/* add padding to Hello PDUs ? */
   char ext_domain;		/* externalDomain   (boolean) */
+  int lsp_regenerate_pending[ISIS_LEVELS];
   /* 
    * Configurables 
    */
   struct isis_passwd passwd;	/* Circuit rx/tx password */
-  long lsp_interval;
-  int manual_l2_only;		/* manualL2OnlyMode (boolean) */
-  int circuit_is_type;		/* circuit is type == level of circuit
+  int is_type;	                /* circuit is type == level of circuit
 				 * diffrenciated from circuit type (media) */
   u_int32_t hello_interval[2];	/* l1HelloInterval in msecs */
   u_int16_t hello_multiplier[2];	/* l1HelloMultiplier */
@@ -110,24 +113,17 @@ struct isis_circuit
   u_int16_t psnp_interval[2];	/* level-1 psnp-interval in seconds */
   struct metric metrics[2];	/* l1XxxMetric */
   u_int32_t te_metric[2];
-  struct password *c_rx_passwds;	/* circuitReceivePasswords */
-  struct password *c_tc_passwd;	/* circuitTransmitPassword */
   int ip_router;		/* Route IP ? */
+  int is_passive;		/* Is Passive ? */
   struct list *ip_addrs;	/* our IP addresses */
 #ifdef HAVE_IPV6
   int ipv6_router;		/* Route IPv6 ? */
   struct list *ipv6_link;	/* our link local IPv6 addresses */
   struct list *ipv6_non_link;	/* our non-link local IPv6 addresses */
 #endif				/* HAVE_IPV6 */
-  /* 
-   * RFC 2973 IS-IS Mesh Groups 
-   */
-#define MESH_INACTIVE 0
-#define MESH_BLOCKED  1
-#define MESH_SET      2
-  int mesh_enabled;		/* meshGroupEnabled */
-  u_int16_t mesh_group;		/* meshGroup */
   u_int16_t upadjcount[2];
+#define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01
+  u_char flags;
   /*
    * Counters as in 10589--11.2.5.9
    */
@@ -141,25 +137,30 @@ struct isis_circuit
 
 void isis_circuit_init (void);
 struct isis_circuit *isis_circuit_new (void);
+void isis_circuit_del (struct isis_circuit *circuit);
 struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp,
 					    struct list *list);
 struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp);
-void isis_circuit_del (struct isis_circuit *circuit);
 void isis_circuit_configure (struct isis_circuit *circuit,
 			     struct isis_area *area);
-void isis_circuit_up (struct isis_circuit *circuit);
 void isis_circuit_deconfigure (struct isis_circuit *circuit,
 			       struct isis_area *area);
-
-int isis_circuit_destroy (struct isis_circuit *circuit);
 void isis_circuit_if_add (struct isis_circuit *circuit,
 			  struct interface *ifp);
-void isis_circuit_if_del (struct isis_circuit *circuit);
-void circuit_update_nlpids (struct isis_circuit *circuit);
-void isis_circuit_update_params (struct isis_circuit *circuit,
-				 struct interface *ifp);
+void isis_circuit_if_del (struct isis_circuit *circuit,
+			  struct interface *ifp);
+void isis_circuit_if_bind (struct isis_circuit *circuit,
+                           struct interface *ifp);
+void isis_circuit_if_unbind (struct isis_circuit *circuit,
+                             struct interface *ifp);
 void isis_circuit_add_addr (struct isis_circuit *circuit,
 			    struct connected *conn);
 void isis_circuit_del_addr (struct isis_circuit *circuit,
 			    struct connected *conn);
+int isis_circuit_up (struct isis_circuit *circuit);
+void isis_circuit_down (struct isis_circuit *);
+void circuit_update_nlpids (struct isis_circuit *circuit);
+void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
+                             char detail);
+
 #endif /* _ZEBRA_ISIS_CIRCUIT_H */

+ 5 - 8
isisd/isis_common.h

@@ -21,6 +21,9 @@
  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+#ifndef ISIS_COMMON_H
+#define ISIS_COMMON_H
+
 /*
  * Area Address
  */
@@ -35,6 +38,7 @@ struct isis_passwd
   u_char len;
 #define ISIS_PASSWD_TYPE_UNUSED   0
 #define ISIS_PASSWD_TYPE_CLEARTXT 1
+#define ISIS_PASSWD_TYPE_HMAC_MD5 54
 #define ISIS_PASSWD_TYPE_PRIVATE  255
   u_char type;
   /* Authenticate SNPs? */
@@ -64,11 +68,4 @@ struct nlpids
   u_char nlpids[4];		/* FIXME: enough ? */
 };
 
-/*
- * Flags structure for SSN and SRM flags
- */
-struct flags
-{
-  int maxindex;
-  struct list *free_idcs;
-};
+#endif

+ 52 - 26
isisd/isis_constants.h

@@ -27,8 +27,10 @@
  * Architectural constant values from p. 35 of ISO/IEC 10589
  */
 
-#define MAX_LINK_METRIC               63
-#define MAX_PATH_METRIC               1023
+#define MAX_NARROW_LINK_METRIC        63
+#define MAX_NARROW_PATH_METRIC        1023
+#define MAX_WIDE_LINK_METRIC          0x00FFFFFF  /* RFC4444 */
+#define MAX_WIDE_PATH_METRIC          0xFE000000  /* RFC3787 */
 #define ISO_SAP                       0xFE
 #define INTRADOMAIN_ROUTEING_SELECTOR 0
 #define SEQUENCE_MODULUS              4294967296
@@ -38,7 +40,7 @@
  * implementation specific jitter values
  */
 
-#define IIH_JITTER                    25	/* % */
+#define IIH_JITTER                    10	/* % */
 #define MAX_AGE_JITTER                 5	/* % */
 #define MAX_LSP_GEN_JITTER             5	/* % */
 #define CSNP_JITTER                   10	/* % */
@@ -46,36 +48,59 @@
 
 #define RANDOM_SPREAD           100000.0
 
+#define ISIS_LEVELS                   2
+#define ISIS_LEVEL1                   1
+#define ISIS_LEVEL2                   2
+
 /*
  * Default values
- * ISO - 10589
- * Section 7.3.21 - Parameters
+ * ISO - 10589 Section 7.3.21 - Parameters
+ * RFC 4444
  */
 #define MAX_AGE                       1200
 #define ZERO_AGE_LIFETIME             60
-#define MAX_LSP_GEN_INTERVAL          900
-#define MIN_LSP_GEN_INTERVAL          30
+#define MIN_LSP_LIFETIME              350
+#define MAX_LSP_LIFETIME              65535
+#define DEFAULT_LSP_LIFETIME          1200
+
+#define MIN_MAX_LSP_GEN_INTERVAL      1
+#define MAX_MAX_LSP_GEN_INTERVAL      65235
+#define DEFAULT_MAX_LSP_GEN_INTERVAL  900
+
+#define MIN_MIN_LSP_GEN_INTERVAL      1
+#define MAX_MIN_LSP_GEN_INTERVAL      120  /* RFC 4444 says 65535 */
+#define DEFAULT_MIN_LSP_GEN_INTERVAL  30
+
 #define MIN_LSP_TRANS_INTERVAL        5
-#define ISIS_MIN_LSP_LIFETIME         380
-#define CSNP_INTERVAL                 10
-#define PSNP_INTERVAL                 2
-#define ISIS_MAX_PATH_SPLITS          3
 
-#define ISIS_LEVELS                   2
-#define ISIS_LEVEL1                   1
-#define ISIS_LEVEL2                   2
+#define MIN_CSNP_INTERVAL             1
+#define MAX_CSNP_INTERVAL             600
+#define DEFAULT_CSNP_INTERVAL         10
+
+#define MIN_PSNP_INTERVAL             1
+#define MAX_PSNP_INTERVAL             120
+#define DEFAULT_PSNP_INTERVAL         2
+
+#define MIN_HELLO_INTERVAL            1
+#define MAX_HELLO_INTERVAL            600
+#define DEFAULT_HELLO_INTERVAL        3
+
+#define MIN_HELLO_MULTIPLIER          2
+#define MAX_HELLO_MULTIPLIER          100
+#define DEFAULT_HELLO_MULTIPLIER      10
 
-#define HELLO_INTERVAL                10
-#define HELLO_MINIMAL HELLO_INTERVAL
-#define HELLO_MULTIPLIER              3
+#define MIN_PRIORITY                  0
+#define MAX_PRIORITY                  127
 #define DEFAULT_PRIORITY              64
-/* different vendors implement different values 5-10 on average */
-#define LSP_GEN_INTERVAL_DEFAULT      10
-#define LSP_INTERVAL                  33	/* msecs */
-#define DEFAULT_CIRCUIT_METRICS 10
-#define METRICS_UNSUPPORTED 0x80
-#define PERIODIC_SPF_INTERVAL         60	/* at the top of my head */
-#define MINIMUM_SPF_INTERVAL           5	/* .. same here          */
+
+/* min and max metric varies by new vs old metric types */
+#define DEFAULT_CIRCUIT_METRIC        10
+
+#define METRICS_UNSUPPORTED           0x80
+
+#define MINIMUM_SPF_INTERVAL          1
+
+#define ISIS_MAX_PATH_SPLITS          64
 
 /*
  * NLPID values
@@ -104,6 +129,7 @@
 
 #define SNPA_ADDRSTRLEN 18
 #define ISIS_SYS_ID_LEN  6
+#define ISIS_NSEL_LEN    1
 #define SYSID_STRLEN    24
 
 /*
@@ -136,8 +162,8 @@
  * packets, using isomtu = mtu - LLC_LEN
  */
 #define ISO_MTU(C) \
-          (C->circ_type==CIRCUIT_T_BROADCAST) ? \
-          (C->interface->mtu - LLC_LEN) : (C->interface->mtu)
+          ((if_is_broadcast ((C)->interface)) ? \
+           (C->interface->mtu - LLC_LEN) : (C->interface->mtu))
 
 #ifndef ETH_ALEN
 #define ETH_ALEN 6

+ 26 - 10
isisd/isis_csm.c

@@ -36,6 +36,7 @@
 #include "isisd/include-netbsd/iso.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
@@ -45,7 +46,6 @@
 #include "isisd/isis_constants.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
@@ -85,6 +85,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
     case C_STATE_NA:
       if (circuit)
 	zlog_warn ("Non-null circuit while state C_STATE_NA");
+      assert (circuit == NULL);
       switch (event)
 	{
 	case ISIS_ENABLE:
@@ -106,23 +107,29 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
 	}
       break;
     case C_STATE_INIT:
+      assert (circuit);
       switch (event)
 	{
 	case ISIS_ENABLE:
 	  isis_circuit_configure (circuit, (struct isis_area *) arg);
-	  isis_circuit_up (circuit);
+	  if (isis_circuit_up (circuit) != ISIS_OK)
+	    {
+	      isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
+	      break;
+	    }
 	  circuit->state = C_STATE_UP;
-	  isis_event_circuit_state_change (circuit, 1);
+	  isis_event_circuit_state_change (circuit, circuit->area, 1);
 	  listnode_delete (isis->init_circ_list, circuit);
 	  break;
 	case IF_UP_FROM_Z:
+          assert (circuit);
 	  zlog_warn ("circuit already connected");
 	  break;
 	case ISIS_DISABLE:
 	  zlog_warn ("circuit already disabled");
 	  break;
 	case IF_DOWN_FROM_Z:
-	  isis_circuit_if_del (circuit);
+	  isis_circuit_if_del (circuit, (struct interface *) arg);
 	  listnode_delete (isis->init_circ_list, circuit);
 	  isis_circuit_del (circuit);
 	  circuit = NULL;
@@ -130,6 +137,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
 	}
       break;
     case C_STATE_CONF:
+      assert (circuit);
       switch (event)
 	{
 	case ISIS_ENABLE:
@@ -137,9 +145,13 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
 	  break;
 	case IF_UP_FROM_Z:
 	  isis_circuit_if_add (circuit, (struct interface *) arg);
-	  isis_circuit_up (circuit);
+	  if (isis_circuit_up (circuit) != ISIS_OK)
+            {
+              isis_circuit_if_del (circuit, (struct interface *) arg);
+	      break;
+            }
 	  circuit->state = C_STATE_UP;
-	  isis_event_circuit_state_change (circuit, 1);
+	  isis_event_circuit_state_change (circuit, circuit->area, 1);
 	  break;
 	case ISIS_DISABLE:
 	  isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
@@ -152,6 +164,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
 	}
       break;
     case C_STATE_UP:
+      assert (circuit);
       switch (event)
 	{
 	case ISIS_ENABLE:
@@ -161,15 +174,18 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
 	  zlog_warn ("circuit already connected");
 	  break;
 	case ISIS_DISABLE:
+	  isis_circuit_down (circuit);
 	  isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
-	  listnode_add (isis->init_circ_list, circuit);
 	  circuit->state = C_STATE_INIT;
-	  isis_event_circuit_state_change (circuit, 0);
+	  isis_event_circuit_state_change (circuit,
+                                           (struct isis_area *)arg, 0);
+	  listnode_add (isis->init_circ_list, circuit);
 	  break;
 	case IF_DOWN_FROM_Z:
-	  isis_circuit_if_del (circuit);
+	  isis_circuit_down (circuit);
+          isis_circuit_if_del (circuit, (struct interface *) arg);
 	  circuit->state = C_STATE_CONF;
-	  isis_event_circuit_state_change (circuit, 0);
+	  isis_event_circuit_state_change (circuit, circuit->area, 0);
 	  break;
 	}
       break;

+ 14 - 4
isisd/isis_dlpi.c

@@ -442,12 +442,12 @@ open_dlpi_dev (struct isis_circuit *circuit)
    * 8.4.2 - Broadcast subnetwork IIH PDUs
    */
   retval = 0;
-  if (circuit->circuit_is_type & IS_LEVEL_1)
+  if (circuit->is_type & IS_LEVEL_1)
     {
       retval |= dlpimcast (fd, ALL_L1_ISS);
       retval |= dlpimcast (fd, ALL_ISS);
     }
-  if (circuit->circuit_is_type & IS_LEVEL_2)
+  if (circuit->is_type & IS_LEVEL_2)
     retval |= dlpimcast (fd, ALL_L2_ISS);
 
   if (retval != 0)
@@ -589,6 +589,16 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl;
   char *dstaddr;
   u_short *dstsap;
+  int buflen;
+
+  buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN;
+  if (buflen > sizeof (sock_buff))
+    {
+      zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than "
+		 "output pdu size %d on circuit %s",
+		 sizeof (sock_buff), buflen, circuit->interface->name);
+      return ISIS_WARNING;
+    }
 
   stream_set_getp (circuit->snd_stream, 0);
 
@@ -612,7 +622,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   else
     memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL);
   /* Note: DLPI SAP values are in host byte order */
-  *dstsap = stream_get_endp (circuit->snd_stream) + LLC_LEN;
+  *dstsap = buflen;
 
   sock_buff[0] = ISO_SAP;
   sock_buff[1] = ISO_SAP;
@@ -620,7 +630,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
 	  stream_get_endp (circuit->snd_stream));
   dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length,
-    sock_buff, stream_get_endp (circuit->snd_stream) + LLC_LEN, 0);
+	    sock_buff, buflen, 0);
   return ISIS_OK;
 }
 

+ 26 - 43
isisd/isis_dr.c

@@ -47,9 +47,6 @@
 #include "isisd/isis_dr.h"
 #include "isisd/isis_events.h"
 
-extern struct isis *isis;
-extern struct thread_master *master;
-
 const char *
 isis_disflag2string (int disflag)
 {
@@ -137,15 +134,14 @@ isis_dr_elect (struct isis_circuit *circuit, int level)
   int biggest_prio = -1;
   int cmp_res, retval = ISIS_OK;
 
-  own_prio = circuit->u.bc.priority[level - 1];
+  own_prio = circuit->priority[level - 1];
   adjdb = circuit->u.bc.adjdb[level - 1];
 
   if (!adjdb)
     {
       zlog_warn ("isis_dr_elect() adjdb == NULL");
-      retval = ISIS_WARNING;
       list_delete (list);
-      goto out;
+      return ISIS_WARNING;
     }
   isis_adj_build_up_list (adjdb, list);
 
@@ -189,42 +185,34 @@ isis_dr_elect (struct isis_circuit *circuit, int level)
   if (!adj_dr)
     {
       /*
-       * Could not find the DR - means we are alone and thus the DR
+       * Could not find the DR - means we are alone. Resign if we were DR.
        */
-      if (!circuit->u.bc.is_dr[level - 1])
-	{
-	  list_delete (list);
-	  list = NULL;
-	  return isis_dr_commence (circuit, level);
-	}
-      goto out;
+      if (circuit->u.bc.is_dr[level - 1])
+        retval = isis_dr_resign (circuit, level);
+      list_delete (list);
+      return retval;
     }
 
   /*
    * Now we have the DR adjacency, compare it to self
    */
-  if (adj_dr->prio[level - 1] < own_prio
-      || (adj_dr->prio[level - 1] == own_prio
-	  && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
+  if (adj_dr->prio[level - 1] < own_prio ||
+      (adj_dr->prio[level - 1] == own_prio &&
+       memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
     {
-      if (!circuit->u.bc.is_dr[level - 1])
-	{
-	  /*
-	   * We are the DR
-	   */
+      adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
+      adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
 
-	  /* rotate the history log */
-	  for (ALL_LIST_ELEMENTS_RO (list, node, adj))
-            isis_check_dr_change (adj, level);
+      /* rotate the history log */
+      for (ALL_LIST_ELEMENTS_RO (list, node, adj))
+        isis_check_dr_change (adj, level);
 
-	  /* commence */
-	  list_delete (list);
-	  return isis_dr_commence (circuit, level);
-	}
+      /* We are the DR, commence DR */
+      if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0)
+        retval = isis_dr_commence (circuit, level);
     }
   else
     {
-
       /* ok we have found the DIS - lets mark the adjacency */
       /* set flag for show output */
       adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
@@ -240,16 +228,10 @@ isis_dr_elect (struct isis_circuit *circuit, int level)
       /*
        * We are not DR - if we were -> resign
        */
-
       if (circuit->u.bc.is_dr[level - 1])
-	{
-	  list_delete (list);
-	  return isis_dr_resign (circuit, level);
-	}
+        retval = isis_dr_resign (circuit, level);
     }
-out:
-  if (list)
-    list_delete (list);
+  list_delete (list);
   return retval;
 }
 
@@ -264,11 +246,12 @@ isis_dr_resign (struct isis_circuit *circuit, int level)
   circuit->u.bc.run_dr_elect[level - 1] = 0;
   THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]);
   THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+  circuit->lsp_regenerate_pending[level - 1] = 0;
 
   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
   LSP_PSEUDO_ID (id) = circuit->circuit_id;
   LSP_FRAGMENT (id) = 0;
-  lsp_purge_dr (id, circuit, level);
+  lsp_purge_pseudo (id, circuit, level);
 
   if (level == 1)
     {
@@ -327,7 +310,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level)
       if (LSP_PSEUDO_ID (old_dr))
 	{
 	  /* there was a dr elected, purge its LSPs from the db */
-	  lsp_purge_dr (old_dr, circuit, level);
+	  lsp_purge_pseudo (old_dr, circuit, level);
 	}
       memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
       *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
@@ -335,7 +318,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level)
       assert (circuit->circuit_id);	/* must be non-zero */
       /*    if (circuit->t_send_l1_psnp)
          thread_cancel (circuit->t_send_l1_psnp); */
-      lsp_l1_pseudo_generate (circuit);
+      lsp_generate_pseudo (circuit, 1);
 
       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
@@ -353,7 +336,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level)
       if (LSP_PSEUDO_ID (old_dr))
 	{
 	  /* there was a dr elected, purge its LSPs from the db */
-	  lsp_purge_dr (old_dr, circuit, level);
+	  lsp_purge_pseudo (old_dr, circuit, level);
 	}
       memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
       *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
@@ -361,7 +344,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level)
       assert (circuit->circuit_id);	/* must be non-zero */
       /*    if (circuit->t_send_l1_psnp)
          thread_cancel (circuit->t_send_l1_psnp); */
-      lsp_l2_pseudo_generate (circuit);
+      lsp_generate_pseudo (circuit, 2);
 
       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,

+ 30 - 5
isisd/isis_dynhn.c

@@ -41,8 +41,6 @@
 #include "isisd/isis_misc.h"
 #include "isisd/isis_constants.h"
 
-extern struct isis *isis;
-extern struct thread_master *master;
 extern struct host host;
 
 struct list *dyn_cache = NULL;
@@ -51,7 +49,8 @@ static int dyn_cache_cleanup (struct thread *);
 void
 dyn_cache_init (void)
 {
-  dyn_cache = list_new ();
+  if (dyn_cache == NULL)
+    dyn_cache = list_new ();
   THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120);
   return;
 }
@@ -67,8 +66,8 @@ dyn_cache_cleanup (struct thread *thread)
 
   for (ALL_LIST_ELEMENTS (dyn_cache, node, nnode, dyn))
     {
-      if ((now - dyn->refresh) < (MAX_AGE + 120))
-	continue;
+      if ((now - dyn->refresh) < MAX_LSP_LIFETIME)
+        continue;
 
       list_delete_node (dyn_cache, node);
       XFREE (MTYPE_ISIS_DYNHN, dyn);
@@ -91,6 +90,19 @@ dynhn_find_by_id (u_char * id)
   return NULL;
 }
 
+struct isis_dynhn *
+dynhn_find_by_name (const char *hostname)
+{
+  struct listnode *node = NULL;
+  struct isis_dynhn *dyn = NULL;
+
+  for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn))
+    if (strncmp ((char *)dyn->name.name, hostname, 255) == 0)
+      return dyn;
+
+  return NULL;
+}
+
 void
 isis_dynhn_insert (u_char * id, struct hostname *hostname, int level)
 {
@@ -122,6 +134,19 @@ isis_dynhn_insert (u_char * id, struct hostname *hostname, int level)
   return;
 }
 
+void
+isis_dynhn_remove (u_char * id)
+{
+  struct isis_dynhn *dyn;
+
+  dyn = dynhn_find_by_id (id);
+  if (!dyn)
+    return;
+  listnode_delete (dyn_cache, dyn);
+  XFREE (MTYPE_ISIS_DYNHN, dyn);
+  return;
+}
+
 /*
  * Level  System ID      Dynamic Hostname  (notag)
  *  2     0000.0000.0001 foo-gw

+ 2 - 0
isisd/isis_dynhn.h

@@ -33,7 +33,9 @@ struct isis_dynhn
 
 void dyn_cache_init (void);
 void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level);
+void isis_dynhn_remove (u_char * id);
 struct isis_dynhn *dynhn_find_by_id (u_char * id);
+struct isis_dynhn *dynhn_find_by_name (const char *hostname);
 void dynhn_print_all (struct vty *vty);
 
 #endif /* _ZEBRA_ISIS_DYNHN_H */

+ 107 - 43
isisd/isis_events.c

@@ -30,11 +30,13 @@
 #include "hash.h"
 #include "prefix.h"
 #include "stream.h"
+#include "table.h"
 
 #include "isisd/dict.h"
 #include "isisd/include-netbsd/iso.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
@@ -44,15 +46,11 @@
 #include "isisd/isis_constants.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
 #include "isisd/isis_spf.h"
 
-extern struct thread_master *master;
-extern struct isis *isis;
-
 /* debug isis-spf spf-events 
  4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4
  4w4d: ISIS-Spf (tlt): L2, 0000.0000.0042.01-00 TLV contents changed, code 0x2
@@ -62,26 +60,59 @@ extern struct isis *isis;
 */
 
 void
-isis_event_circuit_state_change (struct isis_circuit *circuit, int up)
+isis_event_circuit_state_change (struct isis_circuit *circuit,
+                                 struct isis_area *area, int up)
 {
-  struct isis_area *area;
-
-  area = circuit->area;
-  assert (area);
   area->circuit_state_changes++;
 
   if (isis->debugs & DEBUG_EVENTS)
-    zlog_debug ("ISIS-Evt (%s) circuit %s", circuit->area->area_tag,
-	       up ? "up" : "down");
+    zlog_debug ("ISIS-Evt (%s) circuit %s", area->area_tag,
+                up ? "up" : "down");
 
   /*
    * Regenerate LSPs this affects
    */
-  lsp_regenerate_schedule (area);
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
 
   return;
 }
 
+static void
+area_resign_level (struct isis_area *area, int level)
+{
+  if (area->lspdb[level - 1])
+    {
+      lsp_db_destroy (area->lspdb[level - 1]);
+      area->lspdb[level - 1] = NULL;
+    }
+  if (area->spftree[level - 1])
+    {
+      isis_spftree_del (area->spftree[level - 1]);
+      area->spftree[level - 1] = NULL;
+    }
+#ifdef HAVE_IPV6
+  if (area->spftree6[level - 1])
+    {
+      isis_spftree_del (area->spftree6[level - 1]);
+      area->spftree6[level - 1] = NULL;
+    }
+#endif
+  if (area->route_table[level - 1])
+    {
+      route_table_finish (area->route_table[level - 1]);
+      area->route_table[level - 1] = NULL;
+    }
+#ifdef HAVE_IPV6
+  if (area->route_table6[level - 1])
+    {
+      route_table_finish (area->route_table6[level - 1]);
+      area->route_table6[level - 1] = NULL;
+    }
+#endif /* HAVE_IPV6 */
+
+  THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
+}
+
 void
 isis_event_system_type_change (struct isis_area *area, int newtype)
 {
@@ -96,45 +127,71 @@ isis_event_system_type_change (struct isis_area *area, int newtype)
     return;			/* No change */
 
   switch (area->is_type)
-    {
+  {
     case IS_LEVEL_1:
-      if (area->lspdb[1] == NULL)
-	area->lspdb[1] = lsp_db_init ();
-      lsp_l2_generate (area);
+      if (newtype == IS_LEVEL_2)
+      {
+        area_resign_level (area, IS_LEVEL_1);
+      }
+      else
+      {
+        if (area->lspdb[1] == NULL)
+          area->lspdb[1] = lsp_db_init ();
+        if (area->route_table[1] == NULL)
+          area->route_table[1] = route_table_init ();
+#ifdef HAVE_IPV6
+        if (area->route_table6[1] == NULL)
+          area->route_table6[1] = route_table_init ();
+#endif /* HAVE_IPV6 */
+      }
       break;
+
     case IS_LEVEL_1_AND_2:
       if (newtype == IS_LEVEL_1)
-	{
-	  lsp_db_destroy (area->lspdb[1]);
-	}
+        area_resign_level (area, IS_LEVEL_2);
       else
-	{
-	  lsp_db_destroy (area->lspdb[0]);
-	}
+        area_resign_level (area, IS_LEVEL_1);
       break;
+
     case IS_LEVEL_2:
-      if (area->lspdb[0] == NULL)
-	area->lspdb[0] = lsp_db_init ();
-      lsp_l1_generate (area);
+      if (newtype == IS_LEVEL_1)
+      {
+        area_resign_level (area, IS_LEVEL_2);
+      }
+      else
+      {
+        if (area->lspdb[0] == NULL)
+          area->lspdb[0] = lsp_db_init ();
+        if (area->route_table[0] == NULL)
+          area->route_table[0] = route_table_init ();
+#ifdef HAVE_IPV6
+        if (area->route_table6[0] == NULL)
+          area->route_table6[0] = route_table_init ();
+#endif /* HAVE_IPV6 */
+      }
       break;
     default:
       break;
-    }
+  }
 
   area->is_type = newtype;
-  for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
-    isis_event_circuit_type_change (circuit, newtype);
 
-  spftree_area_init (area);
-  lsp_regenerate_schedule (area);
+  /* override circuit's is_type */
+  if (area->is_type != IS_LEVEL_1_AND_2)
+  {
+    for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
+      isis_event_circuit_type_change (circuit, newtype);
+  }
 
-  return;
-}
+  spftree_area_init (area);
 
-void
-isis_event_area_addr_change (struct isis_area *area)
-{
+  if (newtype & IS_LEVEL_1)
+    lsp_generate (area, IS_LEVEL_1);
+  if (newtype & IS_LEVEL_2)
+    lsp_generate (area, IS_LEVEL_2);
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
 
+  return;
 }
 
 static void
@@ -148,7 +205,7 @@ circuit_commence_level (struct isis_circuit *circuit, int level)
       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 	{
 	  THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
-			   circuit, 2 * circuit->hello_interval[1]);
+			   circuit, 2 * circuit->hello_interval[0]);
 
 	  THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
 			   send_lan_l1_hello, circuit,
@@ -194,6 +251,8 @@ circuit_resign_level (struct isis_circuit *circuit, int level)
       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]);
       THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]);
       circuit->u.bc.run_dr_elect[idx] = 0;
+      list_delete (circuit->u.bc.lan_neighs[idx]);
+      circuit->u.bc.lan_neighs[idx] = NULL;
     }
 
   return;
@@ -202,14 +261,19 @@ circuit_resign_level (struct isis_circuit *circuit, int level)
 void
 isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)
 {
+  if (circuit->state != C_STATE_UP)
+  {
+    circuit->is_type = newtype;
+    return;
+  }
 
   if (isis->debugs & DEBUG_EVENTS)
     zlog_debug ("ISIS-Evt (%s) circuit type change %s -> %s",
 	       circuit->area->area_tag,
-	       circuit_t2string (circuit->circuit_is_type),
+	       circuit_t2string (circuit->is_type),
 	       circuit_t2string (newtype));
 
-  if (circuit->circuit_is_type == newtype)
+  if (circuit->is_type == newtype)
     return;			/* No change */
 
   if (!(newtype & circuit->area->is_type))
@@ -221,7 +285,7 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)
       return;
     }
 
-  switch (circuit->circuit_is_type)
+  switch (circuit->is_type)
     {
     case IS_LEVEL_1:
       if (newtype == IS_LEVEL_2)
@@ -243,8 +307,8 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)
       break;
     }
 
-  circuit->circuit_is_type = newtype;
-  lsp_regenerate_schedule (circuit->area);
+  circuit->is_type = newtype;
+  lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
 
   return;
 }
@@ -286,7 +350,7 @@ isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate)
 		adj->circuit->area->area_tag);
 
   /* LSP generation again */
-  lsp_regenerate_schedule (adj->circuit->area);
+  lsp_regenerate_schedule (adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
 
   return;
 }
@@ -307,7 +371,7 @@ isis_event_dis_status_change (struct thread *thread)
     zlog_debug ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag);
 
   /* LSP generation again */
-  lsp_regenerate_schedule (circuit->area);
+  lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
 
   return 0;
 }

+ 1 - 2
isisd/isis_events.h

@@ -26,13 +26,12 @@
  * Events related to area
  */
 void isis_event_system_type_change (struct isis_area *area, int newtype);
-void isis_event_area_addr_change (struct isis_area *area);
 
 /*
  * Events related to circuit
  */
 void isis_event_circuit_state_change (struct isis_circuit *circuit,
-				      int state);
+				      struct isis_area *area, int state);
 void isis_event_circuit_type_change (struct isis_circuit *circuit,
 				     int newtype);
 /*

+ 4 - 4
isisd/isis_flags.c

@@ -36,11 +36,11 @@ flags_initialize (struct flags *flags)
   flags->free_idcs = NULL;
 }
 
-int
+long int
 flags_get_index (struct flags *flags)
 {
   struct listnode *node;
-  int index;
+  long int index;
 
   if (flags->free_idcs == NULL || flags->free_idcs->count == 0)
     {
@@ -49,7 +49,7 @@ flags_get_index (struct flags *flags)
   else
     {
       node = listhead (flags->free_idcs);
-      index = (int) listgetdata (node);
+      index = (long int) listgetdata (node);
       listnode_delete (flags->free_idcs, (void *) index);
       index--;
     }
@@ -58,7 +58,7 @@ flags_get_index (struct flags *flags)
 }
 
 void
-flags_free_index (struct flags *flags, int index)
+flags_free_index (struct flags *flags, long int index)
 {
   if (index + 1 == flags->maxindex)
     {

+ 25 - 10
isisd/isis_flags.h

@@ -26,28 +26,43 @@
 
 /* The grand plan is to support 1024 circuits so we have 32*32 bit flags
  * the support will be achived using the newest drafts */
-#define ISIS_MAX_CIRCUITS 32 /* = 1024 */	/*FIXME:defined in lsp.h as well */
+#define ISIS_MAX_CIRCUITS 32 /* = 1024 */
 
-void flags_initialize (struct flags *flags);
-struct flags *new_flags (int size);
-int flags_get_index (struct flags *flags);
-void flags_free_index (struct flags *flags, int index);
+/*
+ * Flags structure for SSN and SRM flags
+ */
+struct flags
+{
+  int maxindex;
+  struct list *free_idcs;
+};
 
+void flags_initialize (struct flags *flags);
+long int flags_get_index (struct flags *flags);
+void flags_free_index (struct flags *flags, long int index);
 int flags_any_set (u_int32_t * flags);
 
 #define ISIS_SET_FLAG(F,C) \
-        F[C->idx>>5] |= (1<<(C->idx & 0x1F));
+        { \
+          F[C->idx>>5] |= (1<<(C->idx & 0x1F)); \
+        }
 
 #define ISIS_CLEAR_FLAG(F,C) \
-        F[C->idx>>5] &= ~(1<<(C->idx & 0x1F));
+        { \
+          F[C->idx>>5] &= ~(1<<(C->idx & 0x1F)); \
+        }
 
-#define ISIS_CHECK_FLAG(F, C)  F[(C)->idx>>5] & (1<<(C->idx & 0x1F))
+#define ISIS_CHECK_FLAG(F, C)  (F[(C)->idx>>5] & (1<<(C->idx & 0x1F)))
 
 /* sets all u_32int_t flags to 1 */
 #define ISIS_FLAGS_SET_ALL(FLAGS) \
-        memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4);
+        { \
+          memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4); \
+        }
 
 #define ISIS_FLAGS_CLEAR_ALL(FLAGS) \
-        memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4);
+        { \
+          memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4); \
+        }
 
 #endif /* _ZEBRA_ISIS_FLAGS_H */

File diff suppressed because it is too large
+ 883 - 634
isisd/isis_lsp.c


+ 19 - 27
isisd/isis_lsp.h

@@ -24,10 +24,6 @@
 #ifndef _ZEBRA_ISIS_LSP_H
 #define _ZEBRA_ISIS_LSP_H
 
-/* The grand plan is to support 1024 circuits so we have 32*32 bit flags
- * the support will be achived using the newest drafts */
-#define ISIS_MAX_CIRCUITS 32 /* = 1024 - FIXME:defined in flags.h as well */
-
 /* Structure for isis_lsp, this structure will only support the fixed
  * System ID (Currently 6) (atleast for now). In order to support more
  * We will have to split the header into two parts, and for readability
@@ -42,15 +38,13 @@ struct isis_lsp
     struct list *frags;
     struct isis_lsp *zero_lsp;
   } lspu;
+  u_int32_t auth_tlv_offset;    /* authentication TLV position in the pdu */
   u_int32_t SRMflags[ISIS_MAX_CIRCUITS];
   u_int32_t SSNflags[ISIS_MAX_CIRCUITS];
-  u_int32_t rexmit_queue[ISIS_MAX_CIRCUITS];
   int level;			/* L1 or L2? */
-  int purged;			/* have purged this one */
   int scheduled;		/* scheduled for sending */
   time_t installed;
   time_t last_generated;
-  time_t last_sent;
   int own_lsp;
 #ifdef TOPOLOGY_GENERATE
   int from_topology;
@@ -58,8 +52,6 @@ struct isis_lsp
 #endif
   /* used for 60 second counting when rem_lifetime is zero */
   int age_out;
-  struct isis_adjacency *adj;
-  /* FIXME: For now only topology LSP's use this. Is it helpful for others? */
   struct isis_area *area;
   struct tlvs tlv_data;		/* Simplifies TLV access */
 };
@@ -68,37 +60,32 @@ dict_t *lsp_db_init (void);
 void lsp_db_destroy (dict_t * lspdb);
 int lsp_tick (struct thread *thread);
 
-int lsp_l1_generate (struct isis_area *area);
-int lsp_l2_generate (struct isis_area *area);
-int lsp_refresh_l1 (struct thread *thread);
-int lsp_refresh_l2 (struct thread *thread);
-int lsp_regenerate_schedule (struct isis_area *area);
+int lsp_generate (struct isis_area *area, int level);
+int lsp_regenerate_schedule (struct isis_area *area, int level,
+                             int all_pseudo);
+int lsp_generate_pseudo (struct isis_circuit *circuit, int level);
+int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level);
 
-int lsp_l1_pseudo_generate (struct isis_circuit *circuit);
-int lsp_l2_pseudo_generate (struct isis_circuit *circuit);
-int lsp_l1_refresh_pseudo (struct thread *thread);
-int lsp_l2_refresh_pseudo (struct thread *thread);
-int isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
-			     int pdulen, struct isis_passwd *passwd);
 struct isis_lsp *lsp_new (u_char * lsp_id, u_int16_t rem_lifetime,
 			  u_int32_t seq_num, u_int8_t lsp_bits,
 			  u_int16_t checksum, int level);
 struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream,
 					  u_int16_t pdu_len,
 					  struct isis_lsp *lsp0,
-					  struct isis_area *area);
+					  struct isis_area *area,
+                                          int level);
 void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb);
 struct isis_lsp *lsp_search (u_char * id, dict_t * lspdb);
 
-void lsp_build_list (u_char * start_id, u_char * stop_id,
+void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
 		     struct list *list, dict_t * lspdb);
 void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
 				struct list *list, dict_t * lspdb);
-void lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
-			 dict_t * lspdb);
+void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
+                         struct list *list, dict_t * lspdb);
 
 void lsp_search_and_destroy (u_char * id, dict_t * lspdb);
-void lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level);
+void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level);
 void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
 			  struct isis_area *area);
 
@@ -115,13 +102,18 @@ void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
 int lsp_id_cmp (u_char * id1, u_char * id2);
 int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
 		 u_int16_t checksum, u_int16_t rem_lifetime);
-void lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
-		 struct stream *stream, struct isis_area *area, int level);
+void lsp_update (struct isis_lsp *lsp, struct stream *stream,
+                 struct isis_area *area, int level);
 void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num);
+void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost);
+void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
 int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
 		   char dynhost);
 const char *lsp_bits2string (u_char *);
 
+/* sets SRMflags for all active circuits of an lsp */
+void lsp_set_all_srmflags (struct isis_lsp *lsp);
+
 #ifdef TOPOLOGY_GENERATE
 void generate_topology_lsps (struct isis_area *area);
 void remove_topology_lsps (struct isis_area *area);

+ 19 - 10
isisd/isis_main.c

@@ -43,6 +43,9 @@
 #include "isisd/isis_circuit.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_route.h"
+#include "isisd/isis_zebra.h"
 
 /* Default configuration file name */
 #define ISISD_DEFAULT_CONFIG "isisd.conf"
@@ -66,7 +69,7 @@ struct zebra_privs_t isisd_privs = {
   .vty_group = VTY_GROUP,
 #endif
   .caps_p = _caps_p,
-  .cap_num_p = 2,
+  .cap_num_p = sizeof (_caps_p) / sizeof (*_caps_p),
   .cap_num_i = 0
 };
 
@@ -151,7 +154,10 @@ reload ()
   zlog_debug ("Reload");
   /* FIXME: Clean up func call here */
   vty_reset ();
+  (void) isisd_privs.change (ZPRIVS_RAISE);
   execve (_progpath, _argv, _envp);
+  zlog_err ("Reload failed: cannot exec %s: %s", _progpath,
+      safe_strerror (errno));
 }
 
 static void
@@ -319,28 +325,31 @@ main (int argc, char **argv, char **envp)
   memory_init ();
   access_list_init();
   isis_init ();
-  dyn_cache_init ();
+  isis_circuit_init ();
+  isis_spf_cmds_init ();
+
+  /* create the global 'isis' instance */
+  isis_new (1);
+
+  isis_zebra_init ();
+
   sort_node ();
 
   /* parse config file */
   /* this is needed three times! because we have interfaces before the areas */
   vty_read_config (config_file, config_default);
-  vty_read_config (config_file, config_default);
-  vty_read_config (config_file, config_default);
 
   /* Start execution only if not in dry-run mode */
   if (dryrun)
     return(0);
   
   /* demonize */
-  if (daemon_mode && daemon (0, 0) < 0)
-    {
-      zlog_err("ISISd daemon failed: %s", strerror(errno));
-      exit (1);
-    }
+  if (daemon_mode)
+    daemon (0, 0);
 
   /* Process ID file creation. */
-  pid_output (pid_file);
+  if (pid_file[0] != '\0')
+    pid_output (pid_file);
 
   /* Make isis vty socket. */
   vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH);

+ 128 - 6
isisd/isis_misc.c

@@ -32,7 +32,9 @@
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
+#include "isisd/isis_csm.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_misc.h"
 
@@ -40,6 +42,7 @@
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_adjacency.h"
+#include "isisd/isis_dynhn.h"
 
 /* staticly assigned vars for printing purposes */
 struct in_addr new_prefix;
@@ -99,10 +102,10 @@ isonet_print (u_char * from, int len)
  * extract dot from the dotted str, and insert all the number in a buff 
  */
 int
-dotformat2buff (u_char * buff, const u_char * dotted)
+dotformat2buff (u_char * buff, const char * dotted)
 {
   int dotlen, len = 0;
-  const u_char *pos = dotted;
+  const char *pos = dotted;
   u_char number[3];
   int nextdotpos = 2;
 
@@ -157,10 +160,10 @@ dotformat2buff (u_char * buff, const u_char * dotted)
  * conversion of XXXX.XXXX.XXXX to memory
  */
 int
-sysid2buff (u_char * buff, const u_char * dotted)
+sysid2buff (u_char * buff, const char * dotted)
 {
   int len = 0;
-  const u_char *pos = dotted;
+  const char *pos = dotted;
   u_char number[3];
 
   number[2] = '\0';
@@ -271,7 +274,7 @@ speaks (struct nlpids *nlpids, int family)
  * Returns 0 on error, IS-IS Circuit Type on ok
  */
 int
-string2circuit_t (const u_char * str)
+string2circuit_t (const char * str)
 {
 
   if (!str)
@@ -290,6 +293,42 @@ string2circuit_t (const u_char * str)
 }
 
 const char *
+circuit_state2string (int state)
+{
+
+  switch (state)
+    {
+    case C_STATE_INIT:
+      return "Init";
+    case C_STATE_CONF:
+      return "Config";
+    case C_STATE_UP:
+      return "Up";
+    default:
+      return "Unknown";
+    }
+  return NULL;
+}
+
+const char *
+circuit_type2string (int type)
+{
+
+  switch (type)
+    {
+    case CIRCUIT_T_P2P:
+      return "p2p";
+    case CIRCUIT_T_BROADCAST:
+      return "lan";
+    case CIRCUIT_T_LOOPBACK:
+      return "loopback";
+    default:
+      return "Unknown";
+    }
+  return NULL;
+}
+
+const char *
 circuit_t2string (int circuit_t)
 {
   switch (circuit_t)
@@ -498,7 +537,6 @@ unix_hostname (void)
 {
   static struct utsname names;
   const char *hostname;
-  extern struct host host;
 
   hostname = host.name;
   if (!hostname)
@@ -509,3 +547,87 @@ unix_hostname (void)
 
   return hostname;
 }
+
+/*
+ * Returns the dynamic hostname associated with the passed system ID.
+ * If no dynamic hostname found then returns formatted system ID.
+ */
+const char *
+print_sys_hostname (u_char *sysid)
+{
+  struct isis_dynhn *dyn;
+
+  if (!sysid)
+    return "nullsysid";
+
+  /* For our system ID return our host name */
+  if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
+    return unix_hostname();
+
+  dyn = dynhn_find_by_id (sysid);
+  if (dyn)
+    return (const char *)dyn->name.name;
+
+  return sysid_print (sysid);
+}
+
+/*
+ * This function is a generic utility that logs data of given length.
+ * Move this to a shared lib so that any protocol can use it.
+ */
+void
+zlog_dump_data (void *data, int len)
+{
+  int i;
+  unsigned char *p;
+  unsigned char c;
+  char bytestr[4];
+  char addrstr[10];
+  char hexstr[ 16*3 + 5];
+  char charstr[16*1 + 5];
+
+  p = data;
+  memset (bytestr, 0, sizeof(bytestr));
+  memset (addrstr, 0, sizeof(addrstr));
+  memset (hexstr, 0, sizeof(hexstr));
+  memset (charstr, 0, sizeof(charstr));
+
+  for (i = 1; i <= len; i++)
+  {
+    c = *p;
+    if (isalnum (c) == 0)
+      c = '.';
+
+    /* store address for this line */
+    if ((i % 16) == 1)
+      snprintf (addrstr, sizeof(addrstr), "%p", p);
+
+    /* store hex str (for left side) */
+    snprintf (bytestr, sizeof (bytestr), "%02X ", *p);
+    strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1);
+
+    /* store char str (for right side) */
+    snprintf (bytestr, sizeof (bytestr), "%c", c);
+    strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1);
+
+    if ((i % 16) == 0)
+    {
+      /* line completed */
+      zlog_debug ("[%8.8s]   %-50.50s  %s", addrstr, hexstr, charstr);
+      hexstr[0] = 0;
+      charstr[0] = 0;
+    }
+    else if ((i % 8) == 0)
+    {
+      /* half line: add whitespaces */
+      strncat (hexstr, "  ", sizeof (hexstr) - strlen (hexstr) - 1);
+      strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1);
+    }
+    p++; /* next byte */
+  }
+
+  /* print rest of buffer if not empty */
+  if (strlen (hexstr) > 0)
+    zlog_debug ("[%8.8s]   %-50.50s  %s", addrstr, hexstr, charstr);
+  return;
+}

+ 9 - 4
isisd/isis_misc.h

@@ -24,8 +24,10 @@
 #ifndef _ZEBRA_ISIS_MISC_H
 #define _ZEBRA_ISIS_MISC_H
 
-int string2circuit_t (const u_char *);
+int string2circuit_t (const char *);
 const char *circuit_t2string (int);
+const char *circuit_state2string (int state);
+const char *circuit_type2string (int type);
 const char *syst2string (int);
 struct in_addr newprefix2inaddr (u_char * prefix_start,
 				 u_char prefix_masklen);
@@ -33,8 +35,8 @@ struct in_addr newprefix2inaddr (u_char * prefix_start,
  * Converting input to memory stored format
  * return value of 0 indicates wrong input
  */
-int dotformat2buff (u_char *, const u_char *);
-int sysid2buff (u_char *, const u_char *);
+int dotformat2buff (u_char *, const char *);
+int sysid2buff (u_char *, const char *);
 
 /*
  * Printing functions
@@ -46,6 +48,8 @@ const char *rawlspid_print (u_char *);
 const char *time2string (u_int32_t);
 /* typedef struct nlpids nlpids; */
 char *nlpid2string (struct nlpids *);
+const char *print_sys_hostname (u_char *sysid);
+void zlog_dump_data (void *data, int len);
 
 /*
  * misc functions
@@ -57,7 +61,8 @@ const char *unix_hostname (void);
 /*
  * macros
  */
-#define GETSYSID(A,L) (A->area_addr + (A->addr_len - (L + 1)))
+#define GETSYSID(A) (A->area_addr + (A->addr_len - \
+                                     (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN)))
 
 /* used for calculating nice string representation instead of plain seconds */
 

File diff suppressed because it is too large
+ 996 - 490
isisd/isis_pdu.c


+ 14 - 5
isisd/isis_pdu.h

@@ -95,7 +95,7 @@ struct isis_fixed_hdr
   u_char version2;
   u_char reserved;
   u_char max_area_addrs;
-};
+} __attribute__ ((packed));
 
 #define ISIS_FIXED_HDR_LEN 8
 
@@ -186,6 +186,17 @@ struct isis_link_state_hdr
 } __attribute__ ((packed));
 #define ISIS_LSP_HDR_LEN 19
 
+/*
+ * Since the length field of LSP Entries TLV is one byte long, and each LSP
+ * entry is LSP_ENTRIES_LEN (16) bytes long, the maximum number of LSP entries
+ * can be accomodated in a TLV is
+ * 255 / 16 = 15.
+ * 
+ * Therefore, the maximum length of the LSP Entries TLV is
+ * 16 * 15 + 2 (header) = 242 bytes.
+ */
+#define MAX_LSP_ENTRIES_TLV_SIZE 242
+
 #define L1_COMPLETE_SEQ_NUM  24
 #define L2_COMPLETE_SEQ_NUM  25
 /*
@@ -241,6 +252,8 @@ int isis_receive (struct thread *thread);
 #define ISIS_SNP_PSNP_FLAG 0
 #define ISIS_SNP_CSNP_FLAG 1
 
+#define ISIS_AUTH_MD5_SIZE       16U
+
 /*
  * Sending functions
  */
@@ -258,8 +271,4 @@ int ack_lsp (struct isis_link_state_hdr *hdr,
 void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);
 int send_hello (struct isis_circuit *circuit, int level);
 
-
-int authentication_check (struct isis_passwd *one,
-			  struct isis_passwd *theother);
-
 #endif /* _ZEBRA_ISIS_PDU_H */

+ 54 - 37
isisd/isis_pfpacket.c

@@ -134,7 +134,7 @@ open_packet_socket (struct isis_circuit *circuit)
 
   circuit->fd = fd;
 
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+  if (if_is_broadcast (circuit->interface))
     {
       /*
        * Join to multicast groups
@@ -142,24 +142,22 @@ open_packet_socket (struct isis_circuit *circuit)
        * 8.4.2 - Broadcast subnetwork IIH PDUs
        * FIXME: is there a case only one will fail??
        */
-      if (circuit->circuit_is_type & IS_LEVEL_1)
-	{
-	  /* joining ALL_L1_ISS */
-	  retval = isis_multicast_join (circuit->fd, 1,
-					circuit->interface->ifindex);
-	  /* joining ALL_ISS */
-	  retval = isis_multicast_join (circuit->fd, 3,
-					circuit->interface->ifindex);
-	}
-      if (circuit->circuit_is_type & IS_LEVEL_2)
-	/* joining ALL_L2_ISS */
-	retval = isis_multicast_join (circuit->fd, 2,
-				      circuit->interface->ifindex);
+      if (circuit->is_type & IS_LEVEL_1)
+        /* joining ALL_L1_ISS */
+        retval = isis_multicast_join (circuit->fd, 1,
+                                      circuit->interface->ifindex);
+      if (circuit->is_type & IS_LEVEL_2)
+        /* joining ALL_L2_ISS */
+        retval = isis_multicast_join (circuit->fd, 2,
+                                      circuit->interface->ifindex);
+      /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */
+      retval = isis_multicast_join (circuit->fd, 3,
+                                    circuit->interface->ifindex);
     }
   else
     {
       retval =
-	isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
+        isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
     }
 
   return retval;
@@ -184,12 +182,13 @@ isis_sock_init (struct isis_circuit *circuit)
       goto end;
     }
 
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+  /* Assign Rx and Tx callbacks are based on real if type */
+  if (if_is_broadcast (circuit->interface))
     {
       circuit->tx = isis_send_pdu_bcast;
       circuit->rx = isis_recv_pdu_bcast;
     }
-  else if (circuit->circ_type == CIRCUIT_T_P2P)
+  else if (if_is_pointopoint (circuit->interface))
     {
       circuit->tx = isis_send_pdu_p2p;
       circuit->rx = isis_recv_pdu_p2p;
@@ -234,13 +233,14 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
 
   if (bytesread < 0)
     {
-      zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
-		 circuit->fd, safe_strerror (errno));
-      zlog_warn ("circuit is %s", circuit->interface->name);
-      zlog_warn ("circuit fd %d", circuit->fd);
-      zlog_warn ("bytesread %d", bytesread);
+      zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, "
+                 "recvfrom(): %s",
+                 circuit->interface->name, circuit->fd, bytesread,
+                 safe_strerror (errno));
       /* get rid of the packet */
-      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+      bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
+                            MSG_DONTWAIT, (struct sockaddr *) &s_addr,
+                            (socklen_t *) &addr_len);
       return ISIS_WARNING;
     }
   /*
@@ -249,15 +249,22 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
   if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
     {
       /*  Read the packet into discard buff */
-      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+      bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
+                            MSG_DONTWAIT, (struct sockaddr *) &s_addr,
+                            (socklen_t *) &addr_len);
       if (bytesread < 0)
-	zlog_warn ("isis_recv_pdu_bcast(): read() failed");
+	zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
       return ISIS_WARNING;
     }
 
   /* on lan we have to read to the static buff first */
-  bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0,
+  bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
 			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
+  if (bytesread < 0)
+    {
+      zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
+      return ISIS_WARNING;
+    }
 
   /* then we lose the LLC */
   stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
@@ -285,9 +292,11 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
   if (s_addr.sll_pkttype == PACKET_OUTGOING)
     {
       /*  Read the packet into discard buff */
-      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+      bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
+                            MSG_DONTWAIT, (struct sockaddr *) &s_addr,
+                            (socklen_t *) &addr_len);
       if (bytesread < 0)
-	zlog_warn ("isis_recv_pdu_p2p(): read() failed");
+	zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
       return ISIS_WARNING;
     }
 
@@ -309,6 +318,9 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
 int
 isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
 {
+  struct msghdr msg;
+  struct iovec iov[2];
+
   /* we need to do the LLC in here because of P2P circuits, which will
    * not need it
    */
@@ -321,7 +333,10 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
   sa.sll_ifindex = circuit->interface->ifindex;
   sa.sll_halen = ETH_ALEN;
-  if (level == 1)
+  /* RFC5309 section 4.1 recommends ALL_ISS */
+  if (circuit->circ_type == CIRCUIT_T_P2P)
+    memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN);
+  else if (level == 1)
     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
   else
     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
@@ -332,14 +347,17 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   sock_buff[1] = 0xFE;
   sock_buff[2] = 0x03;
 
-  /* then we copy the data */
-  memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
-	  stream_get_endp (circuit->snd_stream));
+  memset (&msg, 0, sizeof (msg));
+  msg.msg_name = &sa;
+  msg.msg_namelen = sizeof (struct sockaddr_ll);
+  msg.msg_iov = iov;
+  msg.msg_iovlen = 2;
+  iov[0].iov_base = sock_buff;
+  iov[0].iov_len = LLC_LEN;
+  iov[1].iov_base = circuit->snd_stream->data;
+  iov[1].iov_len = stream_get_endp (circuit->snd_stream);
 
-  /* now we can send this */
-  written = sendto (circuit->fd, sock_buff,
-		    stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
-		    (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));
+  written = sendmsg (circuit->fd, &msg, 0);
 
   return ISIS_OK;
 }
@@ -347,7 +365,6 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
 int
 isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
 {
-
   int written = 1;
   struct sockaddr_ll sa;
 

+ 92 - 156
isisd/isis_route.c

@@ -36,6 +36,7 @@
 
 #include "isis_constants.h"
 #include "isis_common.h"
+#include "isis_flags.h"
 #include "dict.h"
 #include "isisd.h"
 #include "isis_misc.h"
@@ -48,9 +49,6 @@
 #include "isis_route.h"
 #include "isis_zebra.h"
 
-extern struct isis *isis;
-extern struct thread_master *master;
-
 static struct isis_nexthop *
 isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
 {
@@ -294,14 +292,24 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
     {
       rinfo->nexthops = list_new ();
       for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
-        adjinfo2nexthop (rinfo->nexthops, adj);
+        {
+          /* check for force resync this route */
+          if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
+            SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+          adjinfo2nexthop (rinfo->nexthops, adj);
+        }
     }
 #ifdef HAVE_IPV6
   if (family == AF_INET6)
     {
       rinfo->nexthops6 = list_new ();
       for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
-        adjinfo2nexthop6 (rinfo->nexthops6, adj);
+        {
+          /* check for force resync this route */
+          if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
+            SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+          adjinfo2nexthop6 (rinfo->nexthops6, adj);
+        }
     }
 
 #endif /* HAVE_IPV6 */
@@ -353,18 +361,25 @@ isis_route_info_same (struct isis_route_info *new,
 #ifdef HAVE_IPV6
   struct isis_nexthop6 *nexthop6;
 #endif /* HAVE_IPV6 */
+
+  if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+    return 0;
+
+  if (CHECK_FLAG (new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC))
+    return 0;
+
   if (!isis_route_info_same_attrib (new, old))
     return 0;
 
   if (family == AF_INET)
     {
       for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
-        if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) 
+        if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
               == 0)
           return 0;
 
       for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
-        if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) 
+        if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
              == 0)
           return 0;
     }
@@ -386,65 +401,6 @@ isis_route_info_same (struct isis_route_info *new,
   return 1;
 }
 
-static void
-isis_nexthops_merge (struct list *new, struct list *old)
-{
-  struct listnode *node;
-  struct isis_nexthop *nexthop;
-
-  for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
-    {
-      if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
-	continue;
-      listnode_add (old, nexthop);
-      nexthop->lock++;
-    }
-}
-
-#ifdef HAVE_IPV6
-static void
-isis_nexthops6_merge (struct list *new, struct list *old)
-{
-  struct listnode *node;
-  struct isis_nexthop6 *nexthop6;
-
-  for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
-    {
-      if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
-	continue;
-      listnode_add (old, nexthop6);
-      nexthop6->lock++;
-    }
-}
-#endif /* HAVE_IPV6 */
-
-static void
-isis_route_info_merge (struct isis_route_info *new,
-		       struct isis_route_info *old, u_char family)
-{
-  if (family == AF_INET)
-    isis_nexthops_merge (new->nexthops, old->nexthops);
-#ifdef HAVE_IPV6
-  else if (family == AF_INET6)
-    isis_nexthops6_merge (new->nexthops6, old->nexthops6);
-#endif /* HAVE_IPV6 */
-
-  return;
-}
-
-static int
-isis_route_info_prefer_new (struct isis_route_info *new,
-			    struct isis_route_info *old)
-{
-  if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
-    return 1;
-
-  if (new->cost < old->cost)
-    return 1;
-
-  return 0;
-}
-
 struct isis_route_info *
 isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
 		   struct list *adjacencies, struct isis_area *area,
@@ -479,68 +435,32 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
   if (!rinfo_old)
     {
       if (isis->debugs & DEBUG_RTE_EVENTS)
-	zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
-      SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
-      route_node->info = rinfo_new;
-      return rinfo_new;
-    }
-
-  if (isis->debugs & DEBUG_RTE_EVENTS)
-    zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
-	       buff);
-
-  if (isis_route_info_same (rinfo_new, rinfo_old, family))
-    {
-      if (isis->debugs & DEBUG_RTE_EVENTS)
-	zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
-      isis_route_info_delete (rinfo_new);
-      route_info = rinfo_old;
-    }
-  else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
-    {
-      /* merge the nexthop lists */
-      if (isis->debugs & DEBUG_RTE_EVENTS)
-	zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
-		   area->area_tag, buff);
-#ifdef EXTREME_DEBUG
-      if (family == AF_INET)
-	{
-	  zlog_debug ("Old nexthops");
-	  nexthops_print (rinfo_old->nexthops);
-	  zlog_debug ("New nexthops");
-	  nexthops_print (rinfo_new->nexthops);
-	}
-      else if (family == AF_INET6)
-	{
-	  zlog_debug ("Old nexthops");
-	  nexthops6_print (rinfo_old->nexthops6);
-	  zlog_debug ("New nexthops");
-	  nexthops6_print (rinfo_new->nexthops6);
-	}
-#endif /* EXTREME_DEBUG */
-      isis_route_info_merge (rinfo_new, rinfo_old, family);
-      isis_route_info_delete (rinfo_new);
-      route_info = rinfo_old;
-      UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+        zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
+      route_info = rinfo_new;
+      UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
     }
   else
     {
-      if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
-	{
-	  if (isis->debugs & DEBUG_RTE_EVENTS)
-	    zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
-			buff);
-	  isis_route_info_delete (rinfo_old);
-	  route_info = rinfo_new;
-	}
+      if (isis->debugs & DEBUG_RTE_EVENTS)
+        zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
+                   buff);
+      if (isis_route_info_same (rinfo_new, rinfo_old, family))
+        {
+          if (isis->debugs & DEBUG_RTE_EVENTS)
+            zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag,
+                        buff);
+          isis_route_info_delete (rinfo_new);
+          route_info = rinfo_old;
+        }
       else
-	{
-	  if (isis->debugs & DEBUG_RTE_EVENTS)
-	    zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
-			buff);
-	  isis_route_info_delete (rinfo_new);
-	  route_info = rinfo_old;
-	}
+        {
+          if (isis->debugs & DEBUG_RTE_EVENTS)
+            zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
+                        buff);
+          isis_route_info_delete (rinfo_old);
+          route_info = rinfo_new;
+          UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+        }
     }
 
   SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
@@ -570,7 +490,7 @@ isis_route_delete (struct prefix *prefix, struct route_table *table)
       return;
     }
 
-  if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+  if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
     {
       UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
       if (isis->debugs & DEBUG_RTE_EVENTS)
@@ -600,10 +520,12 @@ isis_route_validate_table (struct isis_area *area, struct route_table *table)
       if (isis->debugs & DEBUG_RTE_EVENTS)
 	{
 	  prefix2str (&rnode->p, (char *) buff, BUFSIZ);
-	  zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
+	  zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s",
 		      area->area_tag,
-		      (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
-		      "sync'ed" : "nosync"),
+		      (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ?
+		      "synced" : "not-synced"),
+		      (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ?
+		      "resync" : "not-resync"),
 		      (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
 		      "active" : "inactive"), buff);
 	}
@@ -706,41 +628,55 @@ isis_route_validate_merge (struct isis_area *area, int family)
 
 /* Walk through route tables and propagate necessary changes into RIB. In case
  * of L1L2 area, level tables have to be merged at first. */
-int
-isis_route_validate (struct thread *thread)
+void
+isis_route_validate (struct isis_area *area)
 {
-  struct isis_area *area;
-
-  area = THREAD_ARG (thread);
+  struct listnode *node;
+  struct isis_circuit *circuit;
 
   if (area->is_type == IS_LEVEL_1)
-    { 
-      isis_route_validate_table (area, area->route_table[0]);
-      goto validate_ipv6;
-    }
-  if (area->is_type == IS_LEVEL_2)
-    {
-      isis_route_validate_table (area, area->route_table[1]);
-      goto validate_ipv6;
-    }
-
-  isis_route_validate_merge (area, AF_INET);
+    isis_route_validate_table (area, area->route_table[0]);
+  else if (area->is_type == IS_LEVEL_2)
+    isis_route_validate_table (area, area->route_table[1]);
+  else
+    isis_route_validate_merge (area, AF_INET);
 
-validate_ipv6:
 #ifdef HAVE_IPV6
   if (area->is_type == IS_LEVEL_1)
+    isis_route_validate_table (area, area->route_table6[0]);
+  else if (area->is_type == IS_LEVEL_2)
+    isis_route_validate_table (area, area->route_table6[1]);
+  else
+    isis_route_validate_merge (area, AF_INET6);
+#endif
+
+  /* walk all circuits and reset any spf specific flags */
+  for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
+    UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
+
+  return;
+}
+
+void
+isis_route_invalidate_table (struct isis_area *area, struct route_table *table)
+{
+  struct route_node *rode;
+  struct isis_route_info *rinfo;
+  for (rode = route_top (table); rode; rode = route_next (rode))
     {
-      isis_route_validate_table (area, area->route_table6[0]);
-      return ISIS_OK;
-    }
-  if (area->is_type == IS_LEVEL_2)
-    {
-      isis_route_validate_table (area, area->route_table6[1]);
-      return ISIS_OK;
-    }
+      if (rode->info == NULL)
+        continue;
+      rinfo = rode->info;
 
-  isis_route_validate_merge (area, AF_INET6);
-#endif
+      UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
+    }
+}
 
-  return ISIS_OK;
+void
+isis_route_invalidate (struct isis_area *area)
+{