]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge quagga mainline into the google ISIS code.
authorAvneesh Sachdev <avneesh@opensourcerouting.org>
Thu, 12 Apr 2012 06:51:08 +0000 (23:51 -0700)
committerAvneesh Sachdev <avneesh@opensourcerouting.org>
Thu, 12 Apr 2012 06:51:08 +0000 (23:51 -0700)
The steps were:

  $ git checkout google-is-is
  $ git merge quagga
  $ git checkout google-is-is -- isisd

  # Resolve conflicts in the following:
  lib/md5.h
  zebra/rt_netlink.c
  zebra/zebra_rib.c
  zebra/zserv.c

Note that the content in the isisd directory is left unchanged in the
merge. As a result, changes made to isisd as part of the following
commits on the quagga mainline are dropped.

  # 8ced4e82 is the merge base, e96b3121 is the current quagga master
  $ git log --oneline --reverse 8ced4e82..e96b3121 -- isisd
  5574999 isisd: fix crash on "no router isis" (BZ#536)
  8998075 isisd: raise hello rate for DIS (BZ#539)
  306ca83 isisd: include hash.h, not hash.c
  b82cdeb delete CVS keywords
  2f65867 isisd: indent longopts array
  b511468 quagga: option "-z" ("--socket <path>") added
  05e54ee build: delete .cvsignore files
  b4e45f6 fix zebra protocol after MP-BGP changes
  7fd6cd8 isisd: fix circuit state machine
  907fd95 isisd: send proper LSP after DIS election
  d034aa0 isisd: fix wrong next-hops from SPF
  c25eaff isisd: unexpected kernel routing table (BZ#544)
  e6b03b7 isisd: implement MD5 circuit authentication

52 files changed:
isisd/.cvsignore [new file with mode: 0644]
isisd/AUTHORS
isisd/dict.c
isisd/dict.h
isisd/include-netbsd/.cvsignore [new file with mode: 0644]
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_bpf.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_common.h
isisd/isis_constants.h
isisd/isis_csm.c
isisd/isis_dlpi.c
isisd/isis_dr.c
isisd/isis_dynhn.c
isisd/isis_dynhn.h
isisd/isis_events.c
isisd/isis_events.h
isisd/isis_flags.c
isisd/isis_flags.h
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_main.c
isisd/isis_misc.c
isisd/isis_misc.h
isisd/isis_pdu.c
isisd/isis_pdu.h
isisd/isis_pfpacket.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_routemap.c
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_tlv.c
isisd/isis_tlv.h
isisd/isis_zebra.c
isisd/isisd.c
isisd/isisd.h
isisd/topology/.cvsignore [new file with mode: 0644]
lib/if.c
lib/linklist.h
lib/md5.h
lib/memtypes.c
lib/stream.c
lib/stream.h
lib/zclient.c
zebra/rib.h
zebra/rt_netlink.c
zebra/zebra_rib.c
zebra/zserv.c
zebra/zserv.h

diff --git a/isisd/.cvsignore b/isisd/.cvsignore
new file mode 100644 (file)
index 0000000..26aa85c
--- /dev/null
@@ -0,0 +1,12 @@
+Makefile
+Makefile.in
+*.o
+isisd
+.deps
+isisd.conf
+.nfs*
+*.lo
+*.la
+*.libs
+.arch-inventory
+.arch-ids
index d9f98b22aa5852d6dcf04b09e9719b56e643ded9..05fc0a50738949856f4b1401a3b363867d1faa56 100644 (file)
@@ -1,3 +1,4 @@
-Sampo Saaristo <sambo@cs.tut.fi>
-Ofer Wald      <ofersf@islands.co.il>
-Hannes Gredler <hannes@gredler.at>
+Sampo Saaristo   <sambo@cs.tut.fi>
+Ofer Wald        <ofersf@islands.co.il>
+Hannes Gredler   <hannes@gredler.at>
+Subbaiah Venkata <svenkata@google.com>
index a78b82ac4f17acc569cc8405c15046b153c3ea49..35cb924ca6dd766d7e0fef31452b62a437264962 100644 (file)
  * This source code may be translated into executable form and incorporated
  * into proprietary software; there is no requirement for such software to
  * contain a copyright notice related to this source.
+ *
+ * $Id$
+ * $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
@@ -243,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;
@@ -284,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);
 }
 
 /*
@@ -307,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);
 }
 
@@ -810,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);
@@ -946,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;
@@ -978,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)
@@ -1232,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;
@@ -1347,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 (;;) {
index 9395d1c0805867f1e4501cc9dab7c6d0d2cd09da..93edb7d6039b248759dad329f5b2d943d2fa5471 100644 (file)
@@ -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
 }
diff --git a/isisd/include-netbsd/.cvsignore b/isisd/include-netbsd/.cvsignore
new file mode 100644 (file)
index 0000000..73bcf19
--- /dev/null
@@ -0,0 +1,3 @@
+.arch-inventory
+.arch-ids
+
index de34bea9d3f8b73943533eec10f5f14e86748080..468b0a69c6a272a56cb98e94b405871b293bb7e9 100644 (file)
@@ -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"
 #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,107 @@ 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)
-       {
-         listnode_delete (adj->circuit->u.bc.adjdb[level - 1], adj);
-         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);
+        }
+
+        if (circuit->u.bc.lan_neighs[level - 1])
+          {
+            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 +318,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 +327,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 +344,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 +358,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 +406,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 +419,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);
@@ -393,53 +479,6 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
   return;
 }
 
-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)
 {
index 99a8bb22879aa8234fe9336929d7052bc1bfc72b..caa3107db25c46d5187d0f3bbbd802364afe7f8b 100644 (file)
@@ -44,6 +44,7 @@ enum isis_system_type
 
 enum isis_adj_state
 {
+  ISIS_ADJ_UNKNOWN,
   ISIS_ADJ_INITIALIZING,
   ISIS_ADJ_UP,
   ISIS_ADJ_DOWN
@@ -83,8 +84,10 @@ struct isis_adjacency
   struct list *area_addrs;             /* areaAdressesOfNeighbour */
   struct nlpids nlpids;                        /* protocols spoken ... */
   struct list *ipv4_addrs;
+  struct in_addr router_address;
 #ifdef HAVE_IPV6
   struct list *ipv6_addrs;
+  struct in6_addr router_address6;
 #endif                         /* HAVE_IPV6 */
   u_char prio[ISIS_LEVELS];    /* priorityOfNeighbour for DIS */
   int circuit_t;               /* from hello PDU hdr */
@@ -103,25 +106,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 */
index 05f11386c4d6197d89b8079a6973094fdcd15cdd..4d5b1651314107b13c6e92e6666bb691403a8022 100644 (file)
@@ -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;
 }
index 99e2bf6f2c4e683cd980b59eaaa057701a0ce34c..c09c3a2826c0a0ed23d45f5a9f853356342db4f8 100644 (file)
@@ -44,6 +44,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"
 #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"
 
-extern struct thread_master *master;
-extern struct isis *isis;
-
 /*
  * Prototypes.
  */
-void isis_circuit_down(struct isis_circuit *);
 int isis_interface_config_write(struct vty *);
 int isis_if_new_hook(struct interface *);
 int isis_if_delete_hook(struct interface *);
@@ -76,55 +72,63 @@ isis_circuit_new ()
   int i;
 
   circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit));
-  if (circuit)
-    {
-      /* set default metrics for circuit */
-      for (i = 0; i < 2; i++)
-       {
-         circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRICS;
-         circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED;
-         circuit->metrics[i].metric_error = METRICS_UNSUPPORTED;
-         circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED;
-         circuit->te_metric[i] = DEFAULT_CIRCUIT_METRICS;
-       }
-    }
-  else
+  if (circuit == NULL)
     {
       zlog_err ("Can't malloc isis circuit");
       return NULL;
     }
 
+  /*
+   * Default values
+   */
+  circuit->is_type = IS_LEVEL_1_AND_2;
+  circuit->flags = 0;
+  circuit->pad_hellos = 1;
+  for (i = 0; i < 2; i++)
+    {
+      circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL;
+      circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER;
+      circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL;
+      circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL;
+      circuit->priority[i] = DEFAULT_PRIORITY;
+      circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC;
+      circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED;
+      circuit->metrics[i].metric_error = METRICS_UNSUPPORTED;
+      circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED;
+      circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
+    }
+
   return circuit;
 }
 
+void
+isis_circuit_del (struct isis_circuit *circuit)
+{
+  if (!circuit)
+    return;
+
+  isis_circuit_if_unbind (circuit, circuit->interface);
+
+  /* and lastly the circuit itself */
+  XFREE (MTYPE_ISIS_CIRCUIT, circuit);
+
+  return;
+}
+
 void
 isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
 {
-  int i;
+  assert (area);
   circuit->area = area;
+
   /*
    * The level for the circuit is same as for the area, unless configured
    * otherwise.
    */
-  circuit->circuit_is_type = area->is_type;
-  /*
-   * Default values
-   */
-  for (i = 0; i < 2; i++)
-    {
-      circuit->hello_interval[i] = HELLO_INTERVAL;
-      circuit->hello_multiplier[i] = HELLO_MULTIPLIER;
-      circuit->csnp_interval[i] = CSNP_INTERVAL;
-      circuit->psnp_interval[i] = PSNP_INTERVAL;
-      circuit->u.bc.priority[i] = DEFAULT_PRIORITY;
-    }
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
-    {
-      circuit->u.bc.adjdb[0] = list_new ();
-      circuit->u.bc.adjdb[1] = list_new ();
-      circuit->u.bc.pad_hellos = 1;
-    }
-  circuit->lsp_interval = LSP_INTERVAL;
+  if (area->is_type != IS_LEVEL_1_AND_2 && area->is_type != circuit->is_type)
+    zlog_warn ("circut %s is_type %d mismatch with area %s is_type %d",
+               circuit->interface->name, circuit->is_type,
+               circuit->area->area_tag, area->is_type);
 
   /*
    * Add the circuit into area
@@ -132,25 +136,20 @@ isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
   listnode_add (area->circuit_list, circuit);
 
   circuit->idx = flags_get_index (&area->flags);
-  circuit->lsp_queue = list_new ();
 
   return;
 }
 
 void
-isis_circuit_deconfigure (struct isis_circuit *circuit,
-                         struct isis_area *area)
+isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area)
 {
-
-  /* destroy adjacencies */
-  if (circuit->u.bc.adjdb[0])
-    isis_adjdb_iterate (circuit->u.bc.adjdb[0], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[0]);
-  if (circuit->u.bc.adjdb[1])
-    isis_adjdb_iterate (circuit->u.bc.adjdb[1], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[1]);
-  /* Remove circuit from area */
-  listnode_delete (area->circuit_list, circuit);
   /* Free the index of SRM and SSN flags */
   flags_free_index (&area->flags, circuit->idx);
+  circuit->idx = 0;
+  /* Remove circuit from area */
+  assert (circuit->area == area);
+  listnode_delete (area->circuit_list, circuit);
+  circuit->area = NULL;
 
   return;
 }
@@ -166,8 +165,11 @@ circuit_lookup_by_ifp (struct interface *ifp, struct list *list)
 
   for (ALL_LIST_ELEMENTS_RO (list, node, circuit))
     if (circuit->interface == ifp)
-      return circuit;
-  
+      {
+        assert (ifp->info == circuit);
+        return circuit;
+      }
+
   return NULL;
 }
 
@@ -178,83 +180,77 @@ circuit_scan_by_ifp (struct interface *ifp)
   struct listnode *node;
   struct isis_circuit *circuit;
 
-  if (!isis->area_list)
-    return NULL;
+  if (ifp->info)
+    return (struct isis_circuit *)ifp->info;
 
-  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+  if (isis->area_list)
     {
-      circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
-      if (circuit)
-       return circuit;
+      for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+        {
+          circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+          if (circuit)
+            return circuit;
+        }
     }
-
   return circuit_lookup_by_ifp (ifp, isis->init_circ_list);
 }
 
-void
-isis_circuit_del (struct isis_circuit *circuit)
+static struct isis_circuit *
+isis_circuit_lookup (struct vty *vty)
 {
+  struct interface *ifp;
+  struct isis_circuit *circuit;
 
-  if (!circuit)
-    return;
-
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+  ifp = (struct interface *) vty->index;
+  if (!ifp)
     {
-      /* destroy adjacency databases */
-      if (circuit->u.bc.adjdb[0])
-       list_delete (circuit->u.bc.adjdb[0]);
-      if (circuit->u.bc.adjdb[1])
-       list_delete (circuit->u.bc.adjdb[1]);
-      /* destroy neighbour lists */
-      if (circuit->u.bc.lan_neighs[0])
-       list_delete (circuit->u.bc.lan_neighs[0]);
-      if (circuit->u.bc.lan_neighs[1])
-       list_delete (circuit->u.bc.lan_neighs[1]);
-      /* destroy addresses */
+      vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+      return NULL;
     }
-  if (circuit->ip_addrs)
-    list_delete (circuit->ip_addrs);
-#ifdef HAVE_IPV6
-  if (circuit->ipv6_link)
-    list_delete (circuit->ipv6_link);
-  if (circuit->ipv6_non_link)
-    list_delete (circuit->ipv6_non_link);
-#endif /* HAVE_IPV6 */
 
-  /* and lastly the circuit itself */
-  XFREE (MTYPE_ISIS_CIRCUIT, circuit);
+  circuit = circuit_scan_by_ifp (ifp);
+  if (!circuit)
+    {
+      vty_out (vty, "ISIS is not enabled on circuit %s%s",
+               ifp->name, VTY_NEWLINE);
+      return NULL;
+    }
 
-  return;
+  return circuit;
 }
 
 void
 isis_circuit_add_addr (struct isis_circuit *circuit,
                       struct connected *connected)
 {
+  struct listnode *node;
   struct prefix_ipv4 *ipv4;
   u_char buf[BUFSIZ];
 #ifdef HAVE_IPV6
   struct prefix_ipv6 *ipv6;
 #endif /* HAVE_IPV6 */
 
-  if (!circuit->ip_addrs)
-    circuit->ip_addrs = list_new ();
-#ifdef HAVE_IPV6
-  if (!circuit->ipv6_link)
-    circuit->ipv6_link = list_new ();
-  if (!circuit->ipv6_non_link)
-    circuit->ipv6_non_link = list_new ();
-#endif /* HAVE_IPV6 */
-
   memset (&buf, 0, BUFSIZ);
   if (connected->address->family == AF_INET)
     {
+      u_int32_t addr = connected->address->u.prefix4.s_addr;
+      addr = ntohl (addr);
+      if (IPV4_NET0(addr) ||
+          IPV4_NET127(addr) ||
+          IN_CLASSD(addr) ||
+          IPV4_LINKLOCAL(addr))
+        return;
+
+      for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4))
+        if (prefix_same ((struct prefix *) ipv4, connected->address))
+          return;
+
       ipv4 = prefix_ipv4_new ();
       ipv4->prefixlen = connected->address->prefixlen;
       ipv4->prefix = connected->address->u.prefix4;
       listnode_add (circuit->ip_addrs, ipv4);
       if (circuit->area)
-       lsp_regenerate_schedule (circuit->area);
+        lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
 
 #ifdef EXTREME_DEBUG
       prefix2str (connected->address, buf, BUFSIZ);
@@ -265,6 +261,16 @@ isis_circuit_add_addr (struct isis_circuit *circuit,
 #ifdef HAVE_IPV6
   if (connected->address->family == AF_INET6)
     {
+      if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6))
+        return;
+
+      for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6))
+        if (prefix_same ((struct prefix *) ipv6, connected->address))
+          return;
+      for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6))
+        if (prefix_same ((struct prefix *) ipv6, connected->address))
+          return;
+
       ipv6 = prefix_ipv6_new ();
       ipv6->prefixlen = connected->address->prefixlen;
       ipv6->prefix = connected->address->u.prefix6;
@@ -274,7 +280,7 @@ isis_circuit_add_addr (struct isis_circuit *circuit,
       else
        listnode_add (circuit->ipv6_non_link, ipv6);
       if (circuit->area)
-       lsp_regenerate_schedule (circuit->area);
+        lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
 
 #ifdef EXTREME_DEBUG
       prefix2str (connected->address, buf, BUFSIZ);
@@ -306,20 +312,20 @@ isis_circuit_del_addr (struct isis_circuit *circuit,
       ipv4->prefix = connected->address->u.prefix4;
 
       for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip))
-        if (prefix_same ((struct prefix *) ip, (struct prefix *) &ipv4))
+        if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4))
           break;
 
       if (ip)
        {
          listnode_delete (circuit->ip_addrs, ip);
-         if (circuit->area)
-           lsp_regenerate_schedule (circuit->area);
+          if (circuit->area)
+            lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
        }
       else
        {
          prefix2str (connected->address, (char *)buf, BUFSIZ);
-         zlog_warn("Nonexitant ip address %s removal attempt from circuit \
-                    %d", buf, circuit->circuit_id);
+         zlog_warn ("Nonexitant ip address %s removal attempt from \
+                      circuit %d", buf, circuit->circuit_id);
        }
     }
 #ifdef HAVE_IPV6
@@ -359,72 +365,105 @@ isis_circuit_del_addr (struct isis_circuit *circuit,
       if (!found)
        {
          prefix2str (connected->address, (char *)buf, BUFSIZ);
-         zlog_warn("Nonexitant ip address %s removal attempt from \
-                    circuit %d", buf, circuit->circuit_id);
+         zlog_warn ("Nonexitant ip address %s removal attempt from \
+                     circuit %d", buf, circuit->circuit_id);
        }
-      else
-       if (circuit->area)
-         lsp_regenerate_schedule (circuit->area);
+      else if (circuit->area)
+         lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
     }
 #endif /* HAVE_IPV6 */
   return;
 }
 
+static u_char
+isis_circuit_id_gen (struct interface *ifp)
+{
+  u_char id = 0;
+  char ifname[16];
+  unsigned int i;
+  int start = -1, end = -1;
+
+  /*
+   * Get a stable circuit id from ifname. This makes
+   * the ifindex from flapping when netdevs are created
+   * and deleted on the fly. Note that this circuit id
+   * is used in pseudo lsps so it is better to be stable.
+   * The following code works on any reasonanle ifname
+   * like: eth1 or trk-1.1 etc.
+   */
+  for (i = 0; i < strlen (ifp->name); i++)
+    {
+      if (isdigit(ifp->name[i]))
+        {
+          if (start < 0)
+            {
+              start = i;
+              end = i + 1;
+            }
+          else
+            {
+              end = i + 1;
+            }
+        }
+      else if (start >= 0)
+        break;
+    }
+
+  if ((start >= 0) && (end >= start) && (end - start) < 16)
+    {
+      memset (ifname, 0, 16);
+      strncpy (ifname, &ifp->name[start], end - start);
+      id = (u_char)atoi(ifname);
+    }
+
+  /* Try to be unique. */
+  if (!id)
+    id = (u_char)((ifp->ifindex & 0xff) | 0x80);
+
+  return id;
+}
+
 void
 isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
 {
   struct listnode *node, *nnode;
   struct connected *conn;
 
-  circuit->interface = ifp;
-  ifp->info = circuit;
-
-  circuit->circuit_id = ifp->ifindex % 255;    /* FIXME: Why not ? */
+  circuit->circuit_id = isis_circuit_id_gen (ifp);
 
+  isis_circuit_if_bind (circuit, ifp);
   /*  isis_circuit_update_addrs (circuit, ifp); */
 
   if (if_is_broadcast (ifp))
     {
-      circuit->circ_type = CIRCUIT_T_BROADCAST;
-      /*
-       * Get the Hardware Address
-       */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-#ifndef SUNOS_5
-      if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
-       zlog_warn ("unsupported link layer");
-      else
-       memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl),
-               ETH_ALEN);
-#endif
-#else
-      if (circuit->interface->hw_addr_len != ETH_ALEN)
-       {
-         zlog_warn ("unsupported link layer");
-       }
+      if (circuit->circ_type_config == CIRCUIT_T_P2P)
+        circuit->circ_type = CIRCUIT_T_P2P;
       else
-       {
-         memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
-       }
-#ifdef EXTREME_DEGUG
-      zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
-                circuit->interface->ifindex, ISO_MTU (circuit),
-                snpa_print (circuit->u.bc.snpa));
-
-#endif /* EXTREME_DEBUG */
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
+        circuit->circ_type = CIRCUIT_T_BROADCAST;
     }
   else if (if_is_pointopoint (ifp))
     {
       circuit->circ_type = CIRCUIT_T_P2P;
     }
+  else if (if_is_loopback (ifp))
+    {
+      circuit->circ_type = CIRCUIT_T_LOOPBACK;
+      circuit->is_passive = 1;
+    }
   else
     {
       /* It's normal in case of loopback etc. */
       if (isis->debugs & DEBUG_EVENTS)
-       zlog_debug ("isis_circuit_if_add: unsupported media");
+        zlog_debug ("isis_circuit_if_add: unsupported media");
+      circuit->circ_type = CIRCUIT_T_UNKNOWN;
     }
 
+  circuit->ip_addrs = list_new ();
+#ifdef HAVE_IPV6
+  circuit->ipv6_link = list_new ();
+  circuit->ipv6_non_link = list_new ();
+#endif /* HAVE_IPV6 */
+
   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
     isis_circuit_add_addr (circuit, conn);
 
@@ -432,88 +471,158 @@ isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
 }
 
 void
-isis_circuit_update_params (struct isis_circuit *circuit,
-                           struct interface *ifp)
+isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp)
 {
-  assert (circuit);
+  struct listnode *node, *nnode;
+  struct connected *conn;
 
-  if (circuit->circuit_id != ifp->ifindex)
-    {
-      zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id,
-                ifp->ifindex);
-      circuit->circuit_id = ifp->ifindex % 255;
-    }
+  assert (circuit->interface == ifp);
 
-  /* FIXME: Why is this needed? shouldn't we compare to the area's mtu */
-  /* Ofer, this was here in case someone changes the mtu (e.g. with ifconfig) 
-     The areas MTU is the minimum of mtu's of circuits in the area
-     now we can't catch the change
-     if (circuit->mtu != ifp->mtu) {
-     zlog_warn ("changing circuit mtu %d->%d", circuit->mtu, 
-     ifp->mtu);    
-     circuit->mtu = ifp->mtu;
-     }
-   */
-  /*
-   * Get the Hardware Address
-   */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-#ifndef SUNOS_5
-  if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
-    zlog_warn ("unsupported link layer");
-  else
-    memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), ETH_ALEN);
-#endif
-#else
-  if (circuit->interface->hw_addr_len != ETH_ALEN)
-    {
-      zlog_warn ("unsupported link layer");
-    }
-  else
-    {
-      if (memcmp (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN))
-       {
-         zlog_warn ("changing circuit snpa %s->%s",
-                    snpa_print (circuit->u.bc.snpa),
-                    snpa_print (circuit->interface->hw_addr));
-       }
-    }
-#endif
+  /* destroy addresses */
+  for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
+    isis_circuit_del_addr (circuit, conn);
 
-  if (if_is_broadcast (ifp))
+  if (circuit->ip_addrs)
     {
-      circuit->circ_type = CIRCUIT_T_BROADCAST;
+      assert (listcount(circuit->ip_addrs) == 0);
+      list_delete (circuit->ip_addrs);
+      circuit->ip_addrs = NULL;
     }
-  else if (if_is_pointopoint (ifp))
+
+#ifdef HAVE_IPV6
+  if (circuit->ipv6_link)
     {
-      circuit->circ_type = CIRCUIT_T_P2P;
+      assert (listcount(circuit->ipv6_link) == 0);
+      list_delete (circuit->ipv6_link);
+      circuit->ipv6_link = NULL;
     }
-  else
+
+  if (circuit->ipv6_non_link)
     {
-      zlog_warn ("isis_circuit_update_params: unsupported media");
+      assert (listcount(circuit->ipv6_non_link) == 0);
+      list_delete (circuit->ipv6_non_link);
+      circuit->ipv6_non_link = NULL;
     }
+#endif /* HAVE_IPV6 */
+
+  circuit->circ_type = CIRCUIT_T_UNKNOWN;
+  circuit->circuit_id = 0;
 
   return;
 }
 
 void
-isis_circuit_if_del (struct isis_circuit *circuit)
+isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp)
+{
+  assert (circuit != NULL);
+  assert (ifp != NULL);
+  if (circuit->interface)
+    assert (circuit->interface == ifp);
+  else
+    circuit->interface = ifp;
+  if (ifp->info)
+    assert (ifp->info == circuit);
+  else
+    ifp->info = circuit;
+}
+
+void
+isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp)
 {
-  circuit->interface->info = NULL;
+  assert (circuit != NULL);
+  assert (ifp != NULL);
+  assert (circuit->interface == ifp);
+  assert (ifp->info == circuit);
   circuit->interface = NULL;
+  ifp->info = NULL;
+}
 
-  return;
+static void
+isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set)
+{
+  struct isis_area *area;
+  struct isis_lsp *lsp;
+  dnode_t *dnode, *dnode_next;
+  int level;
+
+  assert (circuit);
+  area = circuit->area;
+  assert (area);
+  for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++)
+    {
+      if (level & circuit->is_type)
+        {
+          if (area->lspdb[level - 1] &&
+              dict_count (area->lspdb[level - 1]) > 0)
+            {
+              for (dnode = dict_first (area->lspdb[level - 1]);
+                   dnode != NULL; dnode = dnode_next)
+                {
+                  dnode_next = dict_next (area->lspdb[level - 1], dnode);
+                  lsp = dnode_get (dnode);
+                  if (is_set)
+                    {
+                      ISIS_SET_FLAG (lsp->SRMflags, circuit);
+                    }
+                  else
+                    {
+                      ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+                    }
+                }
+            }
+        }
+    }
 }
 
-void
+int
 isis_circuit_up (struct isis_circuit *circuit)
 {
+  int retv;
+
+  /* Set the flags for all the lsps of the circuit. */
+  isis_circuit_update_all_srmflags (circuit, 1);
+
+  if (circuit->state == C_STATE_UP)
+    return ISIS_OK;
+
+  if (circuit->is_passive)
+    return ISIS_OK;
 
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     {
+      /*
+       * Get the Hardware Address
+       */
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+#ifndef SUNOS_5
+      if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
+        zlog_warn ("unsupported link layer");
+      else
+        memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl),
+                ETH_ALEN);
+#endif
+#else
+      if (circuit->interface->hw_addr_len != ETH_ALEN)
+        {
+          zlog_warn ("unsupported link layer");
+        }
+      else
+        {
+          memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
+        }
+#ifdef EXTREME_DEGUG
+      zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
+                  circuit->interface->ifindex, ISO_MTU (circuit),
+                  snpa_print (circuit->u.bc.snpa));
+#endif /* EXTREME_DEBUG */
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
+
+      circuit->u.bc.adjdb[0] = list_new ();
+      circuit->u.bc.adjdb[1] = list_new ();
+
       if (circuit->area->min_bcast_mtu == 0 ||
-         ISO_MTU (circuit) < circuit->area->min_bcast_mtu)
-       circuit->area->min_bcast_mtu = ISO_MTU (circuit);
+          ISO_MTU (circuit) < circuit->area->min_bcast_mtu)
+        circuit->area->min_bcast_mtu = ISO_MTU (circuit);
       /*
        * ISO 10589 - 8.4.1 Enabling of broadcast circuits
        */
@@ -524,98 +633,183 @@ isis_circuit_up (struct isis_circuit *circuit)
 
       /* 8.4.1 a) commence sending of IIH PDUs */
 
-      if (circuit->circuit_is_type & IS_LEVEL_1)
-       {
-         thread_add_event (master, send_lan_l1_hello, circuit, 0);
-         circuit->u.bc.lan_neighs[0] = list_new ();
-       }
+      if (circuit->is_type & IS_LEVEL_1)
+        {
+          thread_add_event (master, send_lan_l1_hello, circuit, 0);
+          circuit->u.bc.lan_neighs[0] = list_new ();
+        }
 
-      if (circuit->circuit_is_type & IS_LEVEL_2)
-       {
-         thread_add_event (master, send_lan_l2_hello, circuit, 0);
-         circuit->u.bc.lan_neighs[1] = list_new ();
-       }
+      if (circuit->is_type & IS_LEVEL_2)
+        {
+          thread_add_event (master, send_lan_l2_hello, circuit, 0);
+          circuit->u.bc.lan_neighs[1] = list_new ();
+        }
 
       /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
       /* 8.4.1 c) FIXME: listen for ESH PDUs */
 
       /* 8.4.1 d) */
       /* dr election will commence in... */
-      if (circuit->circuit_is_type & IS_LEVEL_1)
-       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
-                        circuit, 2 * circuit->hello_interval[0]);
-      if (circuit->circuit_is_type & IS_LEVEL_2)
-       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
-                        circuit, 2 * circuit->hello_interval[1]);
+      if (circuit->is_type & IS_LEVEL_1)
+        THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
+            circuit, 2 * circuit->hello_interval[0]);
+      if (circuit->is_type & IS_LEVEL_2)
+        THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
+            circuit, 2 * circuit->hello_interval[1]);
     }
   else
     {
       /* initializing the hello send threads
        * for a ptp IF
        */
+      circuit->u.p2p.neighbor = NULL;
       thread_add_event (master, send_p2p_hello, circuit, 0);
-
     }
 
   /* initializing PSNP timers */
-  if (circuit->circuit_is_type & IS_LEVEL_1)
-    {
-      THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
-                      isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
-    }
+  if (circuit->is_type & IS_LEVEL_1)
+    THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
+                     isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
+
+  if (circuit->is_type & IS_LEVEL_2)
+    THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
+                     isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
 
-  if (circuit->circuit_is_type & IS_LEVEL_2)
+  /* unified init for circuits; ignore warnings below this level */
+  retv = isis_sock_init (circuit);
+  if (retv != ISIS_OK)
     {
-      THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
-                      isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
+      isis_circuit_down (circuit);
+      return retv;
     }
 
-  /* initialize the circuit streams */
+  /* initialize the circuit streams after opening connection */
   if (circuit->rcv_stream == NULL)
     circuit->rcv_stream = stream_new (ISO_MTU (circuit));
 
   if (circuit->snd_stream == NULL)
     circuit->snd_stream = stream_new (ISO_MTU (circuit));
 
-  /* unified init for circuits */
-  isis_sock_init (circuit);
-
 #ifdef GNU_LINUX
   THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
-                 circuit->fd);
+                  circuit->fd);
 #else
   THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit,
-                  circuit->fd);
+                   circuit->fd);
 #endif
-  return;
+
+  circuit->lsp_queue = list_new ();
+  circuit->lsp_queue_last_cleared = time (NULL);
+
+  return ISIS_OK;
 }
 
 void
 isis_circuit_down (struct isis_circuit *circuit)
 {
-  /* Cancel all active threads -- FIXME: wrong place */
-  /* HT: Read thread if GNU_LINUX, TIMER thread otherwise. */
-  THREAD_OFF (circuit->t_read);
+  if (circuit->state != C_STATE_UP)
+    return;
+
+  /* Clear the flags for all the lsps of the circuit. */
+  isis_circuit_update_all_srmflags (circuit, 0);
+
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     {
+      /* destroy neighbour lists */
+      if (circuit->u.bc.lan_neighs[0])
+        {
+          list_delete (circuit->u.bc.lan_neighs[0]);
+          circuit->u.bc.lan_neighs[0] = NULL;
+        }
+      if (circuit->u.bc.lan_neighs[1])
+        {
+          list_delete (circuit->u.bc.lan_neighs[1]);
+          circuit->u.bc.lan_neighs[1] = NULL;
+        }
+      /* destroy adjacency databases */
+      if (circuit->u.bc.adjdb[0])
+        {
+          circuit->u.bc.adjdb[0]->del = isis_delete_adj;
+          list_delete (circuit->u.bc.adjdb[0]);
+          circuit->u.bc.adjdb[0] = NULL;
+        }
+      if (circuit->u.bc.adjdb[1])
+        {
+          circuit->u.bc.adjdb[1]->del = isis_delete_adj;
+          list_delete (circuit->u.bc.adjdb[1]);
+          circuit->u.bc.adjdb[1] = NULL;
+        }
+      if (circuit->u.bc.is_dr[0])
+        {
+          isis_dr_resign (circuit, 1);
+          circuit->u.bc.is_dr[0] = 0;
+        }
+      memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
+      if (circuit->u.bc.is_dr[1])
+        {
+          isis_dr_resign (circuit, 2);
+          circuit->u.bc.is_dr[1] = 0;
+        }
+      memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
+      memset (circuit->u.bc.snpa, 0, ETH_ALEN);
+
       THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]);
       THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]);
       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
+      THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
+      THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
     }
   else if (circuit->circ_type == CIRCUIT_T_P2P)
     {
+      isis_delete_adj (circuit->u.p2p.neighbor);
+      circuit->u.p2p.neighbor = NULL;
       THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
     }
 
-  if (circuit->t_send_psnp[0]) {
-    THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
-  }
-  if (circuit->t_send_psnp[1]) {
-    THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
-  }
+  /* Cancel all active threads */
+  THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
+  THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
+  THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
+  THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
+  THREAD_OFF (circuit->t_read);
+
+  if (circuit->lsp_queue)
+    {
+      circuit->lsp_queue->del = NULL;
+      list_delete (circuit->lsp_queue);
+      circuit->lsp_queue = NULL;
+    }
+
+  /* send one gratuitous hello to spead up convergence */
+  if (circuit->is_type & IS_LEVEL_1)
+    send_hello (circuit, IS_LEVEL_1);
+  if (circuit->is_type & IS_LEVEL_2)
+    send_hello (circuit, IS_LEVEL_2);
+
+  circuit->upadjcount[0] = 0;
+  circuit->upadjcount[1] = 0;
+
   /* close the socket */
-  close (circuit->fd);
+  if (circuit->fd)
+    {
+      close (circuit->fd);
+      circuit->fd = 0;
+    }
+
+  if (circuit->rcv_stream != NULL)
+    {
+      stream_free (circuit->rcv_stream);
+      circuit->rcv_stream = NULL;
+    }
+
+  if (circuit->snd_stream != NULL)
+    {
+      stream_free (circuit->snd_stream);
+      circuit->snd_stream = NULL;
+    }
+
+  thread_cancel_event (master, circuit);
 
   return;
 }
@@ -640,216 +834,346 @@ circuit_update_nlpids (struct isis_circuit *circuit)
   return;
 }
 
+void
+isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
+                        char detail)
+{
+  if (detail == ISIS_UI_LEVEL_BRIEF)
+    {
+      vty_out (vty, "  %-12s", circuit->interface->name);
+      vty_out (vty, "0x%-7x", circuit->circuit_id);
+      vty_out (vty, "%-9s", circuit_state2string (circuit->state));
+      vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type));
+      vty_out (vty, "%-9s", circuit_t2string (circuit->is_type));
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  if (detail == ISIS_UI_LEVEL_DETAIL)
+    {
+      vty_out (vty, "  Interface: %s", circuit->interface->name);
+      vty_out (vty, ", State: %s", circuit_state2string (circuit->state));
+      if (circuit->is_passive)
+        vty_out (vty, ", Passive");
+      else
+        vty_out (vty, ", Active");
+      vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "    Type: %s", circuit_type2string (circuit->circ_type));
+      vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type));
+      if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+        vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa));
+      vty_out (vty, "%s", VTY_NEWLINE);
+      if (circuit->is_type & IS_LEVEL_1)
+        {
+          vty_out (vty, "    Level-1 Information:%s", VTY_NEWLINE);
+          if (circuit->area->newmetric)
+            vty_out (vty, "      Metric: %d", circuit->te_metric[0]);
+          else
+            vty_out (vty, "      Metric: %d",
+                     circuit->metrics[0].metric_default);
+          if (!circuit->is_passive)
+            {
+              vty_out (vty, ", Active neighbors: %u%s",
+                       circuit->upadjcount[0], VTY_NEWLINE);
+              vty_out (vty, "      Hello interval: %u, "
+                            "Holddown count: %u %s%s",
+                       circuit->hello_interval[0],
+                       circuit->hello_multiplier[0],
+                       (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
+                       VTY_NEWLINE);
+              vty_out (vty, "      CNSP interval: %u, "
+                            "PSNP interval: %u%s",
+                       circuit->csnp_interval[0],
+                       circuit->psnp_interval[0], VTY_NEWLINE);
+              if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+                vty_out (vty, "      LAN Priority: %u, %s%s",
+                         circuit->priority[0],
+                         (circuit->u.bc.is_dr[0] ? \
+                          "is DIS" : "is not DIS"), VTY_NEWLINE);
+            }
+          else
+            {
+              vty_out (vty, "%s", VTY_NEWLINE);
+            }
+        }
+      if (circuit->is_type & IS_LEVEL_2)
+        {
+          vty_out (vty, "    Level-2 Information:%s", VTY_NEWLINE);
+          if (circuit->area->newmetric)
+            vty_out (vty, "      Metric: %d", circuit->te_metric[1]);
+          else
+            vty_out (vty, "      Metric: %d",
+                     circuit->metrics[1].metric_default);
+          if (!circuit->is_passive)
+            {
+              vty_out (vty, ", Active neighbors: %u%s",
+                       circuit->upadjcount[1], VTY_NEWLINE);
+              vty_out (vty, "      Hello interval: %u, "
+                            "Holddown count: %u %s%s",
+                       circuit->hello_interval[1],
+                       circuit->hello_multiplier[1],
+                       (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
+                       VTY_NEWLINE);
+              vty_out (vty, "      CNSP interval: %u, "
+                            "PSNP interval: %u%s",
+                       circuit->csnp_interval[1],
+                       circuit->psnp_interval[1], VTY_NEWLINE);
+              if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+                vty_out (vty, "      LAN Priority: %u, %s%s",
+                         circuit->priority[1],
+                         (circuit->u.bc.is_dr[1] ? \
+                          "is DIS" : "is not DIS"), VTY_NEWLINE);
+            }
+          else
+            {
+              vty_out (vty, "%s", VTY_NEWLINE);
+            }
+        }
+      if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0)
+        {
+          struct listnode *node;
+          struct prefix *ip_addr;
+          u_char buf[BUFSIZ];
+          vty_out (vty, "    IP Prefix(es):%s", VTY_NEWLINE);
+          for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr))
+            {
+              prefix2str (ip_addr, (char*)buf, BUFSIZ),
+              vty_out (vty, "      %s%s", buf, VTY_NEWLINE);
+            }
+        }
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  return;
+}
+
 int
 isis_interface_config_write (struct vty *vty)
 {
-
   int write = 0;
   struct listnode *node, *node2;
   struct interface *ifp;
   struct isis_area *area;
-  struct isis_circuit *c;
+  struct isis_circuit *circuit;
   int i;
 
   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
-  {
-    /* IF name */
-    vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
-    write++;
-    /* IF desc */
-    if (ifp->desc)
-      {
-       vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
-       write++;
-      }
-    /* ISIS Circuit */
-    for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
     {
-      c = circuit_lookup_by_ifp (ifp, area->circuit_list);
-      if (c)
-       {
-         if (c->ip_router)
-           {
-             vty_out (vty, " ip router isis %s%s", area->area_tag,
-                      VTY_NEWLINE);
-             write++;
-           }
+      /* IF name */
+      vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
+      write++;
+      /* IF desc */
+      if (ifp->desc)
+        {
+          vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
+          write++;
+        }
+      /* ISIS Circuit */
+      for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
+        {
+          circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+          if (circuit == NULL)
+            continue;
+          if (circuit->ip_router)
+            {
+              vty_out (vty, " ip router isis %s%s", area->area_tag,
+                       VTY_NEWLINE);
+              write++;
+            }
+          if (circuit->is_passive)
+            {
+              vty_out (vty, " isis passive%s", VTY_NEWLINE);
+              write++;
+            }
+          if (circuit->circ_type_config == CIRCUIT_T_P2P)
+            {
+              vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE);
+              write++;
+            }
 #ifdef HAVE_IPV6
-         if (c->ipv6_router)
-           {
-             vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
-                      VTY_NEWLINE);
-             write++;
-           }
+          if (circuit->ipv6_router)
+            {
+              vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
+                  VTY_NEWLINE);
+              write++;
+            }
 #endif /* HAVE_IPV6 */
 
-         /* ISIS - circuit type */
-         if (c->circuit_is_type == IS_LEVEL_1)
-           {
-             vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
-             write++;
-           }
-         else
-           {
-             if (c->circuit_is_type == IS_LEVEL_2)
-               {
-                 vty_out (vty, " isis circuit-type level-2-only%s",
-                          VTY_NEWLINE);
-                 write++;
-               }
-           }
-
-         /* ISIS - CSNP interval - FIXME: compare to cisco */
-         if (c->csnp_interval[0] == c->csnp_interval[1])
-           {
-             if (c->csnp_interval[0] != CSNP_INTERVAL)
-               {
-                 vty_out (vty, " isis csnp-interval %d%s",
-                          c->csnp_interval[0], VTY_NEWLINE);
-                 write++;
-               }
-           }
-         else
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 if (c->csnp_interval[1] != CSNP_INTERVAL)
-                   {
-                     vty_out (vty, " isis csnp-interval %d level-%d%s",
-                              c->csnp_interval[1], i + 1, VTY_NEWLINE);
-                     write++;
-                   }
-               }
-           }
-
-         /* ISIS - Hello padding - Defaults to true so only display if false */
-         if (c->circ_type == CIRCUIT_T_BROADCAST && !c->u.bc.pad_hellos)
-           {
-             vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
-             write++;
-           }
-
-         /* ISIS - Hello interval - FIXME: compare to cisco */
-         if (c->hello_interval[0] == c->hello_interval[1])
-           {
-             if (c->hello_interval[0] != HELLO_INTERVAL)
-               {
-                 vty_out (vty, " isis hello-interval %d%s",
-                          c->hello_interval[0], VTY_NEWLINE);
-                 write++;
-               }
-           }
-         else
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 if (c->hello_interval[i] != HELLO_INTERVAL)
-                   {
-                     if (c->hello_interval[i] == HELLO_MINIMAL)
-                       {
-                         vty_out (vty,
-                                  " isis hello-interval minimal level-%d%s",
-                                  i + 1, VTY_NEWLINE);
-                       }
-                     else
-                       {
-                         vty_out (vty, " isis hello-interval %d level-%d%s",
-                                  c->hello_interval[i], i + 1, VTY_NEWLINE);
-                       }
-                     write++;
-                   }
-               }
-           }
-
-         /* ISIS - Hello Multiplier */
-         if (c->hello_multiplier[0] == c->hello_multiplier[1])
-           {
-             if (c->hello_multiplier[0] != HELLO_MULTIPLIER)
-               {
-                 vty_out (vty, " isis hello-multiplier %d%s",
-                          c->hello_multiplier[0], VTY_NEWLINE);
-                 write++;
-               }
-           }
-         else
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 if (c->hello_multiplier[i] != HELLO_MULTIPLIER)
-                   {
-                     vty_out (vty, " isis hello-multiplier %d level-%d%s",
-                              c->hello_multiplier[i], i + 1, VTY_NEWLINE);
-                     write++;
-                   }
-               }
-           }
-         /* ISIS - Priority */
-         if (c->circ_type == CIRCUIT_T_BROADCAST)
-           {
-             if (c->u.bc.priority[0] == c->u.bc.priority[1])
-               {
-                 if (c->u.bc.priority[0] != DEFAULT_PRIORITY)
-                   {
-                     vty_out (vty, " isis priority %d%s",
-                              c->u.bc.priority[0], VTY_NEWLINE);
-                     write++;
-                   }
-               }
-             else
-               {
-                 for (i = 0; i < 2; i++)
-                   {
-                     if (c->u.bc.priority[i] != DEFAULT_PRIORITY)
-                       {
-                         vty_out (vty, " isis priority %d level-%d%s",
-                                  c->u.bc.priority[i], i + 1, VTY_NEWLINE);
-                         write++;
-                       }
-                   }
-               }
-           }
-         /* ISIS - Metric */
-         if (c->te_metric[0] == c->te_metric[1])
-           {
-             if (c->te_metric[0] != DEFAULT_CIRCUIT_METRICS)
-               {
-                 vty_out (vty, " isis metric %d%s", c->te_metric[0],
-                          VTY_NEWLINE);
-                 write++;
-               }
-           }
-         else
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 if (c->te_metric[i] != DEFAULT_CIRCUIT_METRICS)
-                   {
-                     vty_out (vty, " isis metric %d level-%d%s",
-                              c->te_metric[i], i + 1, VTY_NEWLINE);
-                     write++;
-                   }
-               }
-           }
-         if (c->passwd.type==ISIS_PASSWD_TYPE_HMAC_MD5)
-           {
-             vty_out (vty, " isis password md5 %s%s", c->passwd.passwd,
-                      VTY_NEWLINE);
-             write++;
-           }
-         else
-           {
-             if (c->passwd.type==ISIS_PASSWD_TYPE_CLEARTXT)
-               {
-                 vty_out (vty, " isis password clear %s%s", c->passwd.passwd,
-                          VTY_NEWLINE);
-                 write++;
-               }
-           }
-
-       }
+          /* ISIS - circuit type */
+          if (circuit->is_type == IS_LEVEL_1)
+            {
+              vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
+              write++;
+            }
+          else
+            {
+              if (circuit->is_type == IS_LEVEL_2)
+                {
+                  vty_out (vty, " isis circuit-type level-2-only%s",
+                           VTY_NEWLINE);
+                  write++;
+                }
+            }
+
+          /* ISIS - CSNP interval */
+          if (circuit->csnp_interval[0] == circuit->csnp_interval[1])
+            {
+              if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL)
+                {
+                  vty_out (vty, " isis csnp-interval %d%s",
+                           circuit->csnp_interval[0], VTY_NEWLINE);
+                  write++;
+                }
+            }
+          else
+          {
+            for (i = 0; i < 2; i++)
+              {
+                if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL)
+                  {
+                    vty_out (vty, " isis csnp-interval %d level-%d%s",
+                             circuit->csnp_interval[i], i + 1, VTY_NEWLINE);
+                    write++;
+                  }
+              }
+          }
+
+          /* ISIS - PSNP interval */
+          if (circuit->psnp_interval[0] == circuit->psnp_interval[1])
+            {
+              if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL)
+                {
+                  vty_out (vty, " isis psnp-interval %d%s",
+                           circuit->psnp_interval[0], VTY_NEWLINE);
+                  write++;
+                }
+            }
+          else
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL)
+                  {
+                    vty_out (vty, " isis psnp-interval %d level-%d%s",
+                             circuit->psnp_interval[i], i + 1, VTY_NEWLINE);
+                    write++;
+                  }
+                }
+            }
+
+          /* ISIS - Hello padding - Defaults to true so only display if false */
+          if (circuit->pad_hellos == 0)
+            {
+              vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
+              write++;
+            }
+
+          /* ISIS - Hello interval */
+          if (circuit->hello_interval[0] == circuit->hello_interval[1])
+            {
+              if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL)
+                {
+                  vty_out (vty, " isis hello-interval %d%s",
+                           circuit->hello_interval[0], VTY_NEWLINE);
+                  write++;
+                }
+            }
+          else
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL)
+                    {
+                      vty_out (vty, " isis hello-interval %d level-%d%s",
+                               circuit->hello_interval[i], i + 1, VTY_NEWLINE);
+                      write++;
+                    }
+                }
+            }
+
+          /* ISIS - Hello Multiplier */
+          if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1])
+            {
+              if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER)
+                {
+                  vty_out (vty, " isis hello-multiplier %d%s",
+                           circuit->hello_multiplier[0], VTY_NEWLINE);
+                  write++;
+                }
+            }
+          else
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER)
+                    {
+                      vty_out (vty, " isis hello-multiplier %d level-%d%s",
+                               circuit->hello_multiplier[i], i + 1,
+                               VTY_NEWLINE);
+                      write++;
+                    }
+                }
+            }
+
+          /* ISIS - Priority */
+          if (circuit->priority[0] == circuit->priority[1])
+            {
+              if (circuit->priority[0] != DEFAULT_PRIORITY)
+                {
+                  vty_out (vty, " isis priority %d%s",
+                           circuit->priority[0], VTY_NEWLINE);
+                  write++;
+                }
+            }
+          else
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  if (circuit->priority[i] != DEFAULT_PRIORITY)
+                    {
+                      vty_out (vty, " isis priority %d level-%d%s",
+                               circuit->priority[i], i + 1, VTY_NEWLINE);
+                      write++;
+                    }
+                }
+            }
+
+          /* ISIS - Metric */
+          if (circuit->te_metric[0] == circuit->te_metric[1])
+            {
+              if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC)
+                {
+                  vty_out (vty, " isis metric %d%s", circuit->te_metric[0],
+                           VTY_NEWLINE);
+                  write++;
+                }
+            }
+          else
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC)
+                    {
+                      vty_out (vty, " isis metric %d level-%d%s",
+                               circuit->te_metric[i], i + 1, VTY_NEWLINE);
+                      write++;
+                    }
+                }
+            }
+          if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
+            {
+              vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd,
+                       VTY_NEWLINE);
+              write++;
+            }
+          else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+            {
+              vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd,
+                       VTY_NEWLINE);
+              write++;
+            }
+        }
+      vty_out (vty, "!%s", VTY_NEWLINE);
     }
-    vty_out (vty, "!%s", VTY_NEWLINE);
-  }
 
   return write;
 }
@@ -862,58 +1186,45 @@ DEFUN (ip_router_isis,
        "IS-IS Routing for IP\n"
        "Routing process tag\n")
 {
-  struct isis_circuit *c;
+  struct isis_circuit *circuit;
   struct interface *ifp;
   struct isis_area *area;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
 
-  area = isis_area_lookup (argv[0]);
-
-  /* Prevent more than one circuit per interface */
-  if (area)
-    c = circuit_lookup_by_ifp (ifp, area->circuit_list);
-  else
-    c = NULL;
-  if (c && (ifp->info != NULL))
-    {
-#ifdef HAVE_IPV6
-      if (c->ipv6_router == 0)
-       {
-#endif /* HAVE_IPV6 */
-         /* FIXME: Find the way to warn only vty users. */
-         /* vty_out (vty, "ISIS circuit is already defined%s", VTY_NEWLINE); */
-         return CMD_WARNING;
-#ifdef HAVE_IPV6
-       }
-#endif /* HAVE_IPV6 */
-    }
-
-  /* this is here for ciscopability */
-  if (!area)
+  /* Prevent more than one area per circuit */
+  circuit = circuit_scan_by_ifp (ifp);
+  if (circuit)
     {
-      /* FIXME: Find the way to warn only vty users. */
-      /* vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); */
-      return CMD_WARNING;
+      if (circuit->ip_router == 1)
+        {
+          if (strcmp (circuit->area->area_tag, argv[0]))
+            {
+              vty_out (vty, "ISIS circuit is already defined on %s%s",
+                       circuit->area->area_tag, VTY_NEWLINE);
+              return CMD_ERR_NOTHING_TODO;
+            }
+          return CMD_SUCCESS;
+        }
     }
 
-  if (!c)
+  if (isis_area_get (vty, argv[0]) != CMD_SUCCESS)
     {
-      c = circuit_lookup_by_ifp (ifp, isis->init_circ_list);
-      c = isis_csm_state_change (ISIS_ENABLE, c, area);
-      c->interface = ifp;      /* this is automatic */
-      ifp->info = c;           /* hardly related to the FSM */
+      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
+  area = vty->index;
 
-  if (!c)
-    return CMD_WARNING;
+  circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
+  isis_circuit_if_bind (circuit, ifp);
 
-  c->ip_router = 1;
+  circuit->ip_router = 1;
   area->ip_circuits++;
-  circuit_update_nlpids (c);
+  circuit_update_nlpids (circuit);
 
   vty->node = INTERFACE_NODE;
+  vty->index = ifp;
 
   return CMD_SUCCESS;
 }
@@ -927,28 +1238,33 @@ DEFUN (no_ip_router_isis,
        "IS-IS Routing for IP\n"
        "Routing process tag\n")
 {
-  struct isis_circuit *circuit = NULL;
   struct interface *ifp;
   struct isis_area *area;
-  struct listnode *node;
+  struct isis_circuit *circuit;
 
   ifp = (struct interface *) vty->index;
-  assert (ifp);
+  if (!ifp)
+    {
+      vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
 
   area = isis_area_lookup (argv[0]);
   if (!area)
     {
-      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Can't find ISIS instance %s%s",
+               argv[0], VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
-  for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
-    if (circuit->interface == ifp)
-      break;
+
+  circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
   if (!circuit)
     {
-      vty_out (vty, "Can't find ISIS interface %s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "ISIS is not enabled on circuit %s%s",
+               ifp->name, VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
+
   circuit->ip_router = 0;
   area->ip_circuits--;
 #ifdef HAVE_IPV6
@@ -959,80 +1275,240 @@ DEFUN (no_ip_router_isis,
   return CMD_SUCCESS;
 }
 
-DEFUN (isis_circuit_type,
-       isis_circuit_type_cmd,
-       "isis circuit-type (level-1|level-1-2|level-2-only)",
-       "IS-IS commands\n"
-       "Configure circuit type for interface\n"
-       "Level-1 only adjacencies are formed\n"
-       "Level-1-2 adjacencies are formed\n"
-       "Level-2 only adjacencies are formed\n")
+#ifdef HAVE_IPV6
+DEFUN (ipv6_router_isis,
+       ipv6_router_isis_cmd,
+       "ipv6 router isis WORD",
+       "IPv6 interface subcommands\n"
+       "IPv6 Router interface commands\n"
+       "IS-IS Routing for IPv6\n"
+       "Routing process tag\n")
 {
   struct isis_circuit *circuit;
   struct interface *ifp;
-  int circuit_t;
-  int is_type;
+  struct isis_area *area;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  /* UGLY - will remove l8r */
-  if (circuit == NULL)
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+
+  /* Prevent more than one area per circuit */
+  circuit = circuit_scan_by_ifp (ifp);
+  if (circuit)
+    {
+      if (circuit->ipv6_router == 1)
+      {
+        if (strcmp (circuit->area->area_tag, argv[0]))
+          {
+            vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s",
+                     circuit->area->area_tag, VTY_NEWLINE);
+            return CMD_ERR_NOTHING_TODO;
+          }
+        return CMD_SUCCESS;
+      }
+    }
+
+  if (isis_area_get (vty, argv[0]) != CMD_SUCCESS)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
+  area = vty->index;
 
-  /* XXX what to do when ip_router_isis is not executed */
-  if (circuit->area == NULL)
-    return CMD_WARNING;
+  circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
+  isis_circuit_if_bind (circuit, ifp);
 
-  assert (circuit);
+  circuit->ipv6_router = 1;
+  area->ipv6_circuits++;
+  circuit_update_nlpids (circuit);
+
+  vty->node = INTERFACE_NODE;
+  vty->index = ifp;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_router_isis,
+       no_ipv6_router_isis_cmd,
+       "no ipv6 router isis WORD",
+       NO_STR
+       "IPv6 interface subcommands\n"
+       "IPv6 Router interface commands\n"
+       "IS-IS Routing for IPv6\n"
+       "Routing process tag\n")
+{
+  struct interface *ifp;
+  struct isis_area *area;
+  struct listnode *node;
+  struct isis_circuit *circuit;
 
-  circuit_t = string2circuit_t (argv[0]);
+  ifp = (struct interface *) vty->index;
+  if (!ifp)
+    {
+      vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
 
-  if (!circuit_t)
+  area = isis_area_lookup (argv[0]);
+  if (!area)
     {
-      vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE);
-      return CMD_SUCCESS;
+      vty_out (vty, "Can't find ISIS instance %s%s",
+               argv[0], VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
 
-  is_type = circuit->area->is_type;
-  if (is_type == IS_LEVEL_1_AND_2 || is_type == circuit_t)
-    isis_event_circuit_type_change (circuit, circuit_t);
+  circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+  if (!circuit)
+    {
+      vty_out (vty, "ISIS is not enabled on circuit %s%s",
+               ifp->name, VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  circuit->ipv6_router = 0;
+  area->ipv6_circuits--;
+  if (circuit->ip_router == 0)
+    isis_csm_state_change (ISIS_DISABLE, circuit, area);
+
+  return CMD_SUCCESS;
+}
+#endif /* HAVE_IPV6 */
+
+DEFUN (isis_passive,
+       isis_passive_cmd,
+       "isis passive",
+       "IS-IS commands\n"
+       "Configure the passive mode for interface\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  if (circuit->is_passive == 1)
+    return CMD_SUCCESS;
+
+  if (circuit->state != C_STATE_UP)
+    {
+      circuit->is_passive = 1;
+    }
   else
     {
-      vty_out (vty, "invalid circuit level for area %s.%s",
-              circuit->area->area_tag, VTY_NEWLINE);
+      struct isis_area *area = circuit->area;
+      isis_csm_state_change (ISIS_DISABLE, circuit, area);
+      circuit->is_passive = 1;
+      isis_csm_state_change (ISIS_ENABLE, circuit, area);
     }
 
   return CMD_SUCCESS;
 }
 
-DEFUN (no_isis_circuit_type,
-       no_isis_circuit_type_cmd,
-       "no isis circuit-type (level-1|level-1-2|level-2-only)",
+DEFUN (no_isis_passive,
+       no_isis_passive_cmd,
+       "no isis passive",
        NO_STR
        "IS-IS commands\n"
+       "Configure the passive mode for interface\n")
+{
+  struct interface *ifp;
+  struct isis_circuit *circuit;
+
+  ifp = (struct interface *) vty->index;
+  if (!ifp)
+    {
+      vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  /* FIXME: what is wrong with circuit = ifp->info ? */
+  circuit = circuit_scan_by_ifp (ifp);
+  if (!circuit)
+    {
+      vty_out (vty, "ISIS is not enabled on circuit %s%s",
+               ifp->name, VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  if (if_is_loopback(ifp))
+    {
+      vty_out (vty, "Can't set no passive for loopback interface%s",
+               VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (circuit->is_passive == 0)
+    return CMD_SUCCESS;
+
+  if (circuit->state != C_STATE_UP)
+    {
+      circuit->is_passive = 0;
+    }
+  else
+    {
+      struct isis_area *area = circuit->area;
+      isis_csm_state_change (ISIS_DISABLE, circuit, area);
+      circuit->is_passive = 0;
+      isis_csm_state_change (ISIS_ENABLE, circuit, area);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (isis_circuit_type,
+       isis_circuit_type_cmd,
+       "isis circuit-type (level-1|level-1-2|level-2-only)",
+       "IS-IS commands\n"
        "Configure circuit type for interface\n"
        "Level-1 only adjacencies are formed\n"
        "Level-1-2 adjacencies are formed\n"
        "Level-2 only adjacencies are formed\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
+  int circuit_type;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  circuit_type = string2circuit_t (argv[0]);
+  if (!circuit_type)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
 
-  assert (circuit);
+  if (circuit->state == C_STATE_UP &&
+      circuit->area->is_type != IS_LEVEL_1_AND_2 &&
+      circuit->area->is_type != circuit_type)
+    {
+      vty_out (vty, "Invalid circuit level for area %s.%s",
+               circuit->area->area_tag, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+  isis_event_circuit_type_change (circuit, circuit_type);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_circuit_type,
+       no_isis_circuit_type_cmd,
+       "no isis circuit-type (level-1|level-1-2|level-2-only)",
+       NO_STR
+       "IS-IS commands\n"
+       "Configure circuit type for interface\n"
+       "Level-1 only adjacencies are formed\n"
+       "Level-1-2 adjacencies are formed\n"
+       "Level-2 only adjacencies are formed\n")
+{
+  int circuit_type;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
   /*
-   * Set the circuits level to its default value which is that of the area
+   * Set the circuits level to its default value
    */
-  isis_event_circuit_type_change (circuit, circuit->area->is_type);
+  if (circuit->state == C_STATE_UP)
+    circuit_type = circuit->area->is_type;
+  else
+    circuit_type = IS_LEVEL_1_AND_2;
+  isis_event_circuit_type_change (circuit, circuit_type);
 
   return CMD_SUCCESS;
 }
@@ -1041,26 +1517,20 @@ DEFUN (isis_passwd_md5,
        isis_passwd_md5_cmd,
        "isis password md5 WORD",
        "IS-IS commands\n"
-       "Configure the authentication password for interface\n"
-       "Authentication Type\n"
-       "Password\n")
+       "Configure the authentication password for a circuit\n"
+       "Authentication type\n"
+       "Circuit password\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int len;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
   len = strlen (argv[0]);
   if (len > 254)
     {
       vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_AMBIGUOUS;
     }
   circuit->passwd.len = len;
   circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
@@ -1073,26 +1543,20 @@ DEFUN (isis_passwd_clear,
        isis_passwd_clear_cmd,
        "isis password clear WORD",
        "IS-IS commands\n"
-       "Configure the authentication password for interface\n"
-       "Authentication Type\n"
-       "Password\n")
+       "Configure the authentication password for a circuit\n"
+       "Authentication type\n"
+       "Circuit password\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int len;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
   len = strlen (argv[0]);
   if (len > 254)
     {
       vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_AMBIGUOUS;
     }
   circuit->passwd.len = len;
   circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
@@ -1106,17 +1570,11 @@ DEFUN (no_isis_passwd,
        "no isis password",
        NO_STR
        "IS-IS commands\n"
-       "Configure the authentication password for interface\n")
+       "Configure the authentication password for a circuit\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
   memset (&circuit->passwd, 0, sizeof (struct isis_passwd));
 
@@ -1130,22 +1588,21 @@ DEFUN (isis_priority,
        "Set priority for Designated Router election\n"
        "Priority value\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int prio;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  prio = atoi (argv[0]);
+  if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid priority %d - should be <0-127>%s",
+               prio, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
 
-  prio = atoi (argv[0]);
-
-  circuit->u.bc.priority[0] = prio;
-  circuit->u.bc.priority[1] = prio;
+  circuit->priority[0] = prio;
+  circuit->priority[1] = prio;
 
   return CMD_SUCCESS;
 }
@@ -1157,19 +1614,12 @@ DEFUN (no_isis_priority,
        "IS-IS commands\n"
        "Set priority for Designated Router election\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->u.bc.priority[0] = DEFAULT_PRIORITY;
-  circuit->u.bc.priority[1] = DEFAULT_PRIORITY;
+  circuit->priority[0] = DEFAULT_PRIORITY;
+  circuit->priority[1] = DEFAULT_PRIORITY;
 
   return CMD_SUCCESS;
 }
@@ -1190,21 +1640,20 @@ DEFUN (isis_priority_l1,
        "Priority value\n"
        "Specify priority for level-1 routing\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int prio;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  prio = atoi (argv[0]);
+  if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid priority %d - should be <0-127>%s",
+               prio, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
 
-  prio = atoi (argv[0]);
-
-  circuit->u.bc.priority[0] = prio;
+  circuit->priority[0] = prio;
 
   return CMD_SUCCESS;
 }
@@ -1217,18 +1666,11 @@ DEFUN (no_isis_priority_l1,
        "Set priority for Designated Router election\n"
        "Specify priority for level-1 routing\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->u.bc.priority[0] = DEFAULT_PRIORITY;
+  circuit->priority[0] = DEFAULT_PRIORITY;
 
   return CMD_SUCCESS;
 }
@@ -1250,21 +1692,20 @@ DEFUN (isis_priority_l2,
        "Priority value\n"
        "Specify priority for level-2 routing\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int prio;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  prio = atoi (argv[0]);
+  if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid priority %d - should be <0-127>%s",
+               prio, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  prio = atoi (argv[0]);
 
-  circuit->u.bc.priority[1] = prio;
+  circuit->priority[1] = prio;
 
   return CMD_SUCCESS;
 }
@@ -1277,18 +1718,11 @@ DEFUN (no_isis_priority_l2,
        "Set priority for Designated Router election\n"
        "Specify priority for level-2 routing\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->u.bc.priority[1] = DEFAULT_PRIORITY;
+  circuit->priority[1] = DEFAULT_PRIORITY;
 
   return CMD_SUCCESS;
 }
@@ -1303,36 +1737,49 @@ ALIAS (no_isis_priority_l2,
        "Specify priority for level-2 routing\n")
 
 /* Metric command */
-  DEFUN (isis_metric,
+DEFUN (isis_metric,
        isis_metric_cmd,
        "isis metric <0-16777215>",
        "IS-IS commands\n"
        "Set default metric for circuit\n"
        "Default metric value\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int met;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  met = atoi (argv[0]);
+
+  /* RFC3787 section 5.1 */
+  if (circuit->area && circuit->area->oldmetric == 1 &&
+      met > MAX_NARROW_LINK_METRIC)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid metric %d - should be <0-63> "
+               "when narrow metric type enabled%s",
+               met, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
 
-  met = atoi (argv[0]);
+  /* RFC4444 */
+  if (circuit->area && circuit->area->newmetric == 1 &&
+      met > MAX_WIDE_LINK_METRIC)
+    {
+      vty_out (vty, "Invalid metric %d - should be <0-16777215> "
+               "when wide metric type enabled%s",
+               met, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
 
   circuit->te_metric[0] = met;
   circuit->te_metric[1] = met;
 
-  if (met > 63)
-    met = 63;
-
   circuit->metrics[0].metric_default = met;
   circuit->metrics[1].metric_default = met;
 
+  if (circuit->area)
+    lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
+
   return CMD_SUCCESS;
 }
 
@@ -1343,21 +1790,17 @@ DEFUN (no_isis_metric,
        "IS-IS commands\n"
        "Set default metric for circuit\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC;
+  circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC;
+  circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC;
+  circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC;
 
-  circuit->te_metric[0] = DEFAULT_CIRCUIT_METRICS;
-  circuit->te_metric[1] = DEFAULT_CIRCUIT_METRICS;
-  circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRICS;
-  circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRICS;
+  if (circuit->area)
+    lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
 
   return CMD_SUCCESS;
 }
@@ -1370,34 +1813,175 @@ ALIAS (no_isis_metric,
        "Set default metric for circuit\n"
        "Default metric value\n")
 
+DEFUN (isis_metric_l1,
+       isis_metric_l1_cmd,
+       "isis metric <0-16777215> level-1",
+       "IS-IS commands\n"
+       "Set default metric for circuit\n"
+       "Default metric value\n"
+       "Specify metric for level-1 routing\n")
+{
+  int met;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  met = atoi (argv[0]);
+
+  /* RFC3787 section 5.1 */
+  if (circuit->area && circuit->area->oldmetric == 1 &&
+      met > MAX_NARROW_LINK_METRIC)
+    {
+      vty_out (vty, "Invalid metric %d - should be <0-63> "
+               "when narrow metric type enabled%s",
+               met, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  /* RFC4444 */
+  if (circuit->area && circuit->area->newmetric == 1 &&
+      met > MAX_WIDE_LINK_METRIC)
+    {
+      vty_out (vty, "Invalid metric %d - should be <0-16777215> "
+               "when wide metric type enabled%s",
+               met, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  circuit->te_metric[0] = met;
+  circuit->metrics[0].metric_default = met;
+
+  if (circuit->area)
+    lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_metric_l1,
+       no_isis_metric_l1_cmd,
+       "no isis metric level-1",
+       NO_STR
+       "IS-IS commands\n"
+       "Set default metric for circuit\n"
+       "Specify metric for level-1 routing\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC;
+  circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC;
+
+  if (circuit->area)
+    lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_metric_l1,
+       no_isis_metric_l1_arg_cmd,
+       "no isis metric <0-16777215> level-1",
+       NO_STR
+       "IS-IS commands\n"
+       "Set default metric for circuit\n"
+       "Default metric value\n"
+       "Specify metric for level-1 routing\n")
+
+DEFUN (isis_metric_l2,
+       isis_metric_l2_cmd,
+       "isis metric <0-16777215> level-2",
+       "IS-IS commands\n"
+       "Set default metric for circuit\n"
+       "Default metric value\n"
+       "Specify metric for level-2 routing\n")
+{
+  int met;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  met = atoi (argv[0]);
+
+  /* RFC3787 section 5.1 */
+  if (circuit->area && circuit->area->oldmetric == 1 &&
+      met > MAX_NARROW_LINK_METRIC)
+    {
+      vty_out (vty, "Invalid metric %d - should be <0-63> "
+               "when narrow metric type enabled%s",
+               met, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  /* RFC4444 */
+  if (circuit->area && circuit->area->newmetric == 1 &&
+      met > MAX_WIDE_LINK_METRIC)
+    {
+      vty_out (vty, "Invalid metric %d - should be <0-16777215> "
+               "when wide metric type enabled%s",
+               met, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  circuit->te_metric[1] = met;
+  circuit->metrics[1].metric_default = met;
+
+  if (circuit->area)
+    lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_metric_l2,
+       no_isis_metric_l2_cmd,
+       "no isis metric level-2",
+       NO_STR
+       "IS-IS commands\n"
+       "Set default metric for circuit\n"
+       "Specify metric for level-2 routing\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC;
+  circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC;
+
+  if (circuit->area)
+    lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_metric_l2,
+       no_isis_metric_l2_arg_cmd,
+       "no isis metric <0-16777215> level-2",
+       NO_STR
+       "IS-IS commands\n"
+       "Set default metric for circuit\n"
+       "Default metric value\n"
+       "Specify metric for level-2 routing\n")
 /* end of metrics */
+
 DEFUN (isis_hello_interval,
        isis_hello_interval_cmd,
-       "isis hello-interval (<1-65535>|minimal)",
+       "isis hello-interval <1-600>",
        "IS-IS commands\n"
        "Set Hello interval\n"
        "Hello interval value\n"
        "Holdtime 1 seconds, interval depends on multiplier\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int interval;
-  char c;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
-  c = *argv[0];
-  if (isdigit ((int) c))
+  interval = atoi (argv[0]);
+  if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)
     {
-      interval = atoi (argv[0]);
+      vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  else
-    interval = HELLO_MINIMAL;  /* FIXME: should be calculated */
 
   circuit->hello_interval[0] = (u_int16_t) interval;
   circuit->hello_interval[1] = (u_int16_t) interval;
@@ -1412,27 +1996,19 @@ DEFUN (no_isis_hello_interval,
        "IS-IS commands\n"
        "Set Hello interval\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
-
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */
-  circuit->hello_interval[1] = HELLO_INTERVAL;
+  circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL;
+  circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_isis_hello_interval,
        no_isis_hello_interval_arg_cmd,
-       "no isis hello-interval (<1-65535>|minimal)",
+       "no isis hello-interval <1-600>",
        NO_STR
        "IS-IS commands\n"
        "Set Hello interval\n"
@@ -1441,33 +2017,25 @@ ALIAS (no_isis_hello_interval,
 
 DEFUN (isis_hello_interval_l1,
        isis_hello_interval_l1_cmd,
-       "isis hello-interval (<1-65535>|minimal) level-1",
+       "isis hello-interval <1-600> level-1",
        "IS-IS commands\n"
        "Set Hello interval\n"
        "Hello interval value\n"
        "Holdtime 1 second, interval depends on multiplier\n"
        "Specify hello-interval for level-1 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   long interval;
-  char c;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  c = *argv[0];
-  if (isdigit ((int) c))
+  interval = atoi (argv[0]);
+  if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)
     {
-      interval = atoi (argv[0]);
+      vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  else
-    interval = HELLO_MINIMAL;
 
   circuit->hello_interval[0] = (u_int16_t) interval;
 
@@ -1482,26 +2050,18 @@ DEFUN (no_isis_hello_interval_l1,
        "Set Hello interval\n"
        "Specify hello-interval for level-1 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
-
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */
+  circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_isis_hello_interval_l1,
        no_isis_hello_interval_l1_arg_cmd,
-       "no isis hello-interval (<1-65535>|minimal) level-1",
+       "no isis hello-interval <1-600> level-1",
        NO_STR
        "IS-IS commands\n"
        "Set Hello interval\n"
@@ -1511,33 +2071,25 @@ ALIAS (no_isis_hello_interval_l1,
 
 DEFUN (isis_hello_interval_l2,
        isis_hello_interval_l2_cmd,
-       "isis hello-interval (<1-65535>|minimal) level-2",
+       "isis hello-interval <1-600> level-2",
        "IS-IS commands\n"
        "Set Hello interval\n"
        "Hello interval value\n"
        "Holdtime 1 second, interval depends on multiplier\n"
        "Specify hello-interval for level-2 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   long interval;
-  char c;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  c = *argv[0];
-  if (isdigit ((int) c))
+  interval = atoi (argv[0]);
+  if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)
     {
-      interval = atoi (argv[0]);
+      vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  else
-    interval = HELLO_MINIMAL;
 
   circuit->hello_interval[1] = (u_int16_t) interval;
 
@@ -1545,33 +2097,25 @@ DEFUN (isis_hello_interval_l2,
 }
 
 DEFUN (no_isis_hello_interval_l2,
-       no_isis_hello_interval_l2_cmd,
-       "no isis hello-interval level-2",
-       NO_STR
-       "IS-IS commands\n"
-       "Set Hello interval\n"
-       "Specify hello-interval for level-2 IIHs\n")
-{
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
-
+       no_isis_hello_interval_l2_cmd,
+       "no isis hello-interval level-2",
+       NO_STR
+       "IS-IS commands\n"
+       "Set Hello interval\n"
+       "Specify hello-interval for level-2 IIHs\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->hello_interval[1] = HELLO_INTERVAL; /* Default is 1 sec. */
+  circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_isis_hello_interval_l2,
        no_isis_hello_interval_l2_arg_cmd,
-       "no isis hello-interval (<1-65535>|minimal) level-2",
+       "no isis hello-interval <1-600> level-2",
        NO_STR
        "IS-IS commands\n"
        "Set Hello interval\n"
@@ -1581,24 +2125,23 @@ ALIAS (no_isis_hello_interval_l2,
 
 DEFUN (isis_hello_multiplier,
        isis_hello_multiplier_cmd,
-       "isis hello-multiplier <3-1000>",
+       "isis hello-multiplier <2-100>",
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n"
        "Hello multiplier value\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int mult;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  mult = atoi (argv[0]);
+  if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s",
+               mult, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  mult = atoi (argv[0]);
 
   circuit->hello_multiplier[0] = (u_int16_t) mult;
   circuit->hello_multiplier[1] = (u_int16_t) mult;
@@ -1613,26 +2156,19 @@ DEFUN (no_isis_hello_multiplier,
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->hello_multiplier[0] = HELLO_MULTIPLIER;
-  circuit->hello_multiplier[1] = HELLO_MULTIPLIER;
+  circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER;
+  circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_isis_hello_multiplier,
        no_isis_hello_multiplier_arg_cmd,
-       "no isis hello-multiplier <3-1000>",
+       "no isis hello-multiplier <2-100>",
        NO_STR
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n"
@@ -1640,25 +2176,24 @@ ALIAS (no_isis_hello_multiplier,
 
 DEFUN (isis_hello_multiplier_l1,
        isis_hello_multiplier_l1_cmd,
-       "isis hello-multiplier <3-1000> level-1",
+       "isis hello-multiplier <2-100> level-1",
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n"
        "Hello multiplier value\n"
        "Specify hello multiplier for level-1 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int mult;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  mult = atoi (argv[0]);
+  if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s",
+               mult, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  mult = atoi (argv[0]);
 
   circuit->hello_multiplier[0] = (u_int16_t) mult;
 
@@ -1673,25 +2208,18 @@ DEFUN (no_isis_hello_multiplier_l1,
        "Set multiplier for Hello holding time\n"
        "Specify hello multiplier for level-1 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->hello_multiplier[0] = HELLO_MULTIPLIER;
+  circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_isis_hello_multiplier_l1,
        no_isis_hello_multiplier_l1_arg_cmd,
-       "no isis hello-multiplier <3-1000> level-1",
+       "no isis hello-multiplier <2-100> level-1",
        NO_STR
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n"
@@ -1700,25 +2228,24 @@ ALIAS (no_isis_hello_multiplier_l1,
 
 DEFUN (isis_hello_multiplier_l2,
        isis_hello_multiplier_l2_cmd,
-       "isis hello-multiplier <3-1000> level-2",
+       "isis hello-multiplier <2-100> level-2",
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n"
        "Hello multiplier value\n"
        "Specify hello multiplier for level-2 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   int mult;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  mult = atoi (argv[0]);
+  if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s",
+               mult, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  mult = atoi (argv[0]);
 
   circuit->hello_multiplier[1] = (u_int16_t) mult;
 
@@ -1733,57 +2260,43 @@ DEFUN (no_isis_hello_multiplier_l2,
        "Set multiplier for Hello holding time\n"
        "Specify hello multiplier for level-2 IIHs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->hello_multiplier[1] = HELLO_MULTIPLIER;
+  circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_isis_hello_multiplier_l2,
        no_isis_hello_multiplier_l2_arg_cmd,
-       "no isis hello-multiplier <3-1000> level-2",
+       "no isis hello-multiplier <2-100> level-2",
        NO_STR
        "IS-IS commands\n"
        "Set multiplier for Hello holding time\n"
        "Hello multiplier value\n"
        "Specify hello multiplier for level-2 IIHs\n")
 
-DEFUN (isis_hello,
-       isis_hello_cmd,
+DEFUN (isis_hello_padding,
+       isis_hello_padding_cmd,
        "isis hello padding",
        "IS-IS commands\n"
        "Add padding to IS-IS hello packets\n"
        "Pad hello packets\n"
        "<cr>\n")
 {
-  struct interface *ifp;
-  struct isis_circuit *circuit;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->u.bc.pad_hellos = 1;
+  circuit->pad_hellos = 1;
 
   return CMD_SUCCESS;
 }
 
-DEFUN (no_isis_hello,
-       no_isis_hello_cmd,
+DEFUN (no_isis_hello_padding,
+       no_isis_hello_padding_cmd,
        "no isis hello padding",
        NO_STR
        "IS-IS commands\n"
@@ -1791,42 +2304,34 @@ DEFUN (no_isis_hello,
        "Pad hello packets\n"
        "<cr>\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->u.bc.pad_hellos = 0;
+  circuit->pad_hellos = 0;
 
   return CMD_SUCCESS;
 }
 
 DEFUN (csnp_interval,
        csnp_interval_cmd,
-       "isis csnp-interval <0-65535>",
+       "isis csnp-interval <1-600>",
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n"
        "CSNP interval value\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   unsigned long interval;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  interval = atol (argv[0]);
+  if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  interval = atol (argv[0]);
 
   circuit->csnp_interval[0] = (u_int16_t) interval;
   circuit->csnp_interval[1] = (u_int16_t) interval;
@@ -1841,26 +2346,19 @@ DEFUN (no_csnp_interval,
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->csnp_interval[0] = CSNP_INTERVAL;
-  circuit->csnp_interval[1] = CSNP_INTERVAL;
+  circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL;
+  circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_csnp_interval,
        no_csnp_interval_arg_cmd,
-       "no isis csnp-interval <0-65535>",
+       "no isis csnp-interval <1-600>",
        NO_STR
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n"
@@ -1868,25 +2366,24 @@ ALIAS (no_csnp_interval,
 
 DEFUN (csnp_interval_l1,
        csnp_interval_l1_cmd,
-       "isis csnp-interval <0-65535> level-1",
+       "isis csnp-interval <1-600> level-1",
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n"
        "CSNP interval value\n"
        "Specify interval for level-1 CSNPs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   unsigned long interval;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  interval = atol (argv[0]);
+  if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  interval = atol (argv[0]);
 
   circuit->csnp_interval[0] = (u_int16_t) interval;
 
@@ -1901,25 +2398,18 @@ DEFUN (no_csnp_interval_l1,
        "Set CSNP interval in seconds\n"
        "Specify interval for level-1 CSNPs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->csnp_interval[0] = CSNP_INTERVAL;
+  circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_csnp_interval_l1,
        no_csnp_interval_l1_arg_cmd,
-       "no isis csnp-interval <0-65535> level-1",
+       "no isis csnp-interval <1-600> level-1",
        NO_STR
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n"
@@ -1928,25 +2418,24 @@ ALIAS (no_csnp_interval_l1,
 
 DEFUN (csnp_interval_l2,
        csnp_interval_l2_cmd,
-       "isis csnp-interval <0-65535> level-2",
+       "isis csnp-interval <1-600> level-2",
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n"
        "CSNP interval value\n"
        "Specify interval for level-2 CSNPs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
   unsigned long interval;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
+  interval = atol (argv[0]);
+  if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)
     {
-      return CMD_WARNING;
+      vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
-  assert (circuit);
-
-  interval = atol (argv[0]);
 
   circuit->csnp_interval[1] = (u_int16_t) interval;
 
@@ -1961,153 +2450,285 @@ DEFUN (no_csnp_interval_l2,
        "Set CSNP interval in seconds\n"
        "Specify interval for level-2 CSNPs\n")
 {
-  struct isis_circuit *circuit;
-  struct interface *ifp;
-
-  ifp = vty->index;
-  circuit = ifp->info;
-  if (circuit == NULL)
-    {
-      return CMD_WARNING;
-    }
-  assert (circuit);
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  circuit->csnp_interval[1] = CSNP_INTERVAL;
+  circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
 ALIAS (no_csnp_interval_l2,
        no_csnp_interval_l2_arg_cmd,
-       "no isis csnp-interval <0-65535> level-2",
+       "no isis csnp-interval <1-600> level-2",
        NO_STR
        "IS-IS commands\n"
        "Set CSNP interval in seconds\n"
        "CSNP interval value\n"
        "Specify interval for level-2 CSNPs\n")
 
-#ifdef HAVE_IPV6
-DEFUN (ipv6_router_isis,
-       ipv6_router_isis_cmd,
-       "ipv6 router isis WORD",
-       "IPv6 interface subcommands\n"
-       "IPv6 Router interface commands\n"
-       "IS-IS Routing for IPv6\n"
-       "Routing process tag\n")
+DEFUN (psnp_interval,
+       psnp_interval_cmd,
+       "isis psnp-interval <1-120>",
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "PSNP interval value\n")
 {
-  struct isis_circuit *c;
-  struct interface *ifp;
-  struct isis_area *area;
+  unsigned long interval;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  ifp = (struct interface *) vty->index;
-  assert (ifp);
+  interval = atol (argv[0]);
+  if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)
+    {
+      vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
 
-  area = isis_area_lookup (argv[0]);
+  circuit->psnp_interval[0] = (u_int16_t) interval;
+  circuit->psnp_interval[1] = (u_int16_t) interval;
 
-  /* Prevent more than one circuit per interface */
-  if (area)
-    c = circuit_lookup_by_ifp (ifp, area->circuit_list);
-  else
-    c = NULL;
+  return CMD_SUCCESS;
+}
 
-  if (c && (ifp->info != NULL))
-    {
-      if (c->ipv6_router == 1)
-       {
-         vty_out (vty, "ISIS circuit is already defined for IPv6%s",
-                  VTY_NEWLINE);
-         return CMD_WARNING;
-       }
-    }
+DEFUN (no_psnp_interval,
+       no_psnp_interval_cmd,
+       "no isis psnp-interval",
+       NO_STR
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  /* this is here for ciscopability */
-  if (!area)
-    {
-      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
+  circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL;
+  circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_psnp_interval,
+       no_psnp_interval_arg_cmd,
+       "no isis psnp-interval <1-120>",
+       NO_STR
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "PSNP interval value\n")
 
-  if (!c)
+DEFUN (psnp_interval_l1,
+       psnp_interval_l1_cmd,
+       "isis psnp-interval <1-120> level-1",
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "PSNP interval value\n"
+       "Specify interval for level-1 PSNPs\n")
+{
+  unsigned long interval;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  interval = atol (argv[0]);
+  if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)
     {
-      c = circuit_lookup_by_ifp (ifp, isis->init_circ_list);
-      c = isis_csm_state_change (ISIS_ENABLE, c, area);
-      c->interface = ifp;
-      ifp->info = c;
+      vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
 
-  if (!c)
-    return CMD_WARNING;
+  circuit->psnp_interval[0] = (u_int16_t) interval;
 
-  c->ipv6_router = 1;
-  area->ipv6_circuits++;
-  circuit_update_nlpids (c);
+  return CMD_SUCCESS;
+}
 
-  vty->node = INTERFACE_NODE;
+DEFUN (no_psnp_interval_l1,
+       no_psnp_interval_l1_cmd,
+       "no isis psnp-interval level-1",
+       NO_STR
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "Specify interval for level-1 PSNPs\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL;
 
   return CMD_SUCCESS;
 }
 
-DEFUN (no_ipv6_router_isis,
-       no_ipv6_router_isis_cmd,
-       "no ipv6 router isis WORD",
+ALIAS (no_psnp_interval_l1,
+       no_psnp_interval_l1_arg_cmd,
+       "no isis psnp-interval <1-120> level-1",
        NO_STR
-       "IPv6 interface subcommands\n"
-       "IPv6 Router interface commands\n"
-       "IS-IS Routing for IPv6\n"
-       "Routing process tag\n")
-{
-  struct isis_circuit *c;
-  struct interface *ifp;
-  struct isis_area *area;
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "PSNP interval value\n"
+       "Specify interval for level-1 PSNPs\n")
 
-  ifp = (struct interface *) vty->index;
-  /* UGLY - will remove l8r
-     if (circuit == NULL) {
-     return CMD_WARNING;
-     } */
-  assert (ifp);
+DEFUN (psnp_interval_l2,
+       psnp_interval_l2_cmd,
+       "isis psnp-interval <1-120> level-2",
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "PSNP interval value\n"
+       "Specify interval for level-2 PSNPs\n")
+{
+  unsigned long interval;
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
 
-  area = isis_area_lookup (argv[0]);
-  if (!area)
+  interval = atol (argv[0]);
+  if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)
     {
-      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s",
+               interval, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
     }
 
-  c = circuit_lookup_by_ifp (ifp, area->circuit_list);
-  if (!c)
-    return CMD_WARNING;
+  circuit->psnp_interval[1] = (u_int16_t) interval;
 
-  c->ipv6_router = 0;
-  area->ipv6_circuits--;
-  if (c->ip_router == 0)
-    isis_csm_state_change (ISIS_DISABLE, c, area);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_psnp_interval_l2,
+       no_psnp_interval_l2_cmd,
+       "no isis psnp-interval level-2",
+       NO_STR
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "Specify interval for level-2 PSNPs\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL;
 
   return CMD_SUCCESS;
 }
-#endif /* HAVE_IPV6 */
 
-static struct cmd_node interface_node = {
+ALIAS (no_psnp_interval_l2,
+       no_psnp_interval_l2_arg_cmd,
+       "no isis psnp-interval <1-120> level-2",
+       NO_STR
+       "IS-IS commands\n"
+       "Set PSNP interval in seconds\n"
+       "PSNP interval value\n"
+       "Specify interval for level-2 PSNPs\n")
+
+struct cmd_node interface_node = {
   INTERFACE_NODE,
   "%s(config-if)# ",
   1,
 };
 
+DEFUN (isis_network,
+       isis_network_cmd,
+       "isis network point-to-point",
+       "IS-IS commands\n"
+       "Set network type\n"
+       "point-to-point network type\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  /* RFC5309 section 4 */
+  if (circuit->circ_type == CIRCUIT_T_P2P)
+    return CMD_SUCCESS;
+
+  if (circuit->state != C_STATE_UP)
+    {
+      circuit->circ_type = CIRCUIT_T_P2P;
+      circuit->circ_type_config = CIRCUIT_T_P2P;
+    }
+  else
+    {
+      struct isis_area *area = circuit->area;
+      if (!if_is_broadcast (circuit->interface))
+        {
+          vty_out (vty, "isis network point-to-point "
+                   "is valid only on broadcast interfaces%s",
+                   VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
+
+      isis_csm_state_change (ISIS_DISABLE, circuit, area);
+      circuit->circ_type = CIRCUIT_T_P2P;
+      circuit->circ_type_config = CIRCUIT_T_P2P;
+      isis_csm_state_change (ISIS_ENABLE, circuit, area);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_network,
+       no_isis_network_cmd,
+       "no isis network point-to-point",
+       NO_STR
+       "IS-IS commands\n"
+       "Set network type for circuit\n"
+       "point-to-point network type\n")
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+
+  /* RFC5309 section 4 */
+  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+    return CMD_SUCCESS;
+
+  if (circuit->state != C_STATE_UP)
+    {
+      circuit->circ_type = CIRCUIT_T_BROADCAST;
+      circuit->circ_type_config = CIRCUIT_T_BROADCAST;
+    }
+  else
+    {
+      struct isis_area *area = circuit->area;
+      if (circuit->interface &&
+          !if_is_broadcast (circuit->interface))
+      {
+        vty_out (vty, "no isis network point-to-point "
+                 "is valid only on broadcast interfaces%s",
+                 VTY_NEWLINE);
+        return CMD_ERR_AMBIGUOUS;
+      }
+
+      isis_csm_state_change (ISIS_DISABLE, circuit, area);
+      circuit->circ_type = CIRCUIT_T_BROADCAST;
+      circuit->circ_type_config = CIRCUIT_T_BROADCAST;
+      isis_csm_state_change (ISIS_ENABLE, circuit, area);
+    }
+
+  return CMD_SUCCESS;
+}
+
 int
 isis_if_new_hook (struct interface *ifp)
 {
-/* FIXME: Discuss if the circuit should be created here
-  ifp->info = XMALLOC (MTYPE_ISIS_IF_INFO, sizeof (struct isis_if_info)); */
-  ifp->info = NULL;
   return 0;
 }
 
 int
 isis_if_delete_hook (struct interface *ifp)
 {
-/* FIXME: Discuss if the circuit should be created here
-  XFREE (MTYPE_ISIS_IF_INFO, ifp->info);*/
-  ifp->info = NULL;
+  struct isis_circuit *circuit;
+  /* Clean up the circuit data */
+  if (ifp && ifp->info)
+    {
+      circuit = ifp->info;
+      isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area);
+      isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area);
+    }
+
   return 0;
 }
 
@@ -2122,6 +2743,7 @@ isis_circuit_init ()
   /* Install interface node */
   install_node (&interface_node, isis_interface_config_write);
   install_element (CONFIG_NODE, &interface_cmd);
+  install_element (CONFIG_NODE, &no_interface_cmd);
 
   install_default (INTERFACE_NODE);
   install_element (INTERFACE_NODE, &interface_desc_cmd);
@@ -2130,6 +2752,9 @@ isis_circuit_init ()
   install_element (INTERFACE_NODE, &ip_router_isis_cmd);
   install_element (INTERFACE_NODE, &no_ip_router_isis_cmd);
 
+  install_element (INTERFACE_NODE, &isis_passive_cmd);
+  install_element (INTERFACE_NODE, &no_isis_passive_cmd);
+
   install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
   install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd);
 
@@ -2150,6 +2775,12 @@ isis_circuit_init ()
   install_element (INTERFACE_NODE, &isis_metric_cmd);
   install_element (INTERFACE_NODE, &no_isis_metric_cmd);
   install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd);
+  install_element (INTERFACE_NODE, &isis_metric_l1_cmd);
+  install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd);
+  install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd);
+  install_element (INTERFACE_NODE, &isis_metric_l2_cmd);
+  install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd);
+  install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd);
 
   install_element (INTERFACE_NODE, &isis_hello_interval_cmd);
   install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd);
@@ -2171,8 +2802,9 @@ isis_circuit_init ()
   install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd);
   install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd);
 
-  install_element (INTERFACE_NODE, &isis_hello_cmd);
-  install_element (INTERFACE_NODE, &no_isis_hello_cmd);
+  install_element (INTERFACE_NODE, &isis_hello_padding_cmd);
+  install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd);
+
   install_element (INTERFACE_NODE, &csnp_interval_cmd);
   install_element (INTERFACE_NODE, &no_csnp_interval_cmd);
   install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd);
@@ -2183,6 +2815,19 @@ isis_circuit_init ()
   install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd);
   install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd);
 
+  install_element (INTERFACE_NODE, &psnp_interval_cmd);
+  install_element (INTERFACE_NODE, &no_psnp_interval_cmd);
+  install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd);
+  install_element (INTERFACE_NODE, &psnp_interval_l1_cmd);
+  install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd);
+  install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd);
+  install_element (INTERFACE_NODE, &psnp_interval_l2_cmd);
+  install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd);
+  install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd);
+
+  install_element (INTERFACE_NODE, &isis_network_cmd);
+  install_element (INTERFACE_NODE, &no_isis_network_cmd);
+
 #ifdef HAVE_IPV6
   install_element (INTERFACE_NODE, &ipv6_router_isis_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd);
index f32d1ddae709eb0bda05884d6bcf6e062181946a..7ed481dc2ed76b30653d37e35b6c338d19428409 100644 (file)
@@ -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
@@ -65,7 +63,6 @@ struct isis_p2p_info
 struct isis_circuit
 {
   int state;
-  int connected;
   u_char circuit_id;           /* l1/l2 p2p/bcast CircuitID */
   struct isis_area *area;      /* back pointer to the area */
   struct interface *interface; /* interface info from z */
@@ -79,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 */
@@ -111,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
    */
@@ -142,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 */
index 334d33940f64cb1cba646d2c5aecd443c2e6769c..d158961b99f2e6c284d0eea29479b476a548858c 100644 (file)
@@ -21,6 +21,9 @@
  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+#ifndef ISIS_COMMON_H
+#define ISIS_COMMON_H
+
 /*
  * Area Address
  */
@@ -65,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
index 1b75ba6b160e7e1af7aab8782956dc989251731a..bb2c4b40610da3f65fbf64802e01d610fabb5bdf 100644 (file)
  * 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       /* % */
 
 #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
 
 #define SNPA_ADDRSTRLEN 18
 #define ISIS_SYS_ID_LEN  6
+#define ISIS_NSEL_LEN    1
 #define SYSID_STRLEN    24
 
 /*
  * 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
index 6cdde46a9875956c3e57a14c0a29c7d9b0451808..5d74a71be967f61060c84e6633b316c0cca6196b 100644 (file)
@@ -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,24 +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;
-         circuit->connected = 1;
-         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;
@@ -131,19 +137,21 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
        }
       break;
     case C_STATE_CONF:
+      assert (circuit);
       switch (event)
        {
        case ISIS_ENABLE:
          zlog_warn ("circuit already enabled");
          break;
        case IF_UP_FROM_Z:
-         if (!circuit->connected) {
-           isis_circuit_if_add (circuit, (struct interface *) arg);
-           isis_circuit_up (circuit);
-         }
+         isis_circuit_if_add (circuit, (struct interface *) arg);
+         if (isis_circuit_up (circuit) != ISIS_OK)
+            {
+              isis_circuit_if_del (circuit, (struct interface *) arg);
+             break;
+            }
          circuit->state = C_STATE_UP;
-         circuit->connected = 1;
-         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);
@@ -156,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:
@@ -165,14 +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_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;
index fe872a952b6ffcd71a9ae71182dc0da8d2b79f8e..73b6d3e7b223677388cc5dc23b49907d8bf6c9e2 100644 (file)
@@ -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;
 }
 
index 8d306c8f55db5435de89051ba48bb5883612656c..bc6ec11962797b3000db9be37c1b630fa5c08aea 100644 (file)
@@ -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,
index 0b758c856e7c497d61b3c17eb55553933705055b..ffb0d503fb648bf31f4f0bf9789619b257a3db3b 100644 (file)
@@ -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
index 37a7b03c0e08a2e23bc9f40c974293e186a8ad0c..379c454fc565eb6a08aa54976b5890c0a2c7dec3 100644 (file)
@@ -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 */
index 4380092243341ce785d6d7591c90927f92de3f94..3887b7c5a22e90f562475ea5004ce5bc22028b5c 100644 (file)
 #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"
 #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,64 @@ isis_event_system_type_change (struct isis_area *area, int newtype)
     return;                    /* No change */
 
   switch (area->is_type)
-    {
+  {
     case IS_LEVEL_1:
+      if (newtype == IS_LEVEL_2)
+        area_resign_level (area, IS_LEVEL_1);
+
       if (area->lspdb[1] == NULL)
-       area->lspdb[1] = lsp_db_init ();
-      lsp_l2_generate (area);
+        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 (newtype == IS_LEVEL_1)
+        area_resign_level (area, IS_LEVEL_2);
+
       if (area->lspdb[0] == NULL)
-       area->lspdb[0] = lsp_db_init ();
-      lsp_l1_generate (area);
+        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
@@ -142,13 +192,14 @@ circuit_commence_level (struct isis_circuit *circuit, int level)
 {
   if (level == 1)
     {
-      THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
-                      isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
+      if (! circuit->is_passive)
+        THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
+                        isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
 
       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,
@@ -160,8 +211,9 @@ circuit_commence_level (struct isis_circuit *circuit, int level)
     }
   else
     {
-      THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
-                      isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
+      if (! circuit->is_passive)
+        THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
+                        isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
 
       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
        {
@@ -194,6 +246,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 +256,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 +280,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 +302,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 +345,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 +366,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;
 }
index 86bf051f33d3a82f06bc15941fe2c52362f1a752..c252f3def96a346a5d8896e91acabd6c178e2573 100644 (file)
  * 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);
 /*
index 03c91101fcb67d0cebdccf85d207d5b746caff75..ec0eaa4f82015b0e37446f9ccbf4d57a8bde2a24 100644 (file)
@@ -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)
     {
index 13dd9e145683caa39afe7cc7b8c95f97195f81ef..e2e42adcc95117ab3ec524dc6e75f08e9940a0fd 100644 (file)
 
 /* 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 */
index fd40bb37277c00931e779e3a718f4523359bfa10..5c1e9931dc9ec0eea108dd24c5df88d89cbe3d38 100644 (file)
 #include "hash.h"
 #include "if.h"
 #include "checksum.h"
+#include "md5.h"
 
 #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/isisd.h"
 #include "isisd/isis_tlv.h"
@@ -45,7 +47,6 @@
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_misc.h"
-#include "isisd/isis_flags.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
 #include "spgrid.h"
 #endif
 
-#define LSP_MEMORY_PREASSIGN
-
-extern struct isis *isis;
-extern struct thread_master *master;
-extern struct in_addr router_id_zebra;
-
 /* staticly assigned vars for printing purposes */
 char lsp_bits_string[200];     /* FIXME: enough ? */
 
+static int lsp_l1_refresh (struct thread *thread);
+static int lsp_l2_refresh (struct thread *thread);
+static int lsp_l1_refresh_pseudo (struct thread *thread);
+static int lsp_l2_refresh_pseudo (struct thread *thread);
+
 int
 lsp_id_cmp (u_char * id1, u_char * id2)
 {
@@ -90,7 +90,7 @@ lsp_search (u_char * id, dict_t * lspdb)
   zlog_debug ("searching db");
   for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
     {
-      zlog_debug ("%s\t%pX", rawlspid_print ((char *) dnode_getkey (dn)),
+      zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
                  dnode_get (dn));
     }
 #endif /* EXTREME DEBUG */
@@ -109,54 +109,56 @@ lsp_clear_data (struct isis_lsp *lsp)
   if (!lsp)
     return;
 
+  if (lsp->tlv_data.hostname)
+    isis_dynhn_remove (lsp->lsp_header->lsp_id);
+
   if (lsp->own_lsp)
     {
       if (lsp->tlv_data.nlpids)
-       XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
+        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
       if (lsp->tlv_data.hostname)
-       XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
+        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
+      if (lsp->tlv_data.router_id)
+        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
     }
-  if (lsp->tlv_data.is_neighs)
-    list_delete (lsp->tlv_data.is_neighs);
-  if (lsp->tlv_data.te_is_neighs)
-    list_delete (lsp->tlv_data.te_is_neighs);
-  if (lsp->tlv_data.area_addrs)
-    list_delete (lsp->tlv_data.area_addrs);
-  if (lsp->tlv_data.es_neighs)
-    list_delete (lsp->tlv_data.es_neighs);
-  if (lsp->tlv_data.ipv4_addrs)
-    list_delete (lsp->tlv_data.ipv4_addrs);
-  if (lsp->tlv_data.ipv4_int_reachs)
-    list_delete (lsp->tlv_data.ipv4_int_reachs);
-  if (lsp->tlv_data.ipv4_ext_reachs)
-    list_delete (lsp->tlv_data.ipv4_ext_reachs);
-  if (lsp->tlv_data.te_ipv4_reachs)
-    list_delete (lsp->tlv_data.te_ipv4_reachs);
-#ifdef HAVE_IPV6
-  if (lsp->tlv_data.ipv6_addrs)
-    list_delete (lsp->tlv_data.ipv6_addrs);
-  if (lsp->tlv_data.ipv6_reachs)
-    list_delete (lsp->tlv_data.ipv6_reachs);
-#endif /* HAVE_IPV6 */
 
-  memset (&lsp->tlv_data, 0, sizeof (struct tlvs));
-
-  return;
+  free_tlvs (&lsp->tlv_data);
 }
 
 static void
 lsp_destroy (struct isis_lsp *lsp)
 {
+  struct listnode *cnode, *lnode, *lnnode;
+  struct isis_lsp *lsp_in_list;
+  struct isis_circuit *circuit;
+
   if (!lsp)
     return;
 
+  for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
+    {
+      if (circuit->lsp_queue == NULL)
+        continue;
+      for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
+        if (lsp_in_list == lsp)
+          list_delete_node(circuit->lsp_queue, lnode);
+    }
+  ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
+  ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
+
   lsp_clear_data (lsp);
 
   if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
     {
       list_delete (lsp->lspu.frags);
+      lsp->lspu.frags = NULL;
     }
 
+  isis_spf_schedule (lsp->area, lsp->level);
+#ifdef HAVE_IPV6
+  isis_spf_schedule6 (lsp->area, lsp->level);
+#endif
+
   if (lsp->pdu)
     stream_free (lsp->pdu);
   XFREE (MTYPE_ISIS_LSP, lsp);
@@ -254,7 +256,7 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
     {
       if (isis->debugs & DEBUG_SNP_PACKETS)
        {
-         zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
+         zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
                      " lifetime %us",
                      areatag,
                      rawlspid_print (lsp->lsp_header->lsp_id),
@@ -273,7 +275,7 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
     {
       if (isis->debugs & DEBUG_SNP_PACKETS)
        {
-         zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
+         zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
                      " lifetime %us",
                      areatag,
                      rawlspid_print (lsp->lsp_header->lsp_id),
@@ -290,7 +292,7 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
   if (isis->debugs & DEBUG_SNP_PACKETS)
     {
       zlog_debug
-       ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
+       ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
         areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
         ntohs (checksum), ntohs (rem_lifetime));
       zlog_debug ("ISIS-Snp (%s):       is older than ours seq 0x%08x,"
@@ -303,6 +305,91 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
   return LSP_OLDER;
 }
 
+static void
+lsp_auth_add (struct isis_lsp *lsp)
+{
+  struct isis_passwd *passwd;
+  unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+
+  /*
+   * Add the authentication info if its present
+   */
+  (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
+                               (passwd = &lsp->area->domain_passwd);
+  switch (passwd->type)
+    {
+      /* Cleartext */
+      case ISIS_PASSWD_TYPE_CLEARTXT:
+        memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
+        tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
+        break;
+
+      /* HMAC MD5 */
+      case ISIS_PASSWD_TYPE_HMAC_MD5:
+        /* Remember where TLV is written so we can later
+         * overwrite the MD5 hash */
+        lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
+        memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+        lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+        lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
+        memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
+                ISIS_AUTH_MD5_SIZE);
+        tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
+                          lsp->pdu);
+        break;
+
+      default:
+        break;
+    }
+}
+
+static void
+lsp_auth_update (struct isis_lsp *lsp)
+{
+  struct isis_passwd *passwd;
+  unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+  uint16_t checksum, rem_lifetime;
+
+  /* For HMAC MD5 we need to recompute the md5 hash and store it */
+  (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
+                               (passwd = &lsp->area->domain_passwd);
+  if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
+    return;
+
+  /*
+   * In transient conditions (when net is configured where authentication
+   * config and lsp regenerate schedule is not yet run), there could be
+   * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
+   * return, when lsp_regenerate is run, lsp will have auth tlv.
+   */
+  if (lsp->auth_tlv_offset == 0)
+    return;
+
+  /*
+   * RFC 5304 set auth value, checksum and remaining lifetime to zero
+   * before computation and reset to old values after computation.
+   */
+  checksum = lsp->lsp_header->checksum;
+  rem_lifetime = lsp->lsp_header->rem_lifetime;
+  lsp->lsp_header->checksum = 0;
+  lsp->lsp_header->rem_lifetime = 0;
+  /* Set the authentication value as well to zero */
+  memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
+          0, ISIS_AUTH_MD5_SIZE);
+  /* Compute autentication value */
+  hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
+            (unsigned char *) &passwd->passwd, passwd->len,
+            (caddr_t) &hmac_md5_hash);
+  /* Copy the hash into the stream */
+  memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
+          hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+  memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
+          ISIS_AUTH_MD5_SIZE);
+  /* Copy back the checksum and remaining lifetime */
+  lsp->lsp_header->checksum = checksum;
+  lsp->lsp_header->rem_lifetime = rem_lifetime;
+}
+
 void
 lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
 {
@@ -311,11 +398,25 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
   if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
     newseq = ntohl (lsp->lsp_header->seq_num) + 1;
   else
-    newseq = seq_num++;
+    newseq = seq_num + 1;
 
   lsp->lsp_header->seq_num = htonl (newseq);
-  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
-                  ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+
+  /* Recompute authentication and checksum information */
+  lsp_auth_update (lsp);
+  /* ISO 10589 - 7.3.11 Generation of the checksum
+   * The checksum shall be computed over all fields in the LSP which appear
+   * after the Remaining Lifetime field. This field (and those appearing
+   * before it) are excluded so that the LSP may be aged by systems without
+   * requiring recomputation.
+   */
+  fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+                    ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+
+  isis_spf_schedule (lsp->area, lsp->level);
+#ifdef HAVE_IPV6
+  isis_spf_schedule6 (lsp->area, lsp->level);
+#endif
 
   return;
 }
@@ -340,54 +441,40 @@ lsp_seqnum_update (struct isis_lsp *lsp0)
   return;
 }
 
-int
-isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
-                        int pdulen, struct isis_passwd *passwd)
+static u_int8_t
+lsp_bits_generate (int level, int overload_bit)
 {
-  uint32_t expected = 0, found;
-  struct tlvs tlvs;
-  int retval = 0;
-
-  expected |= TLVFLAG_AUTH_INFO;
-  retval = parse_tlvs (area->area_tag, stream->data +
-                      ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
-                      pdulen - ISIS_FIXED_HDR_LEN
-                      - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
-
-  if (retval || !(found & TLVFLAG_AUTH_INFO))
-    return 1;                  /* Auth fail (parsing failed or no auth-tlv) */
-
-  switch (tlvs.auth_info.type)
-    {
-      case ISIS_PASSWD_TYPE_HMAC_MD5:
-       zlog_debug("Got LSP with ISIS_PASSWD_TYPE_HMAC_MD5");
-       break;
-      case ISIS_PASSWD_TYPE_CLEARTXT:
-       zlog_debug("Got LSP with ISIS_PASSWD_TYPE_CLEARTXT");
-       break;
-      default:
-       zlog_debug("Unknown authentication type in LSP");
-       break;
-    }
-
-  return 0;
-  /* return authentication_check (passwd, &tlvs.auth_info);*/
+  u_int8_t lsp_bits = 0;
+  if (level == IS_LEVEL_1)
+    lsp_bits = IS_LEVEL_1;
+  else
+    lsp_bits = IS_LEVEL_1_AND_2;
+  if (overload_bit)
+    lsp_bits |= overload_bit;
+  return lsp_bits;
 }
 
 static void
 lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
-                struct isis_area *area)
+                 struct isis_area *area, int level)
 {
   uint32_t expected = 0, found;
   int retval;
 
+  /* free the old lsp data */
+  lsp_clear_data (lsp);
+
   /* copying only the relevant part of our stream */
+  if (lsp->pdu != NULL)
+    stream_free (lsp->pdu);
   lsp->pdu = stream_dup (stream);
-  
+
   /* setting pointers to the correct place */
   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
                                                    ISIS_FIXED_HDR_LEN);
+  lsp->area = area;
+  lsp->level = level;
   lsp->age_out = ZERO_AGE_LIFETIME;
   lsp->installed = time (NULL);
   /*
@@ -396,8 +483,6 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
   expected |= TLVFLAG_AUTH_INFO;
   expected |= TLVFLAG_AREA_ADDRS;
   expected |= TLVFLAG_IS_NEIGHS;
-  if ((lsp->lsp_header->lsp_bits & 3) == 3)    /* a level 2 LSP */
-    expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS;
   expected |= TLVFLAG_NLPID;
   if (area->dynhostname)
     expected |= TLVFLAG_DYN_HOSTNAME;
@@ -415,57 +500,58 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
   expected |= TLVFLAG_IPV6_REACHABILITY;
 #endif /* HAVE_IPV6 */
 
-  retval = parse_tlvs (area->area_tag, lsp->pdu->data +
-                      ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
-                      ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
-                      - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data);
+  retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
+                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
+                       ntohs (lsp->lsp_header->pdu_len) -
+                       ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
+                       &expected, &found, &lsp->tlv_data,
+                       NULL);
+  if (retval != ISIS_OK)
+    {
+      zlog_warn ("Could not parse LSP");
+      return;
+    }
 
-  if (found & TLVFLAG_DYN_HOSTNAME)
+  if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
     {
-      if (area->dynhostname)
-       isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
-                          (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
-                          IS_LEVEL_1_AND_2 ? IS_LEVEL_2 :
-                          (lsp->lsp_header->lsp_bits & LSPBIT_IST));
+      isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
+                         (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
+                          IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
     }
 
+  return;
 }
 
 void
-lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
-           struct stream *stream, struct isis_area *area, int level)
+lsp_update (struct isis_lsp *lsp, struct stream *stream,
+            struct isis_area *area, int level)
 {
   dnode_t *dnode = NULL;
 
-  /* Remove old LSP from LSP database. */
+  /* Remove old LSP from database. This is required since the
+   * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
+   * and will update it with the new data in the stream. */
   dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
   if (dnode)
     dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
 
-  /* free the old lsp data */
-  XFREE (MTYPE_STREAM_DATA, lsp->pdu);
-  lsp_clear_data (lsp);
-
   /* rebuild the lsp data */
-  lsp_update_data (lsp, stream, area);
-
-  /* set the new values for lsp header */
-  memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
+  lsp_update_data (lsp, stream, area, level);
 
-  if (dnode)
-    lsp_insert (lsp, area->lspdb[level - 1]);
+  /* insert the lsp back into the database */
+  lsp_insert (lsp, area->lspdb[level - 1]);
 }
 
 /* creation of LSP directly from what we received */
 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)
 {
   struct isis_lsp *lsp;
 
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
-  lsp_update_data (lsp, stream, area);
+  lsp_update_data (lsp, stream, area, level);
 
   if (lsp0 == NULL)
     {
@@ -499,12 +585,8 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
       zlog_warn ("lsp_new(): out of memory");
       return NULL;
     }
-#ifdef LSP_MEMORY_PREASSIGN
-  lsp->pdu = stream_new (1514);        /*Should be minimal mtu? yup... */
-#else
-  /* We need to do realloc on TLVs additions */
-  lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-#endif /* LSP_MEMORY_PREASSIGN */
+  /* FIXME: Should be minimal mtu? */
+  lsp->pdu = stream_new (1500);
   if (LSP_FRAGMENT (lsp_id) == 0)
     lsp->lspu.frags = list_new ();
   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
@@ -512,7 +594,7 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
     (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
 
   /* at first we fill the FIXED HEADER */
-  (level == 1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
+  (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
     fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
 
   /* now for the LSP HEADER */
@@ -529,9 +611,10 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
 
   if (isis->debugs & DEBUG_EVENTS)
-    zlog_debug ("New LSP with ID %s-%02x-%02x seqnum %08x",
+    zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
                sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
                LSP_FRAGMENT (lsp->lsp_header->lsp_id),
+               ntohl (lsp->lsp_header->pdu_len),
                ntohl (lsp->lsp_header->seq_num));
 
   return lsp;
@@ -541,6 +624,13 @@ void
 lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
 {
   dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
+  if (lsp->lsp_header->seq_num != 0)
+    {
+      isis_spf_schedule (lsp->area, lsp->level);
+#ifdef HAVE_IPV6
+      isis_spf_schedule6 (lsp->area, lsp->level);
+#endif
+    }
 }
 
 /*
@@ -577,12 +667,13 @@ lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
 }
 
 /*
- * Build a list of all LSPs bounded by start and stop ids
+ * Build a list of num_lsps LSPs bounded by start_id and stop_id.
  */
 void
-lsp_build_list (u_char * start_id, u_char * stop_id,
+lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
                struct list *list, dict_t * lspdb)
 {
+  u_char count;
   dnode_t *first, *last, *curr;
 
   first = dict_lower_bound (lspdb, start_id);
@@ -594,14 +685,18 @@ lsp_build_list (u_char * start_id, u_char * stop_id,
   curr = first;
 
   listnode_add (list, first->dict_data);
+  count = 1;
 
   while (curr)
     {
       curr = dict_next (lspdb, curr);
       if (curr)
-       listnode_add (list, curr->dict_data);
-      if (curr == last)
-       break;
+        {
+          listnode_add (list, curr->dict_data);
+          count++;
+        }
+      if (count == num_lsps || curr == last)
+        break;
     }
 
   return;
@@ -611,11 +706,12 @@ lsp_build_list (u_char * start_id, u_char * stop_id,
  * Build a list of LSPs with SSN flag set for the given circuit
  */
 void
-lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
-                   dict_t * lspdb)
+lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
+                    struct list *list, dict_t * lspdb)
 {
   dnode_t *dnode, *next;
   struct isis_lsp *lsp;
+  u_char count = 0;
 
   dnode = dict_first (lspdb);
   while (dnode != NULL)
@@ -623,7 +719,12 @@ lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
       next = dict_next (lspdb, dnode);
       lsp = dnode_get (dnode);
       if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
-       listnode_add (list, lsp);
+        {
+          listnode_add (list, lsp);
+          ++count;
+        }
+      if (count == num_lsps)
+        break;
       dnode = next;
     }
 
@@ -637,22 +738,11 @@ lsp_set_time (struct isis_lsp *lsp)
 
   if (lsp->lsp_header->rem_lifetime == 0)
     {
-      if (lsp->age_out != 0)
-       lsp->age_out--;
+      if (lsp->age_out > 0)
+        lsp->age_out--;
       return;
     }
 
-  /* If we are turning 0 */
-  /* ISO 10589 - 7.3.16.4 first paragraph */
-
-  if (ntohs (lsp->lsp_header->rem_lifetime) == 1)
-    {
-      /* 7.3.16.4 a) set SRM flags on all */
-      ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-      /* 7.3.16.4 b) retain only the header FIXME  */
-      /* 7.3.16.4 c) record the time to purge FIXME (other way to do it) */
-    }
-
   lsp->lsp_header->rem_lifetime =
     htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
 }
@@ -669,13 +759,11 @@ lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
     dyn = NULL;
 
   if (dyn)
-    sprintf ((char *)id, "%.14s", dyn->name.name);
-  else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost)
-    sprintf ((char *)id, "%.14s", unix_hostname ());
+      sprintf ((char *)id, "%.14s", dyn->name.name);
+  else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
+      sprintf ((char *)id, "%.14s", unix_hostname ());
   else
-    {
       memcpy (id, sysid_print (lsp_id), 15);
-    }
   if (frag)
     sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
             LSP_FRAGMENT (lsp_id));
@@ -707,30 +795,32 @@ lsp_bits2string (u_char * lsp_bits)
 }
 
 /* this function prints the lsp on show isis database */
-static void
-lsp_print (dnode_t * node, struct vty *vty, char dynhost)
+void
+lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {
-  struct isis_lsp *lsp = dnode_get (node);
   u_char LSPid[255];
+  char age_out[8];
 
   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
-  vty_out (vty, "%-21s%c   ", LSPid, lsp->own_lsp ? '*' : ' ');
-  vty_out (vty, "0x%08x   ", ntohl (lsp->lsp_header->seq_num));
-  vty_out (vty, "0x%04x      ", ntohs (lsp->lsp_header->checksum));
-
+  vty_out (vty, "%-21s%c  ", LSPid, lsp->own_lsp ? '*' : ' ');
+  vty_out (vty, "%5u   ", ntohs (lsp->lsp_header->pdu_len));
+  vty_out (vty, "0x%08x  ", ntohl (lsp->lsp_header->seq_num));
+  vty_out (vty, "0x%04x  ", ntohs (lsp->lsp_header->checksum));
   if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
-    vty_out (vty, " (%2u)", lsp->age_out);
+    {
+      snprintf (age_out, 8, "(%u)", lsp->age_out);
+      age_out[7] = '\0';
+      vty_out (vty, "%7s   ", age_out);
+    }
   else
-    vty_out (vty, "%5u", ntohs (lsp->lsp_header->rem_lifetime));
-
-  vty_out (vty, "         %s%s",
-          lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
+    vty_out (vty, " %5u    ", ntohs (lsp->lsp_header->rem_lifetime));
+  vty_out (vty, "%s%s",
+           lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
 }
 
-static void
-lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
+void
+lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {
-  struct isis_lsp *lsp = dnode_get (node);
   struct area_addr *area_addr;
   int i;
   struct listnode *lnode;
@@ -751,7 +841,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
   u_char ipv4_address[20];
 
   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
-  lsp_print (node, vty, dynhost);
+  lsp_print (lsp, vty, dynhost);
 
   /* for all area address */
   if (lsp->tlv_data.area_addrs)
@@ -771,11 +861,11 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
            {
            case NLPID_IP:
            case NLPID_IPV6:
-             vty_out (vty, "  NLPID:        0x%X%s",
+             vty_out (vty, "  NLPID       : 0x%X%s",
                       lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
              break;
            default:
-             vty_out (vty, "  NLPID:        %s%s", "unknown", VTY_NEWLINE);
+             vty_out (vty, "  NLPID       : %s%s", "unknown", VTY_NEWLINE);
              break;
            }
        }
@@ -784,33 +874,42 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
   /* for the hostname tlv */
   if (lsp->tlv_data.hostname)
     {
-      memset (hostname, 0, sizeof (hostname));
+      bzero (hostname, sizeof (hostname));
       memcpy (hostname, lsp->tlv_data.hostname->name,
              lsp->tlv_data.hostname->namelen);
-      vty_out (vty, "  Hostname: %s%s", hostname, VTY_NEWLINE);
+      vty_out (vty, "  Hostname    : %s%s", hostname, VTY_NEWLINE);
     }
 
-  if (lsp->tlv_data.ipv4_addrs)
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
-      {
-       memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
-       vty_out (vty, "  IP:        %s%s", ipv4_address, VTY_NEWLINE);
-      }
+  /* authentication tlv */
+  if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
+    {
+      if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
+        vty_out (vty, "  Auth type   : md5%s", VTY_NEWLINE);
+      else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
+        vty_out (vty, "  Auth type   : clear text%s", VTY_NEWLINE);
+    }
 
   /* TE router id */
   if (lsp->tlv_data.router_id)
     {
       memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
              sizeof (ipv4_address));
-      vty_out (vty, "  Router ID: %s%s", ipv4_address, VTY_NEWLINE);
+      vty_out (vty, "  Router ID   : %s%s", ipv4_address, VTY_NEWLINE);
     }
 
+  if (lsp->tlv_data.ipv4_addrs)
+    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
+      {
+        memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
+        vty_out (vty, "  IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
+      }
+
   /* for the IS neighbor tlv */
   if (lsp->tlv_data.is_neighs)
     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
       {
        lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
-       vty_out (vty, "  Metric: %-10d IS %s%s",
+       vty_out (vty, "  Metric      : %-8d IS            : %s%s",
                 is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
       }
   
@@ -823,7 +922,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
              sizeof (ipv4_reach_prefix));
       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
              sizeof (ipv4_reach_mask));
-      vty_out (vty, "  Metric: %-10d IP-Internal %s %s%s",
+      vty_out (vty, "  Metric      : %-8d IPv4-Internal : %s %s%s",
               ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
               ipv4_reach_mask, VTY_NEWLINE);
     }
@@ -837,7 +936,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
              sizeof (ipv4_reach_prefix));
       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
              sizeof (ipv4_reach_mask));
-      vty_out (vty, "  Metric: %-10d IP-External %s %s%s",
+      vty_out (vty, "  Metric      : %-8d IPv4-External : %s %s%s",
               ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
               ipv4_reach_mask, VTY_NEWLINE);
     }
@@ -853,11 +952,11 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
       inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
       if ((ipv6_reach->control_info &&
           CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
-       vty_out (vty, "  Metric: %-10d IPv6-Internal %s/%d%s",
+       vty_out (vty, "  Metric      : %-8d IPv6-Internal : %s/%d%s",
                 ntohl (ipv6_reach->metric),
                 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
       else
-       vty_out (vty, "  Metric: %-10d IPv6-External %s/%d%s",
+       vty_out (vty, "  Metric      : %-8d IPv6-External : %s/%d%s",
                 ntohl (ipv6_reach->metric),
                 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
     }
@@ -867,11 +966,9 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
   if (lsp->tlv_data.te_is_neighs)
     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
     {
-      uint32_t metric;
-      memcpy (&metric, te_is_neigh->te_metric, 3);
       lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
-      vty_out (vty, "  Metric: %-10d IS-Extended %s%s",
-              ntohl (metric << 8), LSPid, VTY_NEWLINE);
+      vty_out (vty, "  Metric      : %-8d IS-Extended   : %s%s",
+              GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
     }
 
   /* TE IPv4 tlv */
@@ -880,12 +977,13 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
                               te_ipv4_reach))
     {
       /* FIXME: There should be better way to output this stuff. */
-      vty_out (vty, "  Metric: %-10d IP-Extended %s/%d%s",
+      vty_out (vty, "  Metric      : %-8d IPv4-Extended : %s/%d%s",
               ntohl (te_ipv4_reach->te_metric),
               inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
                                            te_ipv4_reach->control)),
               te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
     }
+  vty_out (vty, "%s", VTY_NEWLINE);
 
   return;
 }
@@ -898,10 +996,6 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
   dnode_t *node = dict_first (lspdb), *next;
   int lsp_count = 0;
 
-  /* print the title, for both modes */
-  vty_out (vty, "LSP ID                   LSP Seq Num  LSP Checksum "
-          "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE);
-
   if (detail == ISIS_UI_LEVEL_BRIEF)
     {
       while (node != NULL)
@@ -909,7 +1003,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
          /* I think it is unnecessary, so I comment it out */
          /* dict_contains (lspdb, node); */
          next = dict_next (lspdb, node);
-         lsp_print (node, vty, dynhost);
+         lsp_print (dnode_get (node), vty, dynhost);
          node = next;
          lsp_count++;
        }
@@ -919,7 +1013,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
       while (node != NULL)
        {
          next = dict_next (lspdb, node);
-         lsp_print_detail (node, vty, dynhost);
+         lsp_print_detail (dnode_get (node), vty, dynhost);
          node = next;
          lsp_count++;
        }
@@ -929,7 +1023,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
 }
 
 #define FRAG_THOLD(S,T) \
-((STREAM_SIZE(S)*T)/100)
+  ((STREAM_SIZE(S)*T)/100)
 
 /* stream*, area->lsp_frag_threshold, increment */
 #define FRAG_NEEDED(S,T,I) \
@@ -948,16 +1042,32 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
   if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
     {
       tlv_build_func (*from, lsp->pdu);
-      *to = *from;
-      *from = NULL;
+      if (listcount (*to) != 0)
+       {
+         struct listnode *node, *nextnode;
+         void *elem;
+
+         for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
+           {
+             listnode_add (*to, elem);
+             list_delete_node (*from, node);
+           }
+       }
+      else
+       {
+         list_free (*to);
+         *to = *from;
+         *from = NULL;
+       }
     }
   else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
     {
       /* fit all we can */
       count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
        (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
-      if (count)
-       count = count / tlvsize;
+      count = count / tlvsize;
+      if (count > (int)listcount (*from))
+       count = listcount (*from);
       for (i = 0; i < count; i++)
        {
          listnode_add (*to, listgetdata (listhead (*from)));
@@ -969,6 +1079,44 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
   return;
 }
 
+static u_int16_t
+lsp_rem_lifetime (struct isis_area *area, int level)
+{
+  u_int16_t rem_lifetime;
+
+  /* Add jitter to configured LSP lifetime */
+  rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
+                              MAX_AGE_JITTER);
+
+  /* No jitter if the max refresh will be less than configure gen interval */
+  if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
+    rem_lifetime = area->max_lsp_lifetime[level - 1];
+
+  return rem_lifetime;
+}
+
+static u_int16_t
+lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
+{
+  struct isis_area *area = lsp->area;
+  int level = lsp->level;
+  u_int16_t refresh_time;
+
+  /* Add jitter to LSP refresh time */
+  refresh_time = isis_jitter (area->lsp_refresh[level - 1],
+                              MAX_LSP_GEN_JITTER);
+
+  /* RFC 4444 : make sure the refresh time is at least less than 300
+   * of the remaining lifetime and more than gen interval */
+  if (refresh_time <= area->lsp_gen_interval[level - 1] ||
+      refresh_time > (rem_lifetime - 300))
+    refresh_time = rem_lifetime - 300;
+
+  assert (area->lsp_gen_interval[level - 1] < refresh_time);
+
+  return refresh_time;
+}
+
 static struct isis_lsp *
 lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
               int level)
@@ -978,40 +1126,21 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
 
   memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
   LSP_FRAGMENT (frag_id) = frag_num;
+  /* FIXME add authentication TLV for fragment LSPs */
   lsp = lsp_search (frag_id, area->lspdb[level - 1]);
   if (lsp)
     {
-      /*
-       * Clear the TLVs, but inherit the authinfo
-       */
+      /* Clear the TLVs */
       lsp_clear_data (lsp);
-      if (lsp0->tlv_data.auth_info.type)
-       {
-         memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
-                 sizeof (struct isis_passwd));
-         tlv_add_authinfo (lsp->tlv_data.auth_info.type,
-                           lsp->tlv_data.auth_info.len,
-                           lsp->tlv_data.auth_info.passwd, lsp->pdu);
-       }
       return lsp;
     }
-  lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type,
-                0, level);
+  lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
+                 lsp_bits_generate (level, area->overload_bit), 0, level);
+  lsp->area = area;
   lsp->own_lsp = 1;
   lsp_insert (lsp, area->lspdb[level - 1]);
   listnode_add (lsp0->lspu.frags, lsp);
   lsp->lspu.zero_lsp = lsp0;
-  /*
-   * Copy the authinfo from zero LSP
-   */
-  if (lsp0->tlv_data.auth_info.type)
-    {
-      memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
-             sizeof (struct isis_passwd));
-      tlv_add_authinfo (lsp->tlv_data.auth_info.type,
-                       lsp->tlv_data.auth_info.len,
-                       lsp->tlv_data.auth_info.passwd, lsp->pdu);
-    }
   return lsp;
 }
 
@@ -1020,7 +1149,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
  * area->lsp_frag_threshold is exceeded.
  */
 static void
-lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+lsp_build (struct isis_lsp *lsp, struct isis_area *area)
 {
   struct is_neigh *is_neigh;
   struct te_is_neigh *te_is_neigh;
@@ -1037,8 +1166,27 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
 #endif /* HAVE_IPV6 */
   struct tlvs tlv_data;
   struct isis_lsp *lsp0 = lsp;
-  struct isis_passwd *passwd;
   struct in_addr *routerid;
+  uint32_t expected = 0, found = 0;
+  uint32_t metric;
+  u_char zero_id[ISIS_SYS_ID_LEN + 1];
+  int retval = ISIS_OK;
+
+  /*
+   * Building the zero lsp
+   */
+  memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
+
+  /* Reset stream endp. Stream is always there and on every LSP refresh only
+   * TLV part of it is overwritten. So we must seek past header we will not
+   * touch. */
+  stream_reset (lsp->pdu);
+  stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+
+  /*
+   * Add the authentication info if its present
+   */
+  lsp_auth_add (lsp);
 
   /*
    * First add the tlvs related to area
@@ -1048,6 +1196,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
   if (lsp->tlv_data.area_addrs == NULL)
     lsp->tlv_data.area_addrs = list_new ();
   list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
+  if (listcount (lsp->tlv_data.area_addrs) > 0)
+    tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
+
   /* Protocols Supported */
   if (area->ip_circuits > 0
 #ifdef HAVE_IPV6
@@ -1070,7 +1221,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
            NLPID_IPV6;
        }
 #endif /* HAVE_IPV6 */
+      tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
     }
+
   /* Dynamic Hostname */
   if (area->dynhostname)
     {
@@ -1080,39 +1233,13 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
       memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
              strlen (unix_hostname ()));
       lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
+      tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
     }
 
-  /*
-   * Building the zero lsp
-   */
-
-  /* Reset stream endp. Stream is always there and on every LSP refresh only
-   * TLV part of it is overwritten. So we must seek past header we will not
-   * touch. */
-  stream_reset (lsp->pdu);
-  stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-  /*
-   * Add the authentication info if its present
-   */
-  (level == 1) ? (passwd = &area->area_passwd) :
-    (passwd = &area->domain_passwd);
-  if (passwd->type)
-    {
-      memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
-      tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
-    }
-  if (lsp->tlv_data.nlpids)
-    tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
-  if (lsp->tlv_data.hostname)
-    tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
-  if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
-    tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
-
   /* IPv4 address and TE router ID TLVs. In case of the first one we don't
    * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
    * LSP and this address is same as router id. */
-  if (router_id_zebra.s_addr != 0)
+  if (isis->router_id != 0)
     {
       if (lsp->tlv_data.ipv4_addrs == NULL)
        {
@@ -1121,7 +1248,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
        }
 
       routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
-      routerid->s_addr = router_id_zebra.s_addr;
+      routerid->s_addr = isis->router_id;
       listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
       tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
 
@@ -1131,8 +1258,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
        {
          lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
                                             sizeof (struct in_addr));
-         lsp->tlv_data.router_id->id.s_addr = router_id_zebra.s_addr;
-         tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID);
+         lsp->tlv_data.router_id->id.s_addr = isis->router_id;
+         tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
+                           TE_ROUTER_ID);
        }
     }
 
@@ -1141,7 +1269,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
 #ifdef TOPOLOGY_GENERATE
   /* If topology exists (and we create topology for level 1 only), create
    * (hardcoded) link to topology. */
-  if (area->topology && level == 1)
+  if (area->topology && level == IS_LEVEL_1)
     {
       if (tlv_data.is_neighs == NULL)
        {
@@ -1192,7 +1320,6 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
                                            (ipv4->prefix.s_addr));
                  listnode_add (tlv_data.ipv4_int_reachs, ipreach);
                }
-             tlv_data.ipv4_int_reachs->del = free_tlv;
            }
          if (area->newmetric)
            {
@@ -1220,6 +1347,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
                }
            }
        }
+
 #ifdef HAVE_IPV6
       /*
        * Add IPv6 reachability of this circuit
@@ -1258,7 +1386,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
       switch (circuit->circ_type)
        {
        case CIRCUIT_T_BROADCAST:
-         if (level & circuit->circuit_is_type)
+         if (level & circuit->is_type)
            {
              if (area->oldmetric)
                {
@@ -1268,20 +1396,21 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
                      tlv_data.is_neighs->del = free_tlv;
                    }
                  is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
-                 if (level == 1)
+                 if (level == IS_LEVEL_1)
                    memcpy (is_neigh->neigh_id,
                            circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
                  else
                    memcpy (is_neigh->neigh_id,
                            circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
                  is_neigh->metrics = circuit->metrics[level - 1];
-                 listnode_add (tlv_data.is_neighs, is_neigh);
-                 tlv_data.is_neighs->del = free_tlv;
+                  if (!memcmp (is_neigh->neigh_id, zero_id,
+                               ISIS_SYS_ID_LEN + 1))
+                    XFREE (MTYPE_ISIS_TLV, is_neigh);
+                  else
+                    listnode_add (tlv_data.is_neighs, is_neigh);
                }
              if (area->newmetric)
                {
-                 uint32_t metric;
-
                  if (tlv_data.te_is_neighs == NULL)
                    {
                      tlv_data.te_is_neighs = list_new ();
@@ -1289,21 +1418,22 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
                    }
                  te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
                                         sizeof (struct te_is_neigh));
-                 if (level == 1)
+                 if (level == IS_LEVEL_1)
                    memcpy (te_is_neigh->neigh_id,
                            circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
                  else
                    memcpy (te_is_neigh->neigh_id,
                            circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
                  if (area->oldmetric)
-                   metric =
-                     ((htonl(circuit->metrics[level - 1].metric_default) >> 8)
-                             & 0xffffff);
+                   metric = circuit->metrics[level - 1].metric_default;
                  else
-                   metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
-
-                 memcpy (te_is_neigh->te_metric, &metric, 3);
-                 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
+                   metric = circuit->te_metric[level - 1];
+                 SET_TE_METRIC(te_is_neigh, metric);
+                  if (!memcmp (te_is_neigh->neigh_id, zero_id,
+                               ISIS_SYS_ID_LEN + 1))
+                    XFREE (MTYPE_ISIS_TLV, te_is_neigh);
+                  else
+                    listnode_add (tlv_data.te_is_neighs, te_is_neigh);
                }
            }
          break;
@@ -1335,21 +1465,14 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
                  te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
                                         sizeof (struct te_is_neigh));
                  memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
-                 metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
-                 memcpy (te_is_neigh->te_metric, &metric, 3);
+                 metric = circuit->te_metric[level - 1];
+                 SET_TE_METRIC(te_is_neigh, metric);
                  listnode_add (tlv_data.te_is_neighs, te_is_neigh);
                }
            }
          break;
-       case CIRCUIT_T_STATIC_IN:
-         zlog_warn ("lsp_area_create: unsupported circuit type");
-         break;
-       case CIRCUIT_T_STATIC_OUT:
-         zlog_warn ("lsp_area_create: unsupported circuit type");
-         break;
-       case CIRCUIT_T_DA:
-         zlog_warn ("lsp_area_create: unsupported circuit type");
-         break;
+       case CIRCUIT_T_LOOPBACK:
+          break;
        default:
          zlog_warn ("lsp_area_create: unknown circuit type");
        }
@@ -1367,6 +1490,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                             lsp0, area, level);
     }
+
   /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
    * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
    * TLVs (sub TLVs!). */
@@ -1376,7 +1500,8 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
        lsp->tlv_data.te_ipv4_reachs = list_new ();
       lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
                   &lsp->tlv_data.te_ipv4_reachs,
-                  9, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs);
+                  TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
+                  tlv_add_te_ipv4_reachs);
       if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                             lsp0, area, level);
@@ -1421,87 +1546,99 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                             lsp0, area, level);
     }
+  lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
 
   free_tlvs (&tlv_data);
+
+  /* Validate the LSP */
+  retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
+                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
+                       stream_get_endp (lsp->pdu) -
+                       ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
+                       &expected, &found, &tlv_data, NULL);
+  assert (retval == ISIS_OK);
+
   return;
 }
 
 /*
- * 7.3.7 Generation on non-pseudonode LSPs
+ * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
  */
-static int
-lsp_generate_non_pseudo (struct isis_area *area, int level)
+int
+lsp_generate (struct isis_area *area, int level)
 {
   struct isis_lsp *oldlsp, *newlsp;
   u_int32_t seq_num = 0;
   u_char lspid[ISIS_SYS_ID_LEN + 2];
+  u_int16_t rem_lifetime, refresh_time;
+
+  if ((area == NULL) || (area->is_type & level) != level)
+    return ISIS_ERROR;
 
   memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
   memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
 
   /* only builds the lsp if the area shares the level */
-  if ((area->is_type & level) == level)
-    {
-      oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
-      if (oldlsp)
-       {
-         seq_num = ntohl (oldlsp->lsp_header->seq_num);
-         lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
-                                 area->lspdb[level - 1]);
-         /* FIXME: we should actually initiate a purge */
-       }
-      newlsp = lsp_new (lspid, area->max_lsp_lifetime[level - 1], seq_num,
-                       area->is_type, 0, level);
-      newlsp->own_lsp = 1;
+  oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
+  if (oldlsp)
+    {
+      /* FIXME: we should actually initiate a purge */
+      seq_num = ntohl (oldlsp->lsp_header->seq_num);
+      lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
+                              area->lspdb[level - 1]);
+    }
+  rem_lifetime = lsp_rem_lifetime (area, level);
+  newlsp = lsp_new (lspid, rem_lifetime, seq_num,
+                    area->is_type | area->overload_bit, 0, level);
+  newlsp->area = area;
+  newlsp->own_lsp = 1;
+
+  lsp_insert (newlsp, area->lspdb[level - 1]);
+  /* build_lsp_data (newlsp, area); */
+  lsp_build (newlsp, area);
+  /* time to calculate our checksum */
+  lsp_seqnum_update (newlsp);
+  lsp_set_all_srmflags (newlsp);
+
+  refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
+  THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
+  if (level == IS_LEVEL_1)
+    THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+                     lsp_l1_refresh, area, refresh_time);
+  else if (level == IS_LEVEL_2)
+    THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+                     lsp_l2_refresh, area, refresh_time);
 
-      lsp_insert (newlsp, area->lspdb[level - 1]);
-      /* build_lsp_data (newlsp, area); */
-      lsp_build_nonpseudo (newlsp, area);
-      /* time to calculate our checksum */
-      lsp_seqnum_update (newlsp);
-    }
-
-  /* DEBUG_ADJ_PACKETS */
-  if (isis->debugs & DEBUG_ADJ_PACKETS)
+  if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
-      /* FIXME: is this place right? fix missing info */
-      zlog_debug ("ISIS-Upd (%s): Building L%d LSP", area->area_tag, level);
+      zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
+                  "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
+                  area->area_tag, level,
+                  rawlspid_print (newlsp->lsp_header->lsp_id),
+                  ntohl (newlsp->lsp_header->pdu_len),
+                  ntohl (newlsp->lsp_header->seq_num),
+                  ntohs (newlsp->lsp_header->checksum),
+                  ntohs (newlsp->lsp_header->rem_lifetime),
+                  refresh_time);
     }
 
   return ISIS_OK;
 }
 
 /*
- * 7.3.9 Generation of level 1 LSPs (non-pseudonode)
+ * Search own LSPs, update holding time and set SRM
  */
-int
-lsp_l1_generate (struct isis_area *area)
-{
-  THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,
-                  MAX_LSP_GEN_INTERVAL);
-
-  return lsp_generate_non_pseudo (area, 1);
-}
-
-/*
- * 7.3.9 Generation of level 2 LSPs (non-pseudonode)
- */
-int
-lsp_l2_generate (struct isis_area *area)
-{
-  THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,
-                  MAX_LSP_GEN_INTERVAL);
-
-  return lsp_generate_non_pseudo (area, 2);
-}
-
 static int
-lsp_non_pseudo_regenerate (struct isis_area *area, int level)
+lsp_regenerate (struct isis_area *area, int level)
 {
   dict_t *lspdb = area->lspdb[level - 1];
   struct isis_lsp *lsp, *frag;
   struct listnode *node;
   u_char lspid[ISIS_SYS_ID_LEN + 2];
+  u_int16_t rem_lifetime, refresh_time;
+
+  if ((area == NULL) || (area->is_type & level) != level)
+    return ISIS_ERROR;
 
   memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
   memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
@@ -1510,180 +1647,148 @@ lsp_non_pseudo_regenerate (struct isis_area *area, int level)
 
   if (!lsp)
     {
-      zlog_err
-       ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!",
-        area->area_tag, level);
-
+      zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
+                area->area_tag, level);
       return ISIS_ERROR;
     }
 
   lsp_clear_data (lsp);
-  lsp_build_nonpseudo (lsp, area);
-  lsp->lsp_header->rem_lifetime = htons (isis_jitter
-                                        (area->max_lsp_lifetime[level - 1],
-                                         MAX_AGE_JITTER));
+  lsp_build (lsp, area);
+  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit);
+  rem_lifetime = lsp_rem_lifetime (area, level);
+  lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
   lsp_seqnum_update (lsp);
 
-  if (isis->debugs & DEBUG_UPDATE_PACKETS)
+  lsp->last_generated = time (NULL);
+  lsp_set_all_srmflags (lsp);
+  for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
     {
-      zlog_debug ("ISIS-Upd (%s): refreshing our L%d LSP %s, "
-                 "seq 0x%08x, cksum 0x%04x lifetime %us",
-                 area->area_tag,
-                 level,
-                 rawlspid_print (lsp->lsp_header->lsp_id),
-                 ntohl (lsp->lsp_header->seq_num),
-                 ntohs (lsp->lsp_header->checksum),
-                 ntohs (lsp->lsp_header->rem_lifetime));
+      frag->lsp_header->lsp_bits = lsp_bits_generate (level,
+                                                      area->overload_bit);
+      /* Set the lifetime values of all the fragments to the same value,
+       * so that no fragment expires before the lsp is refreshed.
+       */
+      frag->lsp_header->rem_lifetime = htons (rem_lifetime);
+      lsp_set_all_srmflags (frag);
     }
 
-  lsp->last_generated = time (NULL);
-  area->lsp_regenerate_pending[level - 1] = 0;
-  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-  for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
+  refresh_time = lsp_refresh_time (lsp, rem_lifetime);
+  if (level == IS_LEVEL_1)
+    THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+                     lsp_l1_refresh, area, refresh_time);
+  else if (level == IS_LEVEL_2)
+    THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+                     lsp_l2_refresh, area, refresh_time);
+
+  if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
-      frag->lsp_header->rem_lifetime = htons (isis_jitter
-                                             (area->
-                                              max_lsp_lifetime[level - 1],
-                                              MAX_AGE_JITTER));
-      ISIS_FLAGS_SET_ALL (frag->SRMflags);
+      zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
+                  "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
+                  area->area_tag, level,
+                  rawlspid_print (lsp->lsp_header->lsp_id),
+                  ntohl (lsp->lsp_header->pdu_len),
+                  ntohl (lsp->lsp_header->seq_num),
+                  ntohs (lsp->lsp_header->checksum),
+                  ntohs (lsp->lsp_header->rem_lifetime),
+                  refresh_time);
     }
 
-  if (area->ip_circuits)
-    isis_spf_schedule (area, level);
-#ifdef HAVE_IPV6
-  if (area->ipv6_circuits)
-    isis_spf_schedule6 (area, level);
-#endif
   return ISIS_OK;
 }
 
 /*
- * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding
- * time and set SRM
+ * Something has changed or periodic refresh -> regenerate LSP
  */
-int
-lsp_refresh_l1 (struct thread *thread)
+static int
+lsp_l1_refresh (struct thread *thread)
 {
   struct isis_area *area;
-  unsigned long ref_time;
 
   area = THREAD_ARG (thread);
   assert (area);
 
   area->t_lsp_refresh[0] = NULL;
-  if (area->is_type & IS_LEVEL_1)
-    lsp_non_pseudo_regenerate (area, 1);
-
-  ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
+  area->lsp_regenerate_pending[0] = 0;
 
-  THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,
-                  isis_jitter (ref_time, MAX_AGE_JITTER));
+  if ((area->is_type & IS_LEVEL_1) == 0)
+    return ISIS_ERROR;
 
-  return ISIS_OK;
+  return lsp_regenerate (area, IS_LEVEL_1);
 }
 
-int
-lsp_refresh_l2 (struct thread *thread)
+static int
+lsp_l2_refresh (struct thread *thread)
 {
   struct isis_area *area;
-  unsigned long ref_time;
 
   area = THREAD_ARG (thread);
   assert (area);
 
   area->t_lsp_refresh[1] = NULL;
-  if (area->is_type & IS_LEVEL_2)
-    lsp_non_pseudo_regenerate (area, 2);
-
-  ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1];
-
-  THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,
-                  isis_jitter (ref_time, MAX_AGE_JITTER));
-
-  return ISIS_OK;
-}
-
-/*
- * Something has changed -> regenerate LSP
- */
-
-static int
-lsp_l1_regenerate (struct thread *thread)
-{
-  struct isis_area *area;
-
-  area = THREAD_ARG (thread);
-  area->lsp_regenerate_pending[0] = 0;
-
-  return lsp_non_pseudo_regenerate (area, 1);
-}
-
-static int
-lsp_l2_regenerate (struct thread *thread)
-{
-  struct isis_area *area;
-
-  area = THREAD_ARG (thread);
   area->lsp_regenerate_pending[1] = 0;
 
-  return lsp_non_pseudo_regenerate (area, 2);
+  if ((area->is_type & IS_LEVEL_2) == 0)
+    return ISIS_ERROR;
+
+  return lsp_regenerate (area, IS_LEVEL_2);
 }
 
 int
-lsp_regenerate_schedule (struct isis_area *area)
+lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
 {
   struct isis_lsp *lsp;
   u_char id[ISIS_SYS_ID_LEN + 2];
   time_t now, diff;
+  struct listnode *cnode;
+  struct isis_circuit *circuit;
+  int lvl;
+
+  if (area == NULL)
+    return ISIS_ERROR;
+
   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
   LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
   now = time (NULL);
-  /*
-   * First level 1
-   */
-  if (area->is_type & IS_LEVEL_1)
+
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
     {
-      lsp = lsp_search (id, area->lspdb[0]);
-      if (!lsp || area->lsp_regenerate_pending[0])
-       goto L2;
+      if (!((level & lvl) && (area->is_type & lvl)))
+        continue;
+
+      if (area->lsp_regenerate_pending[lvl - 1])
+        continue;
+
+      lsp = lsp_search (id, area->lspdb[lvl - 1]);
+      if (!lsp)
+        continue;
+
       /*
        * Throttle avoidance
        */
+      THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
       diff = now - lsp->last_generated;
-      if (diff < MIN_LSP_GEN_INTERVAL)
-       {
-         area->lsp_regenerate_pending[0] = 1;
-         area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area,
-                           MIN_LSP_GEN_INTERVAL - diff);
-         goto L2;
-       }
+      if (diff < area->lsp_gen_interval[lvl - 1])
+        {
+          area->lsp_regenerate_pending[lvl - 1] = 1;
+          if (lvl == IS_LEVEL_1)
+            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
+                             lsp_l1_refresh, area,
+                             area->lsp_gen_interval[lvl - 1] - diff);
+          else if (lvl == IS_LEVEL_2)
+            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
+                             lsp_l2_refresh, area,
+                             area->lsp_gen_interval[lvl - 1] - diff);
+        }
       else
-       lsp_non_pseudo_regenerate (area, 1);
+        {
+          lsp_regenerate (area, lvl);
+        }
     }
-  /*
-   * then 2
-   */
-L2:
-  if (area->is_type & IS_LEVEL_2)
+
+  if (all_pseudo)
     {
-      lsp = lsp_search (id, area->lspdb[1]);
-      if (!lsp || area->lsp_regenerate_pending[1])
-       return ISIS_OK;
-      /*
-       * Throttle avoidance
-       */
-      diff = now - lsp->last_generated;
-      if (diff < MIN_LSP_GEN_INTERVAL)
-       {
-         area->lsp_regenerate_pending[1] = 1;
-         area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area,
-                           MIN_LSP_GEN_INTERVAL - diff);
-         return ISIS_OK;
-       }
-      else
-       lsp_non_pseudo_regenerate (area, 2);
+      for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+        lsp_regenerate_schedule_pseudo (circuit, level);
     }
 
   return ISIS_OK;
@@ -1706,19 +1811,10 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
   struct es_neigh *es_neigh;
   struct list *adj_list;
   struct listnode *node;
-  struct isis_passwd *passwd;
-
-  assert (circuit);
-  assert (circuit->circ_type == CIRCUIT_T_BROADCAST);
-
-  if (!circuit->u.bc.is_dr[level - 1])
-    return;                    /* we are not DIS on this circuit */
 
   lsp->level = level;
-  if (level == 1)
-    lsp->lsp_header->lsp_bits |= IS_LEVEL_1;
-  else
-    lsp->lsp_header->lsp_bits |= IS_LEVEL_2;
+  /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
+  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0);
 
   /*
    * add self to IS neighbours 
@@ -1753,12 +1849,12 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
 
   for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
     {
-      if (adj->circuit_t & level)
+      if (adj->level & level)
        {
-         if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
-             (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
+         if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
+             (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
              adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
-             (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
+             (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
            {
              /* an IS neighbour -> add it */
              if (circuit->area->oldmetric)
@@ -1776,7 +1872,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
                  listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
                }
            }
-         else if (level == 1 && adj->sys_type == ISIS_SYSTYPE_ES)
+         else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
            {
              /* an ES neigbour add it, if we are building level 1 LSP */
              /* FIXME: the tlv-format is hard to use here */
@@ -1792,6 +1888,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
            }
        }
     }
+  list_delete (adj_list);
 
   /* Reset endp of stream to overwrite only TLV part of it. */
   stream_reset (lsp->pdu);
@@ -1800,13 +1897,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
   /*
    * Add the authentication info if it's present
    */
-  (level == 1) ? (passwd = &circuit->area->area_passwd) :
-    (passwd = &circuit->area->domain_passwd);
-  if (passwd->type)
-    {
-      memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
-      tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
-    }
+  lsp_auth_add (lsp);
 
   if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
     tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
@@ -1818,20 +1909,89 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
 
   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
-  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
-                  ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
-  list_delete (adj_list);
+  /* Recompute authentication and checksum information */
+  lsp_auth_update (lsp);
+  fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+                    ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
   return;
 }
 
+int
+lsp_generate_pseudo (struct isis_circuit *circuit, int level)
+{
+  dict_t *lspdb = circuit->area->lspdb[level - 1];
+  struct isis_lsp *lsp;
+  u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+  u_int16_t rem_lifetime, refresh_time;
+
+  if ((circuit->is_type & level) != level ||
+      (circuit->state != C_STATE_UP) ||
+      (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
+      (circuit->u.bc.is_dr[level - 1] == 0))
+    return ISIS_ERROR;
+
+  memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+  LSP_FRAGMENT (lsp_id) = 0;
+  LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
+
+  /*
+   * If for some reason have a pseudo LSP in the db already -> regenerate
+   */
+  if (lsp_search (lsp_id, lspdb))
+    return lsp_regenerate_schedule_pseudo (circuit, level);
+
+  rem_lifetime = lsp_rem_lifetime (circuit->area, level);
+  /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
+  lsp = lsp_new (lsp_id, rem_lifetime, 1, circuit->area->is_type, 0, level);
+  lsp->area = circuit->area;
+
+  lsp_build_pseudo (lsp, circuit, level);
+
+  lsp->own_lsp = 1;
+  lsp_insert (lsp, lspdb);
+  lsp_set_all_srmflags (lsp);
+
+  refresh_time = lsp_refresh_time (lsp, rem_lifetime);
+  THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+  circuit->lsp_regenerate_pending[level - 1] = 0;
+  if (level == IS_LEVEL_1)
+    THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+                     lsp_l1_refresh_pseudo, circuit, refresh_time);
+  else if (level == IS_LEVEL_2)
+    THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+                     lsp_l2_refresh_pseudo, circuit, refresh_time);
+
+  if (isis->debugs & DEBUG_UPDATE_PACKETS)
+    {
+      zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
+                  "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+                  circuit->area->area_tag, level,
+                  rawlspid_print (lsp->lsp_header->lsp_id),
+                  ntohl (lsp->lsp_header->pdu_len),
+                  ntohl (lsp->lsp_header->seq_num),
+                  ntohs (lsp->lsp_header->checksum),
+                  ntohs (lsp->lsp_header->rem_lifetime),
+                  refresh_time);
+    }
+
+  return ISIS_OK;
+}
+
 static int
-lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)
+lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
 {
   dict_t *lspdb = circuit->area->lspdb[level - 1];
   struct isis_lsp *lsp;
   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+  u_int16_t rem_lifetime, refresh_time;
+
+  if ((circuit->is_type & level) != level ||
+      (circuit->state != C_STATE_UP) ||
+      (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
+      (circuit->u.bc.is_dr[level - 1] == 0))
+    return ISIS_ERROR;
 
   memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
   LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
@@ -1841,151 +2001,154 @@ lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)
 
   if (!lsp)
     {
-      zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level,
-               rawlspid_print (lsp_id));
+      zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
+                level, rawlspid_print (lsp_id));
       return ISIS_ERROR;
     }
   lsp_clear_data (lsp);
 
   lsp_build_pseudo (lsp, circuit, level);
 
-  lsp->lsp_header->rem_lifetime =
-    htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1],
-                       MAX_AGE_JITTER));
-
+  /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
+  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0);
+  rem_lifetime = lsp_rem_lifetime (circuit->area, level);
+  lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
   lsp_inc_seqnum (lsp, 0);
+  lsp->last_generated = time (NULL);
+  lsp_set_all_srmflags (lsp);
+
+  refresh_time = lsp_refresh_time (lsp, rem_lifetime);
+  if (level == IS_LEVEL_1)
+    THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+                     lsp_l1_refresh_pseudo, circuit, refresh_time);
+  else if (level == IS_LEVEL_2)
+    THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+                     lsp_l2_refresh_pseudo, circuit, refresh_time);
 
   if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
-      zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s",
-                 circuit->area->area_tag, level,
-                 rawlspid_print (lsp->lsp_header->lsp_id));
+      zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
+                  "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+                  circuit->area->area_tag, level,
+                  rawlspid_print (lsp->lsp_header->lsp_id),
+                  ntohl (lsp->lsp_header->pdu_len),
+                  ntohl (lsp->lsp_header->seq_num),
+                  ntohs (lsp->lsp_header->checksum),
+                  ntohs (lsp->lsp_header->rem_lifetime),
+                  refresh_time);
     }
 
-  lsp->last_generated = time (NULL);
-  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-
   return ISIS_OK;
 }
 
-int
+/*
+ * Something has changed or periodic refresh -> regenerate pseudo LSP
+ */
+static int
 lsp_l1_refresh_pseudo (struct thread *thread)
 {
   struct isis_circuit *circuit;
-  int retval;
-  unsigned long ref_time;
+  u_char id[ISIS_SYS_ID_LEN + 2];
 
   circuit = THREAD_ARG (thread);
 
-  if (!circuit->u.bc.is_dr[0])
-    return ISIS_ERROR;         /* FIXME: purge and such */
-
   circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
+  circuit->lsp_regenerate_pending[0] = 0;
 
-  retval = lsp_pseudo_regenerate (circuit, 1);
-
-  ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
-
-  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0],
-                  lsp_l1_refresh_pseudo, circuit,
-                  isis_jitter (ref_time, MAX_AGE_JITTER));
-
-  return retval;
-}
-
-int
-lsp_l1_pseudo_generate (struct isis_circuit *circuit)
-{
-  struct isis_lsp *lsp;
-  u_char id[ISIS_SYS_ID_LEN + 2];
-  unsigned long ref_time;
-
-  memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
-  LSP_FRAGMENT (id) = 0;
-  LSP_PSEUDO_ID (id) = circuit->circuit_id;
-
-  /*
-   * If for some reason have a pseudo LSP in the db already -> regenerate
-   */
-  if (lsp_search (id, circuit->area->lspdb[0]))
-    return lsp_pseudo_regenerate (circuit, 1);
-  lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0],
-                1, circuit->area->is_type, 0, 1);
-
-  lsp_build_pseudo (lsp, circuit, 1);
-
-  lsp->own_lsp = 1;
-  lsp_insert (lsp, circuit->area->lspdb[0]);
-  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-
-  ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
-
-  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0],
-                  lsp_l1_refresh_pseudo, circuit,
-                  isis_jitter (ref_time, MAX_AGE_JITTER));
+  if ((circuit->u.bc.is_dr[0] == 0) ||
+      (circuit->is_type & IS_LEVEL_1) == 0)
+    {
+      memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
+      LSP_PSEUDO_ID (id) = circuit->circuit_id;
+      LSP_FRAGMENT (id) = 0;
+      lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
+      return ISIS_ERROR;
+    }
 
-  return lsp_regenerate_schedule (circuit->area);
+  return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
 }
 
-int
+static int
 lsp_l2_refresh_pseudo (struct thread *thread)
 {
   struct isis_circuit *circuit;
-  int retval;
-  unsigned long ref_time;
-  circuit = THREAD_ARG (thread);
+  u_char id[ISIS_SYS_ID_LEN + 2];
 
-  if (!circuit->u.bc.is_dr[1])
-    return ISIS_ERROR;         /* FIXME: purge and such */
+  circuit = THREAD_ARG (thread);
 
   circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
+  circuit->lsp_regenerate_pending[1] = 0;
 
-  retval = lsp_pseudo_regenerate (circuit, 2);
-
-  ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
-
-  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],
-                  lsp_l2_refresh_pseudo, circuit,
-                  isis_jitter (ref_time, MAX_AGE_JITTER));
+  if ((circuit->u.bc.is_dr[1] == 0) ||
+      (circuit->is_type & IS_LEVEL_2) == 0)
+    {
+      memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
+      LSP_PSEUDO_ID (id) = circuit->circuit_id;
+      LSP_FRAGMENT (id) = 0;
+      lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
+      return ISIS_ERROR;
+    }
 
-  return retval;
+  return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
 }
 
 int
-lsp_l2_pseudo_generate (struct isis_circuit *circuit)
+lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
 {
   struct isis_lsp *lsp;
-  u_char id[ISIS_SYS_ID_LEN + 2];
-  unsigned long ref_time;
-
-  memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
-  LSP_FRAGMENT (id) = 0;
-  LSP_PSEUDO_ID (id) = circuit->circuit_id;
-
-  if (lsp_search (id, circuit->area->lspdb[1]))
-    return lsp_pseudo_regenerate (circuit, 2);
+  u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+  time_t now, diff;
+  int lvl;
 
-  lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1],
-                1, circuit->area->is_type, 0, 2);
+  if (circuit == NULL ||
+      circuit->circ_type != CIRCUIT_T_BROADCAST ||
+      circuit->state != C_STATE_UP)
+    return ISIS_OK;
 
-  lsp_build_pseudo (lsp, circuit, 2);
+  memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+  LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
+  LSP_FRAGMENT (lsp_id) = 0;
+  now = time (NULL);
 
-  ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
+    {
+      if (!((level & lvl) && (circuit->is_type & lvl)))
+        continue;
 
+      if (circuit->u.bc.is_dr[lvl - 1] == 0 ||
+          circuit->lsp_regenerate_pending[lvl - 1])
+        continue;
 
-  lsp->own_lsp = 1;
-  lsp_insert (lsp, circuit->area->lspdb[1]);
-  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+      lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
+      if (!lsp)
+        continue;
 
-  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],
-                  lsp_l2_refresh_pseudo, circuit,
-                  isis_jitter (ref_time, MAX_AGE_JITTER));
+      /*
+       * Throttle avoidance
+       */
+      THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
+      diff = now - lsp->last_generated;
+      if (diff < circuit->area->lsp_gen_interval[lvl - 1])
+        {
+          circuit->lsp_regenerate_pending[lvl - 1] = 1;
+          if (lvl == IS_LEVEL_1)
+            THREAD_TIMER_ON (master,
+                             circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
+                             lsp_l1_refresh_pseudo, circuit,
+                             circuit->area->lsp_gen_interval[lvl - 1] - diff);
+          else if (lvl == IS_LEVEL_2)
+            THREAD_TIMER_ON (master,
+                             circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
+                             lsp_l2_refresh_pseudo, circuit,
+                             circuit->area->lsp_gen_interval[lvl - 1] - diff);
+        }
+      else
+        {
+          lsp_regenerate_pseudo (circuit, lvl);
+        }
+    }
 
-  return lsp_regenerate_schedule (circuit->area);
+  return ISIS_OK;
 }
 
 /*
@@ -2003,6 +2166,7 @@ lsp_tick (struct thread *thread)
   struct listnode *lspnode, *cnode;
   dnode_t *dnode, *dnode_next;
   int level;
+  u_int16_t rem_lifetime;
 
   lsp_list = list_new ();
 
@@ -2018,56 +2182,87 @@ lsp_tick (struct thread *thread)
   for (level = 0; level < ISIS_LEVELS; level++)
     {
       if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
-       {
-         dnode = dict_first (area->lspdb[level]);
-         while (dnode != NULL)
-           {
-             dnode_next = dict_next (area->lspdb[level], dnode);
-             lsp = dnode_get (dnode);
-             lsp_set_time (lsp);
-             if (lsp->age_out == 0)
-               {
-
-                 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
-                             area->area_tag,
-                             lsp->level,
-                             rawlspid_print (lsp->lsp_header->lsp_id),
-                             ntohl (lsp->lsp_header->seq_num));
+        {
+          for (dnode = dict_first (area->lspdb[level]);
+               dnode != NULL; dnode = dnode_next)
+            {
+              dnode_next = dict_next (area->lspdb[level], dnode);
+              lsp = dnode_get (dnode);
+
+              /*
+               * The lsp rem_lifetime is kept at 0 for MaxAge or
+               * ZeroAgeLifetime depending on explicit purge or
+               * natural age out. So schedule spf only once when
+               * the first time rem_lifetime becomes 0.
+               */
+              rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
+              lsp_set_time (lsp);
+
+              /*
+               * Schedule may run spf which should be done only after
+               * the lsp rem_lifetime becomes 0 for the first time.
+               * ISO 10589 - 7.3.16.4 first paragraph.
+               */
+              if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
+                {
+                  /* 7.3.16.4 a) set SRM flags on all */
+                  lsp_set_all_srmflags (lsp);
+                  /* 7.3.16.4 b) retain only the header FIXME  */
+                  /* 7.3.16.4 c) record the time to purge FIXME */
+                  /* run/schedule spf */
+                  /* isis_spf_schedule is called inside lsp_destroy() below;
+                   * so it is not needed here. */
+                  /* isis_spf_schedule (lsp->area, lsp->level); */
+                }
+
+              if (lsp->age_out == 0)
+                {
+                  zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
+                              area->area_tag,
+                              lsp->level,
+                              rawlspid_print (lsp->lsp_header->lsp_id),
+                              ntohl (lsp->lsp_header->seq_num));
 #ifdef TOPOLOGY_GENERATE
-                 if (lsp->from_topology)
-                   THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
+                  if (lsp->from_topology)
+                    THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
 #endif /* TOPOLOGY_GENERATE */
-                 lsp_destroy (lsp);
-                 dict_delete (area->lspdb[level], dnode);
-               }
-             else if (flags_any_set (lsp->SRMflags))
-               listnode_add (lsp_list, lsp);
-             dnode = dnode_next;
-           }
-
-         /*
-          * Send LSPs on circuits indicated by the SRMflags
-          */
-         if (listcount (lsp_list) > 0)
-           {
+                  lsp_destroy (lsp);
+                  lsp = NULL;
+                  dict_delete_free (area->lspdb[level], dnode);
+                }
+              else if (flags_any_set (lsp->SRMflags))
+                listnode_add (lsp_list, lsp);
+            }
+
+          /*
+           * Send LSPs on circuits indicated by the SRMflags
+           */
+          if (listcount (lsp_list) > 0)
+            {
               for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
-               {
-                 if (circuit->state != C_STATE_UP)
-                   continue;
+                {
+                  int diff = time (NULL) - circuit->lsp_queue_last_cleared;
+                  if (circuit->lsp_queue == NULL ||
+                      diff < MIN_LSP_TRANS_INTERVAL)
+                    continue;
                   for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
-                   {
-                     if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
-                       {
-                         /* FIXME: if same or elder lsp is already in lsp
-                          * queue */
-                         listnode_add (circuit->lsp_queue, lsp);
-                         thread_add_event (master, send_lsp, circuit, 0);
-                       }
-                   }
-               }
-           }
-         list_delete_all_node (lsp_list);
-       }
+                    {
+                      if (circuit->upadjcount[lsp->level - 1] &&
+                          ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
+                        {
+                          /* Add the lsp only if it is not already in lsp
+                           * queue */
+                          if (! listnode_lookup (circuit->lsp_queue, lsp))
+                            {
+                              listnode_add (circuit->lsp_queue, lsp);
+                              thread_add_event (master, send_lsp, circuit, 0);
+                            }
+                        }
+                    }
+                }
+              list_delete_all_node (lsp_list);
+            }
+        }
     }
 
   list_delete (lsp_list);
@@ -2076,22 +2271,45 @@ lsp_tick (struct thread *thread)
 }
 
 void
-lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level)
+lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
 {
   struct isis_lsp *lsp;
+  u_int16_t seq_num;
+  u_int8_t lsp_bits;
 
   lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
+  if (!lsp)
+    return;
 
-  if (lsp && lsp->purged == 0)
-    {
-      lsp->lsp_header->rem_lifetime = htons (0);
-      lsp->lsp_header->pdu_len =
-       htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-      lsp->purged = 0;
-      fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
-                      ntohs (lsp->lsp_header->pdu_len) - 12, 12);
-      ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-    }
+  /* store old values */
+  seq_num = lsp->lsp_header->seq_num;
+  lsp_bits = lsp->lsp_header->lsp_bits;
+
+  /* reset stream */
+  lsp_clear_data (lsp);
+  stream_reset (lsp->pdu);
+
+  /* update header */
+  lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+  memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
+  lsp->lsp_header->checksum = 0;
+  lsp->lsp_header->seq_num = seq_num;
+  lsp->lsp_header->rem_lifetime = 0;
+  lsp->lsp_header->lsp_bits = lsp_bits;
+  lsp->level = level;
+  lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
+  stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+
+  /*
+   * Add and update the authentication info if its present
+   */
+  lsp_auth_add (lsp);
+  lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+  lsp_auth_update (lsp);
+  fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+                    ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+
+  lsp_set_all_srmflags (lsp);
 
   return;
 }
@@ -2109,27 +2327,36 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
   /*
    * We need to create the LSP to be purged 
    */
-  zlog_debug ("LSP PURGE NON EXIST");
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
-  /*FIXME: BUG BUG BUG! the lsp doesn't exist here! */
-  /*did smt here, maybe good probably not */
-  lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;
-  lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+  lsp->area = area;
+  lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ?
+    IS_LEVEL_1 : IS_LEVEL_2;
+  /* FIXME: Should be minimal mtu? */
+  lsp->pdu = stream_new (1500);
   lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
-  fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE
+  fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
                  : L2_LINK_STATE);
   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
                                                    ISIS_FIXED_HDR_LEN);
   memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
+  stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
 
-  /*
-   * Retain only LSP header
-   */
-  lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
   /*
    * Set the remaining lifetime to 0
    */
   lsp->lsp_header->rem_lifetime = 0;
+
+  /*
+   * Add and update the authentication info if its present
+   */
+  lsp_auth_add (lsp);
+  lsp_auth_update (lsp);
+
+  /*
+   * Update the PDU length to header plus any authentication TLV.
+   */
+  lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+
   /*
    * Put the lsp into LSPdb
    */
@@ -2138,17 +2365,36 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
   /*
    * Send in to whole area
    */
-  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+  lsp_set_all_srmflags (lsp);
 
   return;
 }
 
+void lsp_set_all_srmflags (struct isis_lsp *lsp)
+{
+  struct listnode *node;
+  struct isis_circuit *circuit;
+
+  assert (lsp);
+
+  ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
+
+  if (lsp->area)
+    {
+      struct list *circuit_list = lsp->area->circuit_list;
+      for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
+        {
+          ISIS_SET_FLAG(lsp->SRMflags, circuit);
+        }
+    }
+}
+
 #ifdef TOPOLOGY_GENERATE
 static int
 top_lsp_refresh (struct thread *thread)
 {
   struct isis_lsp *lsp;
-  unsigned long ref_time;
+  u_int16_t rem_lifetime, refresh_time;
 
   lsp = THREAD_ARG (thread);
   assert (lsp);
@@ -2157,7 +2403,7 @@ top_lsp_refresh (struct thread *thread)
 
   lsp_seqnum_update (lsp);
 
-  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+  lsp_set_all_srmflags (lsp);
   if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
       zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
@@ -2167,14 +2413,14 @@ top_lsp_refresh (struct thread *thread)
   isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
                     IS_LEVEL_1);
 
-  lsp->lsp_header->rem_lifetime =
-    htons (isis_jitter (lsp->area->max_lsp_lifetime[0], MAX_AGE_JITTER));
-
-  ref_time = lsp->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
-    MAX_LSP_GEN_INTERVAL : lsp->area->lsp_refresh[0];
+  lsp->lsp_header->lsp_bits = lsp_bits_generate (level,
+                                                 lsp->area->overload_bit);
+  rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
+  lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
 
+  refresh_time = lsp_refresh_time (lsp, rem_lifetime);
   THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
-                  isis_jitter (ref_time, MAX_LSP_GEN_JITTER));
+                  lsp->area->lsp_refresh[0]);
 
   return ISIS_OK;
 }
@@ -2187,16 +2433,16 @@ generate_topology_lsps (struct isis_area *area)
   struct arc *arc;
   u_char lspid[ISIS_SYS_ID_LEN + 2];
   struct isis_lsp *lsp;
-  unsigned long ref_time;
+  u_int16_t rem_lifetime, refresh_time;
 
   /* first we find the maximal node */
   for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
-  {
-    if (arc->from_node > max)
-      max = arc->from_node;
-    if (arc->to_node > max)
-      max = arc->to_node;
-  }
+    {
+      if (arc->from_node > max)
+        max = arc->from_node;
+      if (arc->to_node > max)
+        max = arc->to_node;
+    }
 
   for (i = 1; i < (max + 1); i++)
     {
@@ -2206,12 +2452,13 @@ generate_topology_lsps (struct isis_area *area)
       lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
       lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
 
-      lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0],
-                    MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1);
+      rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
+      lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit,
+                     0, 1);
       if (!lsp)
        return;
-      lsp->from_topology = 1;
       lsp->area = area;
+      lsp->from_topology = 1;
 
       /* Creating LSP data based on topology info. */
       build_topology_lsp_data (lsp, area, i);
@@ -2220,12 +2467,10 @@ generate_topology_lsps (struct isis_area *area)
       /* Take care of inserting dynamic hostname into cache. */
       isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
 
-      ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
-       MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
-
+      refresh_time = lsp_refresh_time (lsp, rem_lifetime);
       THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
-                      isis_jitter (ref_time, MAX_LSP_GEN_JITTER));
-      ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+                      refresh_time);
+      lsp_set_all_srmflags (lsp);
       lsp_insert (lsp, area->lspdb[0]);
     }
 }
@@ -2342,8 +2587,6 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
 
       if (area->newmetric)
        {
-         uint32_t metric;
-
          if (tlv_data.te_is_neighs == NULL)
            {
              tlv_data.te_is_neighs = list_new ();
@@ -2354,8 +2597,7 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
                  ISIS_SYS_ID_LEN);
          te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
          te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
-         metric = ((htonl(arc->distance) >> 8) & 0xffffff);
-         memcpy (te_is_neigh->te_metric, &metric, 3);
+         SET_TE_METRIC(te_is_neigh, arc->distance);
          listnode_add (tlv_data.te_is_neighs, te_is_neigh);
        }
     }
index 8d648d059f5725435b3303c8d8afa9e347c72aae..6e7f745d2a3e2dbdde7a59c5e7022bb1f33aa06c 100644 (file)
 #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,7 +52,6 @@ struct isis_lsp
 #endif
   /* used for 60 second counting when rem_lifetime is zero */
   int age_out;
-  /* 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 */
 };
@@ -67,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);
 
@@ -114,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);
index 15d85d6def45e4f4843ffebdaeb1a587cf72594d..7bb84d8fc2d2d1f5af3dcb94ed858d3ea147b2a0 100644 (file)
@@ -34,7 +34,6 @@
 #include "privs.h"
 #include "sigevent.h"
 #include "filter.h"
-#include "zclient.h"
 
 #include "isisd/dict.h"
 #include "include-netbsd/iso.h"
@@ -44,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"
@@ -67,23 +69,22 @@ 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
 };
 
 /* isisd options */
 struct option longopts[] = {
-  {"daemon",      no_argument,       NULL, 'd'},
+  {"daemon", no_argument, NULL, 'd'},
   {"config_file", required_argument, NULL, 'f'},
-  {"pid_file",    required_argument, NULL, 'i'},
-  {"socket",      required_argument, NULL, 'z'},
-  {"vty_addr",    required_argument, NULL, 'A'},
-  {"vty_port",    required_argument, NULL, 'P'},
-  {"user",        required_argument, NULL, 'u'},
-  {"group",       required_argument, NULL, 'g'},
-  {"version",     no_argument,       NULL, 'v'},
-  {"dryrun",      no_argument,       NULL, 'C'},
-  {"help",        no_argument,       NULL, 'h'},
+  {"pid_file", required_argument, NULL, 'i'},
+  {"vty_addr", required_argument, NULL, 'A'},
+  {"vty_port", required_argument, NULL, 'P'},
+  {"user", required_argument, NULL, 'u'},
+  {"group", required_argument, NULL, 'g'},
+  {"version", no_argument, NULL, 'v'},
+  {"dryrun", no_argument, NULL, 'C'},
+  {"help", no_argument, NULL, 'h'},
   {0}
 };
 
@@ -132,7 +133,6 @@ Daemon which manages IS-IS routing\n\n\
 -d, --daemon       Runs in daemon mode\n\
 -f, --config_file  Set configuration file name\n\
 -i, --pid_file     Set process identifier file name\n\
--z, --socket       Set path of zebra socket\n\
 -A, --vty_addr     Set vty's bind address\n\
 -P, --vty_port     Set vty's port number\n\
 -u, --user         User to run as\n\
@@ -154,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
@@ -249,7 +252,7 @@ main (int argc, char **argv, char **envp)
   /* Command line argument treatment. */
   while (1)
     {
-      opt = getopt_long (argc, argv, "df:i:z:hA:p:P:u:g:vC", longopts, 0);
+      opt = getopt_long (argc, argv, "df:i:hA:p:P:u:g:vC", longopts, 0);
 
       if (opt == EOF)
        break;
@@ -267,9 +270,6 @@ main (int argc, char **argv, char **envp)
        case 'i':
          pid_file = optarg;
          break;
-       case 'z':
-         zclient_serv_path_set (optarg);
-         break;
        case 'A':
          vty_addr = optarg;
          break;
@@ -325,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);
index 6b565bcbe23a5b2b0659f8afa96e72e88b2883fc..968fa05fe360e4231445723e3ec51cf607264e1b 100644 (file)
@@ -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)
@@ -289,6 +292,42 @@ string2circuit_t (const u_char * str)
   return 0;
 }
 
+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)
 {
@@ -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;
+}
index d5003a8e68ccb31ced677666e1b14c6e59885961..0cd65a66ae5be1f00852a951f099c551fb37ab36 100644 (file)
 #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 */
 
index d67df31baa9bad99f98986b14d95d81ccd07d8a6..497fad20fd215fa84134e62382f9499aefa4388a 100644 (file)
 #include "isisd/include-netbsd/iso.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_network.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
 #include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
@@ -54,9 +54,6 @@
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
 
-extern struct thread_master *master;
-extern struct isis *isis;
-
 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
 #define ISIS_MIN_PDU_LEN           13  /* partial seqnum pdu with id_len=2 */
 
@@ -65,7 +62,7 @@ extern struct isis *isis;
 #endif /* PNBBY */
 
 /* Utility mask array. */
-static const u_char maskbit[] = {
+static u_char maskbit[] = {
   0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
 };
 
@@ -169,43 +166,151 @@ accept_level (int level, int circuit_t)
   return retval;
 }
 
-
 /*
  * Verify authentication information
  * Support cleartext and HMAC MD5 authentication
  */
-int
-authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c)
+static int
+authentication_check (struct isis_passwd *remote, struct isis_passwd *local,
+                      struct stream *stream, uint32_t auth_tlv_offset)
 {
   unsigned char digest[ISIS_AUTH_MD5_SIZE];
 
-  if (c->passwd.type)
-    {
-      switch (c->passwd.type)
-    {
-         case ISIS_PASSWD_TYPE_HMAC_MD5:
-           /* HMAC MD5 (RFC 3567) */
-           /* MD5 computation according to RFC 2104 */
-           hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), (unsigned char *) &(local->passwd), c->passwd.len, (unsigned char *) &digest);
-           return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
-           break;
-    case ISIS_PASSWD_TYPE_CLEARTXT:
-           /* Cleartext (ISO 10589) */
-           if (local->len != remote->len)
-       return 1;               /* Auth fail () - passwd len mismatch */
-           return memcmp (local->passwd, remote->passwd, local->len);
+  /* Auth fail () - passwd type mismatch */
+  if (local->type != remote->type)
+    return ISIS_ERROR;
+
+  switch (local->type)
+  {
+    /* No authentication required */
+    case ISIS_PASSWD_TYPE_UNUSED:
       break;
+
+    /* Cleartext (ISO 10589) */
+    case ISIS_PASSWD_TYPE_CLEARTXT:
+      /* Auth fail () - passwd len mismatch */
+      if (remote->len != local->len)
+        return ISIS_ERROR;
+      return memcmp (local->passwd, remote->passwd, local->len);
+
+    /* HMAC MD5 (RFC 3567) */
+    case ISIS_PASSWD_TYPE_HMAC_MD5:
+      /* Auth fail () - passwd len mismatch */
+      if (remote->len != ISIS_AUTH_MD5_SIZE)
+        return ISIS_ERROR;
+      /* Set the authentication value to 0 before the check */
+      memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0,
+              ISIS_AUTH_MD5_SIZE);
+      /* Compute the digest */
+      hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream),
+                (unsigned char *) &(local->passwd), local->len,
+                (caddr_t) &digest);
+      /* Copy back the authentication value after the check */
+      memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3,
+              remote->passwd, ISIS_AUTH_MD5_SIZE);
+      return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
+
     default:
-      zlog_warn ("Unsupported authentication type");
-      break;
+      zlog_err ("Unsupported authentication type");
+      return ISIS_ERROR;
+  }
+
+  /* Authentication pass when no authentication is configured */
+  return ISIS_OK;
+}
+
+static int
+lsp_authentication_check (struct stream *stream, struct isis_area *area,
+                          int level, struct isis_passwd *passwd)
+{
+  struct isis_link_state_hdr *hdr;
+  uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
+  uint16_t checksum, rem_lifetime, pdu_len;
+  struct tlvs tlvs;
+  int retval = ISIS_OK;
+
+  hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream));
+  pdu_len = ntohs (hdr->pdu_len);
+  expected |= TLVFLAG_AUTH_INFO;
+  auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN;
+  retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN,
+                       pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
+                       &expected, &found, &tlvs, &auth_tlv_offset);
+
+  if (retval != ISIS_OK)
+    {
+      zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
+                "cksum 0x%04x, lifetime %us, len %u",
+                area->area_tag, level, rawlspid_print (hdr->lsp_id),
+                ntohl (hdr->seq_num), ntohs (hdr->checksum),
+                ntohs (hdr->rem_lifetime), pdu_len);
+      if ((isis->debugs & DEBUG_UPDATE_PACKETS) &&
+          (isis->debugs & DEBUG_PACKET_DUMP))
+        zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream));
+      return retval;
+    }
+
+  if (!(found & TLVFLAG_AUTH_INFO))
+    {
+      zlog_err ("No authentication tlv in LSP");
+      return ISIS_ERROR;
     }
+
+  if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT &&
+      tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)
+    {
+      zlog_err ("Unknown authentication type in LSP");
+      return ISIS_ERROR;
     }
-  return 0; /* Authentication pass when no authentication is configured */
+
+  /*
+   * RFC 5304 set checksum and remaining lifetime to zero before
+   * verification and reset to old values after verification.
+   */
+  checksum = hdr->checksum;
+  rem_lifetime = hdr->rem_lifetime;
+  hdr->checksum = 0;
+  hdr->rem_lifetime = 0;
+  retval = authentication_check (&tlvs.auth_info, passwd, stream,
+                                 auth_tlv_offset);
+  hdr->checksum = checksum;
+  hdr->rem_lifetime = rem_lifetime;
+
+  return retval;
 }
 
 /*
  * Processing helper functions
  */
+static void
+del_addr (void *val)
+{
+  XFREE (MTYPE_ISIS_TMP, val);
+}
+
+static void
+tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
+{
+  struct listnode *node;
+  struct area_addr *area_addr, *malloced;
+
+  if (adj->area_addrs)
+    {
+      adj->area_addrs->del = del_addr;
+      list_delete (adj->area_addrs);
+    }
+  adj->area_addrs = list_new ();
+  if (tlvs->area_addrs)
+    {
+      for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr))
+      {
+       malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr));
+       memcpy (malloced, area_addr, sizeof (struct area_addr));
+       listnode_add (adj->area_addrs, malloced);
+      }
+    }
+}
+
 static void
 tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
 {
@@ -226,12 +331,6 @@ tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
     }
 }
 
-static void
-del_ip_addr (void *val)
-{
-  XFREE (MTYPE_ISIS_TMP, val);
-}
-
 static void
 tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
 {
@@ -240,7 +339,7 @@ tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
 
   if (adj->ipv4_addrs)
     {
-      adj->ipv4_addrs->del = del_ip_addr;
+      adj->ipv4_addrs->del = del_addr;
       list_delete (adj->ipv4_addrs);
     }
   adj->ipv4_addrs = list_new ();
@@ -264,7 +363,7 @@ tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
 
   if (adj->ipv6_addrs)
     {
-      adj->ipv6_addrs->del = del_ip_addr;
+      adj->ipv6_addrs->del = del_addr;
       list_delete (adj->ipv6_addrs);
     }
   adj->ipv6_addrs = list_new ();
@@ -297,9 +396,26 @@ process_p2p_hello (struct isis_circuit *circuit)
   int retval = ISIS_OK;
   struct isis_p2p_hello_hdr *hdr;
   struct isis_adjacency *adj;
-  u_int32_t expected = 0, found;
+  u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
+  uint16_t pdu_len;
   struct tlvs tlvs;
 
+  if (isis->debugs & DEBUG_ADJ_PACKETS)
+    {
+      zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
+                  circuit->area->area_tag, circuit->interface->name,
+                  circuit_t2string (circuit->is_type), circuit->circuit_id);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+                        stream_get_endp (circuit->rcv_stream));
+    }
+
+  if (circuit->circ_type != CIRCUIT_T_P2P)
+    {
+      zlog_warn ("p2p hello on non p2p circuit");
+      return ISIS_WARNING;
+    }
+
   if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
     {
@@ -324,42 +440,25 @@ process_p2p_hello (struct isis_circuit *circuit)
    * Get the header
    */
   hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
-  circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN;
-
-  /*  hdr.circuit_t = stream_getc (stream);
-     stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
-     hdr.hold_time = stream_getw (stream);
-     hdr.pdu_len   = stream_getw (stream);
-     hdr.local_id  = stream_getc (stream); */
+  pdu_len = ntohs (hdr->pdu_len);
 
-  /*
-   * My interpertation of the ISO, if no adj exists we will create one for 
-   * the circuit
-   */
-
-  if (isis->debugs & DEBUG_ADJ_PACKETS)
+  if (pdu_len > ISO_MTU(circuit) ||
+      pdu_len > stream_get_endp (circuit->rcv_stream))
     {
-      zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
-                 " cir id %02d, length %d",
-                 circuit->area->area_tag, circuit->interface->name,
-                 circuit_t2string (circuit->circuit_is_type),
-                 circuit->circuit_id, ntohs (hdr->pdu_len));
+      zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
+                 "invalid pdu length %d",
+                 circuit->area->area_tag, circuit->interface->name, pdu_len);
+      return ISIS_WARNING;
     }
 
-  adj = circuit->u.p2p.neighbor;
-  if (!adj)
-    {
-      adj = isis_new_adj (hdr->source_id, NULL, 0, circuit);
-      if (adj == NULL)
-       return ISIS_ERROR;
-      circuit->u.p2p.neighbor = adj;
-      isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
-      adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
-    }
+  /*
+   * Set the stream endp to PDU length, ignoring additional padding
+   * introduced by transport chips.
+   */
+  if (pdu_len < stream_get_endp (circuit->rcv_stream))
+    stream_set_endp (circuit->rcv_stream, pdu_len);
 
-  /* 8.2.6 Monitoring point-to-point adjacencies */
-  adj->hold_time = ntohs (hdr->hold_time);
-  adj->last_upd = time (NULL);
+  stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
 
   /*
    * Lets get the TLVS now
@@ -370,37 +469,93 @@ process_p2p_hello (struct isis_circuit *circuit)
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;
 
+  auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
                       STREAM_PNT (circuit->rcv_stream),
-                      ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN
-                      - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);
+                      pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
+                       &expected, &found, &tlvs, &auth_tlv_offset);
 
   if (retval > ISIS_WARNING)
     {
+      zlog_warn ("parse_tlvs() failed");
       free_tlvs (&tlvs);
       return retval;
     };
 
+  if (!(found & TLVFLAG_AREA_ADDRS))
+    {
+      zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
+      free_tlvs (&tlvs);
+      return ISIS_WARNING;
+    }
+
   /* 8.2.5.1 c) Authentication */
   if (circuit->passwd.type)
     {
       if (!(found & TLVFLAG_AUTH_INFO) ||
-         authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
-       {
-         isis_event_auth_failure (circuit->area->area_tag,
-                                  "P2P hello authentication failure",
-                                  hdr->source_id);
-         return ISIS_OK;
-       }
+          authentication_check (&tlvs.auth_info, &circuit->passwd,
+                                circuit->rcv_stream, auth_tlv_offset))
+        {
+          isis_event_auth_failure (circuit->area->area_tag,
+                                   "P2P hello authentication failure",
+                                   hdr->source_id);
+          free_tlvs (&tlvs);
+          return ISIS_OK;
+        }
+    }
+
+  /*
+   * check if it's own interface ip match iih ip addrs
+   */
+  if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
+      ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
+    {
+      zlog_warn ("ISIS-Adj: No usable IP interface addresses "
+                 "in LAN IIH from %s\n", circuit->interface->name);
+      free_tlvs (&tlvs);
+      return ISIS_WARNING;
+    }
+
+  /*
+   * My interpertation of the ISO, if no adj exists we will create one for
+   * the circuit
+   */
+  adj = circuit->u.p2p.neighbor;
+  if (!adj || adj->level != hdr->circuit_t)
+    {
+      if (!adj)
+        {
+          adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit);
+          if (adj == NULL)
+            return ISIS_ERROR;
+        }
+      else
+        {
+          adj->level = hdr->circuit_t;
+        }
+      circuit->u.p2p.neighbor = adj;
+      isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
+      adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
     }
 
+  /* 8.2.6 Monitoring point-to-point adjacencies */
+  adj->hold_time = ntohs (hdr->hold_time);
+  adj->last_upd = time (NULL);
+
   /* we do this now because the adj may not survive till the end... */
+  tlvs_to_adj_area_addrs (&tlvs, adj);
+
+  /* which protocol are spoken ??? */
+  if (found & TLVFLAG_NLPID)
+    tlvs_to_adj_nlpids (&tlvs, adj);
 
   /* we need to copy addresses to the adj */
-  tlvs_to_adj_ipv4_addrs (&tlvs, adj);
+  if (found & TLVFLAG_IPV4_ADDR)
+    tlvs_to_adj_ipv4_addrs (&tlvs, adj);
 
 #ifdef HAVE_IPV6
-  tlvs_to_adj_ipv6_addrs (&tlvs, adj);
+  if (found & TLVFLAG_IPV6_ADDR)
+    tlvs_to_adj_ipv6_addrs (&tlvs, adj);
 #endif /* HAVE_IPV6 */
 
   /* lets take care of the expiry */
@@ -435,6 +590,7 @@ process_p2p_hello (struct isis_circuit *circuit)
                {
                  /* (7) reject - wrong system type event */
                  zlog_warn ("wrongSystemType");
+                  free_tlvs (&tlvs);
                  return ISIS_WARNING;  /* Reject */
                }
              else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
@@ -521,6 +677,7 @@ process_p2p_hello (struct isis_circuit *circuit)
                {
                  /* (5) reject - wrong system type event */
                  zlog_warn ("wrongSystemType");
+                  free_tlvs (&tlvs);
                  return ISIS_WARNING;  /* Reject */
                }
              else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
@@ -553,7 +710,7 @@ process_p2p_hello (struct isis_circuit *circuit)
        }
     }
   /* 8.2.5.2 b) if no match was detected */
-  else
+  else if (listcount (circuit->area->area_addrs) > 0)
     {
       if (circuit->area->is_type == IS_LEVEL_1)
        {
@@ -579,6 +736,7 @@ process_p2p_hello (struct isis_circuit *circuit)
                {
                  /* (6) reject - Area Mismatch event */
                  zlog_warn ("AreaMismatch");
+                  free_tlvs (&tlvs);
                  return ISIS_WARNING;  /* Reject */
                }
              else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
@@ -631,6 +789,11 @@ process_p2p_hello (struct isis_circuit *circuit)
            }
        }
     }
+  else
+    {
+      /* down - area mismatch */
+      isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
+    }
   /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
   /* FIXME - Missing parts */
 
@@ -654,7 +817,15 @@ process_p2p_hello (struct isis_circuit *circuit)
     }
 
   adj->circuit_t = hdr->circuit_t;
-  adj->level = hdr->circuit_t;
+
+  if (isis->debugs & DEBUG_ADJ_PACKETS)
+    {
+      zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
+                 " cir id %02d, length %d",
+                 circuit->area->area_tag, circuit->interface->name,
+                 circuit_t2string (circuit->is_type),
+                 circuit->circuit_id, pdu_len);
+    }
 
   free_tlvs (&tlvs);
 
@@ -670,11 +841,28 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
   int retval = ISIS_OK;
   struct isis_lan_hello_hdr hdr;
   struct isis_adjacency *adj;
-  u_int32_t expected = 0, found;
+  u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
   struct tlvs tlvs;
   u_char *snpa;
   struct listnode *node;
 
+  if (isis->debugs & DEBUG_ADJ_PACKETS)
+    {
+      zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
+                  "cirID %u",
+                  circuit->area->area_tag, level, circuit->interface->name,
+                  circuit_t2string (circuit->is_type), circuit->circuit_id);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+                        stream_get_endp (circuit->rcv_stream));
+    }
+
+  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+    {
+      zlog_warn ("lan hello on non broadcast circuit");
+      return ISIS_WARNING;
+    }
+
   if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
     {
@@ -689,7 +877,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
       return ISIS_WARNING;
     }
 
-  if (!accept_level (level, circuit->circuit_is_type))
+  if (!accept_level (level, circuit->is_type))
     {
       if (isis->debugs & DEBUG_ADJ_PACKETS)
        {
@@ -721,13 +909,33 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
   hdr.prio = stream_getc (circuit->rcv_stream);
   stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
 
-  if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 &&
-      hdr.circuit_t != IS_LEVEL_1_AND_2)
+  if (hdr.pdu_len > ISO_MTU(circuit) ||
+      hdr.pdu_len > stream_get_endp (circuit->rcv_stream))
+    {
+      zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
+                 "invalid pdu length %d",
+                 circuit->area->area_tag, circuit->interface->name,
+                 hdr.pdu_len);
+      return ISIS_WARNING;
+    }
+
+  /*
+   * Set the stream endp to PDU length, ignoring additional padding
+   * introduced by transport chips.
+   */
+  if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream))
+    stream_set_endp (circuit->rcv_stream, hdr.pdu_len);
+
+  if (hdr.circuit_t != IS_LEVEL_1 &&
+      hdr.circuit_t != IS_LEVEL_2 &&
+      hdr.circuit_t != IS_LEVEL_1_AND_2 &&
+      (level & hdr.circuit_t) == 0)
     {
-      zlog_warn ("Level %d LAN Hello with Circuit Type %d", level,
-                hdr.circuit_t);
+      zlog_err ("Level %d LAN Hello with Circuit Type %d", level,
+                hdr.circuit_t);
       return ISIS_ERROR;
     }
+
   /*
    * Then get the tlvs
    */
@@ -738,10 +946,12 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;
 
+  auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
-                      STREAM_PNT (circuit->rcv_stream),
-                      hdr.pdu_len - ISIS_LANHELLO_HDRLEN -
-                      ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);
+                       STREAM_PNT (circuit->rcv_stream),
+                       hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
+                       &expected, &found, &tlvs,
+                       &auth_tlv_offset);
 
   if (retval > ISIS_WARNING)
     {
@@ -761,21 +971,24 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
   if (circuit->passwd.type)
     {
       if (!(found & TLVFLAG_AUTH_INFO) ||
-          authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
-       {
-         isis_event_auth_failure (circuit->area->area_tag,
-                                  "LAN hello authentication failure",
-                                  hdr.source_id);
-         retval = ISIS_WARNING;
-         goto out;
-       }
+          authentication_check (&tlvs.auth_info, &circuit->passwd,
+                                circuit->rcv_stream, auth_tlv_offset))
+        {
+          isis_event_auth_failure (circuit->area->area_tag,
+                                   "LAN hello authentication failure",
+                                   hdr.source_id);
+          retval = ISIS_WARNING;
+          goto out;
+        }
     }
 
   /*
    * Accept the level 1 adjacency only if a match between local and
    * remote area addresses is found
    */
-  if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs))
+  if (listcount (circuit->area->area_addrs) == 0 ||
+      (level == IS_LEVEL_1 &&
+       area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0))
     {
       if (isis->debugs & DEBUG_ADJ_PACKETS)
        {
@@ -802,43 +1015,49 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
   /*
    * check if it's own interface ip match iih ip addrs
    */
-  if (!(found & TLVFLAG_IPV4_ADDR)
-      || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
+  if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
+      ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
     {
-      zlog_debug
-       ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
-        circuit->interface->name);
+      zlog_debug ("ISIS-Adj: No usable IP interface addresses "
+                  "in LAN IIH from %s\n", circuit->interface->name);
       retval = ISIS_WARNING;
       goto out;
     }
 
   adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
-  if (!adj)
+  if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) ||
+      (adj->level != level))
     {
-      /*
-       * Do as in 8.4.2.5
-       */
-      adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
-      if (adj == NULL)
-       {
-         retval = ISIS_ERROR;
-         goto out;
-       }
-
-      adj->level = level;
+      if (!adj)
+        {
+          /*
+           * Do as in 8.4.2.5
+           */
+          adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
+          if (adj == NULL)
+            {
+              retval = ISIS_ERROR;
+              goto out;
+            }
+        }
+      else
+        {
+          if (ssnpa) {
+            memcpy (adj->snpa, ssnpa, 6);
+          } else {
+            memset (adj->snpa, ' ', 6);
+          }
+          adj->level = level;
+        }
       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
 
-      if (level == 1)
-       {
-         adj->sys_type = ISIS_SYSTYPE_L1_IS;
-       }
+      if (level == IS_LEVEL_1)
+          adj->sys_type = ISIS_SYSTYPE_L1_IS;
       else
-       {
-         adj->sys_type = ISIS_SYSTYPE_L2_IS;
-       }
+          adj->sys_type = ISIS_SYSTYPE_L2_IS;
       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]);
+                                 circuit->u.bc.lan_neighs[level - 1]);
     }
 
   if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
@@ -847,7 +1066,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
       case 1:
        if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
          {
-           thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+            thread_add_event (master, isis_event_dis_status_change, circuit, 0);
            memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
                    ISIS_SYS_ID_LEN + 1);
          }
@@ -855,7 +1074,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
       case 2:
        if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
          {
-           thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+            thread_add_event (master, isis_event_dis_status_change, circuit, 0);
            memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
                    ISIS_SYS_ID_LEN + 1);
          }
@@ -868,6 +1087,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
 
   memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
 
+  tlvs_to_adj_area_addrs (&tlvs, adj);
+
   /* which protocol are spoken ??? */
   if (found & TLVFLAG_NLPID)
     tlvs_to_adj_nlpids (&tlvs, adj);
@@ -886,7 +1107,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
   /* lets take care of the expiry */
   THREAD_TIMER_OFF (adj->t_expire);
   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
-                  (long) adj->hold_time);
+                   (long) adj->hold_time);
 
   /*
    * If the snpa for this circuit is found from LAN Neighbours TLV
@@ -894,31 +1115,48 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
    */
 
   if (found & TLVFLAG_LAN_NEIGHS)
+  {
+    if (adj->adj_state != ISIS_ADJ_UP)
     {
-      if (adj->adj_state != ISIS_ADJ_UP)
-       {
-         for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
-           if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
-           {
-             isis_adj_state_change (adj, ISIS_ADJ_UP,
-                                    "own SNPA found in LAN Neighbours TLV");
-           }
-       }
+      for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
+      {
+        if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
+        {
+          isis_adj_state_change (adj, ISIS_ADJ_UP,
+                                 "own SNPA found in LAN Neighbours TLV");
+        }
+      }
     }
+    else
+    {
+      int found = 0;
+      for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
+        if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
+        {
+          found = 1;
+          break;
+        }
+      if (found == 0)
+        isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
+                               "own SNPA not found in LAN Neighbours TLV");
+    }
+  }
+  else if (adj->adj_state == ISIS_ADJ_UP)
+  {
+    isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
+                           "no LAN Neighbours TLV found");
+  }
 
 out:
-  /* DEBUG_ADJ_PACKETS */
   if (isis->debugs & DEBUG_ADJ_PACKETS)
     {
-      /* FIXME: is this place right? fix missing info */
       zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
                  "cirID %u, length %ld",
                  circuit->area->area_tag,
                  level, snpa_print (ssnpa), circuit->interface->name,
-                 circuit_t2string (circuit->circuit_is_type),
+                 circuit_t2string (circuit->is_type),
                  circuit->circuit_id,
-                 /* FIXME: use %z when we stop supporting old compilers. */
-                 (unsigned long) stream_get_endp (circuit->rcv_stream));
+                 stream_get_endp (circuit->rcv_stream));
     }
 
   free_tlvs (&tlvs);
@@ -940,8 +1178,18 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
   int retval = ISIS_OK, comp = 0;
   u_char lspid[ISIS_SYS_ID_LEN + 2];
   struct isis_passwd *passwd;
+  uint16_t pdu_len;
+
+  if (isis->debugs & DEBUG_UPDATE_PACKETS)
+    {
+      zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
+                  circuit->area->area_tag, level, circuit->interface->name,
+                  circuit_t2string (circuit->is_type), circuit->circuit_id);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+                        stream_get_endp (circuit->rcv_stream));
+    }
 
-  /* Sanity check - FIXME: move to correct place */
   if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
     {
@@ -951,28 +1199,56 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 
   /* Reference the header   */
   hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
+  pdu_len = ntohs (hdr->pdu_len);
+
+  /* lsp length check */
+  if (pdu_len < ISIS_LSP_HDR_LEN ||
+      pdu_len > ISO_MTU(circuit) ||
+      pdu_len > stream_get_endp (circuit->rcv_stream))
+    {
+      zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
+                 circuit->area->area_tag,
+                 rawlspid_print (hdr->lsp_id), pdu_len);
+
+      return ISIS_WARNING;
+    }
+
+  /*
+   * Set the stream endp to PDU length, ignoring additional padding
+   * introduced by transport chips.
+   */
+  if (pdu_len < stream_get_endp (circuit->rcv_stream))
+    stream_set_endp (circuit->rcv_stream, pdu_len);
 
   if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
       zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
-                 "lifetime %us, len %lu, on %s",
+                 "lifetime %us, len %u, on %s",
                  circuit->area->area_tag,
                  level,
                  rawlspid_print (hdr->lsp_id),
                  ntohl (hdr->seq_num),
                  ntohs (hdr->checksum),
                  ntohs (hdr->rem_lifetime),
-                 /* FIXME: use %z when we stop supporting old compilers. */
-                 (unsigned long) stream_get_endp (circuit->rcv_stream), 
+                 pdu_len,
                  circuit->interface->name);
     }
 
-  assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN);
+  /* lsp is_type check */
+  if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 &&
+      (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2)
+    {
+      zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
+                 circuit->area->area_tag,
+                 rawlspid_print (hdr->lsp_id), hdr->lsp_bits);
+      /* continue as per RFC1122 Be liberal in what you accept, and
+       * conservative in what you send */
+    }
 
   /* Checksum sanity check - FIXME: move to correct place */
   /* 12 = sysid+pdu+remtime */
   if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
-                      ntohs (hdr->pdu_len) - 12, &hdr->checksum))
+                      pdu_len - 12, &hdr->checksum))
     {
       zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
                  circuit->area->area_tag,
@@ -993,13 +1269,13 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
     }
 
   /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
-  if (!accept_level (level, circuit->circuit_is_type))
+  if (!accept_level (level, circuit->is_type))
     {
       zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
                  " type %s",
                  circuit->area->area_tag,
                  rawlspid_print (hdr->lsp_id),
-                 level, circuit_t2string (circuit->circuit_is_type));
+                 level, circuit_t2string (circuit->is_type));
 
       return ISIS_WARNING;
     }
@@ -1009,12 +1285,12 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
   /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
 
   /* 7.3.15.1 a) 7 - password check */
-  (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) :
-    (passwd = &circuit->area->domain_passwd);
+  (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) :
+                          (passwd = &circuit->area->domain_passwd);
   if (passwd->type)
     {
-      if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area,
-                                  ntohs (hdr->pdu_len), passwd))
+      if (lsp_authentication_check (circuit->rcv_stream, circuit->area,
+                                    level, passwd))
        {
          isis_event_auth_failure (circuit->area->area_tag,
                                   "LSP authentication failure", hdr->lsp_id);
@@ -1035,7 +1311,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 
   /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level  */
   /* for broadcast circuits, snpa should be compared */
-  /* FIXME : Point To Point */
 
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     {
@@ -1052,7 +1327,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
          return ISIS_WARNING;  /* Silently discard */
        }
     }
-
   /* for non broadcast, we just need to find same level adj */
   else
     {
@@ -1063,13 +1337,15 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
        }
       else
        {
-         if (((level == 1) &&
+         if (((level == IS_LEVEL_1) &&
               (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
-             ((level == 2) &&
+             ((level == IS_LEVEL_2) &&
               (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
            return ISIS_WARNING;        /* Silently discard */
+         adj = circuit->u.p2p.neighbor;
        }
     }
+
 dontcheckadj:
   /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented  */
 
@@ -1096,10 +1372,9 @@ dontcheckadj:
              /* 7.3.16.4 b) 1)  */
              if (comp == LSP_NEWER)
                {
-                 lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area,
-                             level);
+                  lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
                  /* ii */
-                 ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+                  lsp_set_all_srmflags (lsp);
                  /* iii */
                  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
                  /* v */
@@ -1123,38 +1398,25 @@ dontcheckadj:
                  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
                }
            }
-         else
-           {
-             /* our own LSP -> 7.3.16.4 c) */
-             if (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) !=
-                 circuit->circuit_id
-                 || (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) ==
-                     circuit->circuit_id
-                     && circuit->u.bc.is_dr[level - 1] == 1))
-               {
-                 lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
-                 if (isis->debugs & DEBUG_UPDATE_PACKETS)
-                   zlog_debug ("LSP LEN: %d",
-                               ntohs (lsp->lsp_header->pdu_len));
-                 fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
-                                  ntohs (lsp->lsp_header->pdu_len) - 12, 12);
-                 ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-                 if (isis->debugs & DEBUG_UPDATE_PACKETS)
-                   zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
-                               "seq 0x%08x", circuit->area->area_tag,
-                               rawlspid_print (hdr->lsp_id),
-                               ntohl (lsp->lsp_header->seq_num));
-                 lsp->lsp_header->rem_lifetime =
-                   htons (isis_jitter
-                          (circuit->area->max_lsp_lifetime[level - 1],
-                           MAX_AGE_JITTER));
-               }
-             else
-               {
-                 /* Got purge for own pseudo-lsp, and we are not DR  */
-                 lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level);
-               }
-           }
+          else if (lsp->lsp_header->rem_lifetime != 0)
+            {
+              /* our own LSP -> 7.3.16.4 c) */
+              if (comp == LSP_NEWER)
+                {
+                  lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
+                  lsp_set_all_srmflags (lsp);
+                }
+              else
+                {
+                  ISIS_SET_FLAG (lsp->SRMflags, circuit);
+                  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
+                }
+              if (isis->debugs & DEBUG_UPDATE_PACKETS)
+                zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
+                            "seq 0x%08x", circuit->area->area_tag,
+                            rawlspid_print (hdr->lsp_id),
+                            ntohl (lsp->lsp_header->seq_num));
+            }
        }
       return retval;
     }
@@ -1174,25 +1436,19 @@ dontcheckadj:
        * has information that the current sequence number for source S is
        * "greater" than that held by S, ... */
 
-      else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
+      if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
        {
          /* 7.3.16.1  */
-         lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
-
-         fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
-                          ntohs (lsp->lsp_header->pdu_len) - 12, 12);
-
-         ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+          lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
          if (isis->debugs & DEBUG_UPDATE_PACKETS)
            zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
                        "0x%08x", circuit->area->area_tag,
                        rawlspid_print (hdr->lsp_id),
                        ntohl (lsp->lsp_header->seq_num));
-         lsp->lsp_header->rem_lifetime =
-           htons (isis_jitter
-                  (circuit->area->max_lsp_lifetime[level - 1],
-                   MAX_AGE_JITTER));
        }
+      /* If the received LSP is older or equal,
+       * resend the LSP which will act as ACK */
+      lsp_set_all_srmflags (lsp);
     }
   else
     {
@@ -1201,22 +1457,6 @@ dontcheckadj:
       /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
       if ((!lsp || comp == LSP_NEWER))
        {
-         int regenerate = (lsp == NULL);
-         /* i */
-         if (lsp)
-           {
-#ifdef EXTREME_DEBUG
-             zlog_debug ("level %d number is - %ld", level,
-                         circuit->area->lspdb[level - 1]->dict_nodecount);
-#endif /* EXTREME DEBUG */
-             lsp_search_and_destroy (hdr->lsp_id,
-                                     circuit->area->lspdb[level - 1]);
-             /* exists, so we overwrite */
-#ifdef EXTREME_DEBUG
-             zlog_debug ("level %d number is - %ld", level,
-                         circuit->area->lspdb[level - 1]->dict_nodecount);
-#endif /* EXTREME DEBUG */
-           }
          /*
           * If this lsp is a frag, need to see if we have zero lsp present
           */
@@ -1227,18 +1467,24 @@ dontcheckadj:
              lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
              if (!lsp0)
                {
-                 zlog_debug ("Got lsp frag, while zero lsp not database");
+                 zlog_debug ("Got lsp frag, while zero lsp not in database");
                  return ISIS_OK;
                }
            }
-         lsp =
-           lsp_new_from_stream_ptr (circuit->rcv_stream,
-                                    ntohs (hdr->pdu_len), lsp0,
-                                    circuit->area);
-         lsp->level = level;
-         lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+         /* i */
+         if (!lsp)
+            {
+             lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
+                                             pdu_len, lsp0,
+                                             circuit->area, level);
+              lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+            }
+          else /* exists, so we overwrite */
+            {
+              lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
+            }
          /* ii */
-         ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+          lsp_set_all_srmflags (lsp);
          /* iii */
          ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 
@@ -1246,19 +1492,14 @@ dontcheckadj:
          if (circuit->circ_type != CIRCUIT_T_BROADCAST)
            ISIS_SET_FLAG (lsp->SSNflags, circuit);
          /* FIXME: v) */
-           if (regenerate && circuit->u.bc.is_dr[level - 1]) {
-           lsp_l1_pseudo_generate (circuit);
-         }
        }
       /* 7.3.15.1 e) 2) LSP equal to the one in db */
       else if (comp == LSP_EQUAL)
        {
          ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
-         lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, level);
+         lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
          if (circuit->circ_type != CIRCUIT_T_BROADCAST)
-           {
-             ISIS_SET_FLAG (lsp->SSNflags, circuit);
-           }
+           ISIS_SET_FLAG (lsp->SSNflags, circuit);
        }
       /* 7.3.15.1 e) 3) LSP older than the one in db */
       else
@@ -1267,7 +1508,6 @@ dontcheckadj:
          ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
        }
     }
-
   return retval;
 }
 
@@ -1284,11 +1524,11 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   int retval = ISIS_OK;
   int cmp, own_lsp;
   char typechar = ' ';
-  int len;
+  uint16_t pdu_len;
   struct isis_adjacency *adj;
   struct isis_complete_seqnum_hdr *chdr = NULL;
   struct isis_partial_seqnum_hdr *phdr = NULL;
-  uint32_t found = 0, expected = 0;
+  uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
   struct isis_lsp *lsp;
   struct lsp_entry *entry;
   struct listnode *node, *nnode;
@@ -1303,12 +1543,14 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
       typechar = 'C';
       chdr =
        (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
-      circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;
-      len = ntohs (chdr->pdu_len);
-      if (len < ISIS_CSNP_HDRLEN)
+      stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN);
+      pdu_len = ntohs (chdr->pdu_len);
+      if (pdu_len < ISIS_CSNP_HDRLEN ||
+          pdu_len > ISO_MTU(circuit) ||
+          pdu_len > stream_get_endp (circuit->rcv_stream))
        {
-         zlog_warn ("Received a CSNP with bogus length!");
-         return ISIS_OK;
+         zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
+         return ISIS_WARNING;
        }
     }
   else
@@ -1316,15 +1558,24 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
       typechar = 'P';
       phdr =
        (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
-      circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;
-      len = ntohs (phdr->pdu_len);
-      if (len < ISIS_PSNP_HDRLEN)
+      stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN);
+      pdu_len = ntohs (phdr->pdu_len);
+      if (pdu_len < ISIS_PSNP_HDRLEN ||
+          pdu_len > ISO_MTU(circuit) ||
+          pdu_len > stream_get_endp (circuit->rcv_stream))
        {
-         zlog_warn ("Received a CSNP with bogus length!");
-         return ISIS_OK;
+         zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
+         return ISIS_WARNING;
        }
     }
 
+  /*
+   * Set the stream endp to PDU length, ignoring additional padding
+   * introduced by transport chips.
+   */
+  if (pdu_len < stream_get_endp (circuit->rcv_stream))
+    stream_set_endp (circuit->rcv_stream, pdu_len);
+
   /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
   if (circuit->ext_domain)
     {
@@ -1338,7 +1589,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
     }
 
   /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
-  if (!accept_level (level, circuit->circuit_is_type))
+  if (!accept_level (level, circuit->is_type))
     {
 
       zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
@@ -1347,26 +1598,23 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
                  level,
                  typechar,
                  circuit->interface->name,
-                 circuit_t2string (circuit->circuit_is_type), level);
+                 circuit_t2string (circuit->is_type), level);
 
       return ISIS_OK;
     }
 
   /* 7.3.15.2 a) 4 - not applicable for CSNP  only PSNPs on broadcast */
   if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
-      (circuit->circ_type == CIRCUIT_T_BROADCAST))
+      (circuit->circ_type == CIRCUIT_T_BROADCAST) &&
+      (!circuit->u.bc.is_dr[level - 1]))
     {
-      if (!circuit->u.bc.is_dr[level - 1])
-       {
-
-         zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
-                     "skipping: we are not the DIS",
-                     circuit->area->area_tag,
-                     level,
-                     typechar, snpa_print (ssnpa), circuit->interface->name);
+      zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
+                  "skipping: we are not the DIS",
+                  circuit->area->area_tag,
+                  level,
+                  typechar, snpa_print (ssnpa), circuit->interface->name);
 
-         return ISIS_OK;
-       }
+      return ISIS_OK;
     }
 
   /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
@@ -1396,7 +1644,10 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   else
     {
       if (!circuit->u.p2p.neighbor)
-       return ISIS_OK;         /* Silently discard */
+      {
+        zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name);
+        return ISIS_OK;                /* Silently discard */
+      }
     }
 
   /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented  */
@@ -1408,10 +1659,12 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   /* parse the SNP */
   expected |= TLVFLAG_LSP_ENTRIES;
   expected |= TLVFLAG_AUTH_INFO;
+
+  auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
                       STREAM_PNT (circuit->rcv_stream),
-                      len - circuit->rcv_stream->getp,
-                      &expected, &found, &tlvs);
+                      pdu_len - stream_get_getp (circuit->rcv_stream),
+                      &expected, &found, &tlvs, &auth_tlv_offset);
 
   if (retval > ISIS_WARNING)
     {
@@ -1420,7 +1673,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
       return retval;
     }
 
-  if (level == 1)
+  if (level == IS_LEVEL_1)
     passwd = &circuit->area->area_passwd;
   else
     passwd = &circuit->area->domain_passwd;
@@ -1428,16 +1681,19 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
     {
       if (passwd->type)
-       {
-         if (!(found & TLVFLAG_AUTH_INFO) ||
-             authentication_check (&tlvs.auth_info, passwd, circuit))
-           {
-             isis_event_auth_failure (circuit->area->area_tag,
-                                      "SNP authentication" " failure",
-                                      phdr ? phdr->source_id : chdr->source_id);
-             return ISIS_OK;
-           }
-       }
+        {
+          if (!(found & TLVFLAG_AUTH_INFO) ||
+              authentication_check (&tlvs.auth_info, passwd,
+                                    circuit->rcv_stream, auth_tlv_offset))
+            {
+              isis_event_auth_failure (circuit->area->area_tag,
+                                       "SNP authentication" " failure",
+                                       phdr ? phdr->source_id :
+                                       chdr->source_id);
+              free_tlvs (&tlvs);
+              return ISIS_OK;
+            }
+        }
     }
 
   /* debug isis snp-packets */
@@ -1477,19 +1733,18 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
            /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
            if (cmp == LSP_EQUAL)
              {
-               if (circuit->circ_type != CIRCUIT_T_BROADCAST)
-                 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
-               /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
+               /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
+               ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
              }
+           /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
            else if (cmp == LSP_OLDER)
              {
                ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
                ISIS_SET_FLAG (lsp->SRMflags, circuit);
              }
+           /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
            else
              {
-               /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
-                * on p2p */
                if (own_lsp)
                  {
                    lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
@@ -1498,8 +1753,8 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
                else
                  {
                    ISIS_SET_FLAG (lsp->SSNflags, circuit);
-                   if (circuit->circ_type != CIRCUIT_T_BROADCAST)
-                     ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+                   /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
+                   ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
                  }
              }
          }
@@ -1512,7 +1767,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
              {
                lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
                               0, 0, entry->checksum, level);
+               lsp->area = circuit->area;
                lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+               ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
                ISIS_SET_FLAG (lsp->SSNflags, circuit);
              }
          }
@@ -1523,7 +1780,8 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   if (snp_type == ISIS_SNP_CSNP_FLAG)
     {
       /*
-       * Build a list from our own LSP db bounded with start_ and stop_lsp_id
+       * Build a list from our own LSP db bounded with
+       * start_lsp_id and stop_lsp_id
        */
       lsp_list = list_new ();
       lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
@@ -1546,11 +1804,10 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
        }
       /* on remaining LSPs we set SRM (neighbor knew not of) */
       for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
-      {
        ISIS_SET_FLAG (lsp->SRMflags, circuit);
-      }
       /* lets free it */
-      list_free (lsp_list);
+      list_delete (lsp_list);
+
     }
 
   free_tlvs (&tlvs);
@@ -1560,6 +1817,16 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
 static int
 process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 {
+  if (isis->debugs & DEBUG_SNP_PACKETS)
+    {
+      zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
+                  circuit->area->area_tag, level, circuit->interface->name,
+                  circuit_t2string (circuit->is_type), circuit->circuit_id);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+                        stream_get_endp (circuit->rcv_stream));
+    }
+
   /* Sanity check - FIXME: move to correct place */
   if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
@@ -1574,10 +1841,20 @@ process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 static int
 process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 {
+  if (isis->debugs & DEBUG_SNP_PACKETS)
+    {
+      zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
+                  circuit->area->area_tag, level, circuit->interface->name,
+                  circuit_t2string (circuit->is_type), circuit->circuit_id);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+                        stream_get_endp (circuit->rcv_stream));
+    }
+
   if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
     {
-      zlog_warn ("Packet too short");
+      zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
       return ISIS_WARNING;
     }
 
@@ -1601,6 +1878,16 @@ process_is_hello (struct isis_circuit *circuit)
   u_char neigh_len;
   u_char *sysid;
 
+  if (isis->debugs & DEBUG_ADJ_PACKETS)
+    {
+      zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u",
+                  circuit->area->area_tag, circuit->interface->name,
+                  circuit_t2string (circuit->is_type), circuit->circuit_id);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+                        stream_get_endp (circuit->rcv_stream));
+    }
+
   /* In this point in time we are not yet able to handle is_hellos
    * on lan - Sorry juniper...
    */
@@ -1665,7 +1952,6 @@ static int
 isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
 {
   struct isis_fixed_hdr *hdr;
-  struct esis_fixed_hdr *esis_hdr;
 
   int retval = ISIS_OK;
 
@@ -1676,7 +1962,7 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
 
   if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
     {
-      zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
+      zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
       return ISIS_ERROR;
     }
 
@@ -1685,28 +1971,11 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
    */
   if (hdr->idrp == ISO9542_ESIS)
     {
-      esis_hdr = (struct esis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
-      stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN);
-      /* FIXME: Need to do some acceptence tests */
-      /* example length... */
-      switch (esis_hdr->pdu_type)
-       {
-       case ESH_PDU:
-         /* FIXME */
-         break;
-       case ISH_PDU:
-         zlog_debug ("AN ISH PDU!!");
-         retval = process_is_hello (circuit);
-         break;
-       default:
-         return ISIS_ERROR;
-       }
-      return retval;
-    }
-  else
-    {
-      stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
+      zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp);
+      return ISIS_ERROR;
     }
+  stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
+
   /*
    * and then process it
    */
@@ -1737,6 +2006,14 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
       zlog_warn ("Unsupported ISIS version %u", hdr->version2);
       return ISIS_WARNING;
     }
+
+  if (circuit->is_passive)
+    {
+      zlog_warn ("Received ISIS PDU on passive circuit %s",
+                circuit->interface->name);
+      return ISIS_WARNING;
+    }
+
   /* either 3 or 0 */
   if ((hdr->max_area_addrs != 0)
       && (hdr->max_area_addrs != isis->max_area_addrs))
@@ -1797,9 +2074,6 @@ isis_receive (struct thread *thread)
   circuit = THREAD_ARG (thread);
   assert (circuit);
 
-  if (!circuit->area)
-    return ISIS_OK;
-
   if (circuit->rcv_stream == NULL)
     circuit->rcv_stream = stream_new (ISO_MTU (circuit));
   else
@@ -1814,8 +2088,11 @@ isis_receive (struct thread *thread)
   /* 
    * prepare for next packet. 
    */
-  THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
-                 circuit->fd);
+  if (!circuit->is_passive)
+  {
+    THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
+                    circuit->fd);
+  }
 
   return retval;
 }
@@ -1849,10 +2126,13 @@ isis_receive (struct thread *thread)
   /* 
    * prepare for next packet. 
    */
-  circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
-                                          listcount
-                                          (circuit->area->circuit_list) *
-                                          100);
+  if (!circuit->is_passive)
+  {
+    circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
+                                            listcount
+                                            (circuit->area->circuit_list) *
+                                            100);
+  }
 
   return retval;
 }
@@ -1927,14 +2207,13 @@ send_hello (struct isis_circuit *circuit, int level)
   struct isis_fixed_hdr fixed_hdr;
   struct isis_lan_hello_hdr hello_hdr;
   struct isis_p2p_hello_hdr p2p_hello_hdr;
-  char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-
+  unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+  unsigned long len_pointer, length, auth_tlv_offset = 0;
   u_int32_t interval;
-  unsigned long len_pointer, length, auth_tlv;
   int retval;
 
-  if (circuit->state != C_STATE_UP || circuit->interface == NULL)
-    return ISIS_WARNING;
+  if (circuit->is_passive)
+    return ISIS_OK;
 
   if (circuit->interface->mtu == 0)
     {
@@ -1948,7 +2227,7 @@ send_hello (struct isis_circuit *circuit, int level)
     stream_reset (circuit->snd_stream);
 
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
-    if (level == 1)
+    if (level == IS_LEVEL_1)
       fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
                                circuit->snd_stream);
     else
@@ -1963,12 +2242,9 @@ send_hello (struct isis_circuit *circuit, int level)
   memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
   interval = circuit->hello_multiplier[level - 1] *
     circuit->hello_interval[level - 1];
-  /* If we are the DIS then hello interval is divided by three, as is the hold-timer */
-  if (circuit->u.bc.is_dr[level - 1])
-    interval=interval/3;
   if (interval > USHRT_MAX)
     interval = USHRT_MAX;
-  hello_hdr.circuit_t = circuit->circuit_is_type;
+  hello_hdr.circuit_t = circuit->is_type;
   memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
   hello_hdr.hold_time = htons ((u_int16_t) interval);
 
@@ -1985,13 +2261,13 @@ send_hello (struct isis_circuit *circuit, int level)
     }
   else
     {
-      hello_hdr.prio = circuit->u.bc.priority[level - 1];
-      if (level == 1 && circuit->u.bc.l1_desig_is)
+      hello_hdr.prio = circuit->priority[level - 1];
+      if (level == IS_LEVEL_1)
        {
          memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
                  ISIS_SYS_ID_LEN + 1);
        }
-      else if (level == 2 && circuit->u.bc.l2_desig_is)
+      else if (level == IS_LEVEL_2)
        {
          memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
                  ISIS_SYS_ID_LEN + 1);
@@ -2000,68 +2276,73 @@ send_hello (struct isis_circuit *circuit, int level)
     }
 
   /*
-   * Then the variable length part 
+   * Then the variable length part.
    */
 
   /* add circuit password */
-  /* Cleartext */
-  if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
-    if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len,
-                         circuit->passwd.passwd, circuit->snd_stream))
-      return ISIS_WARNING;
+  switch (circuit->passwd.type)
+  {
+    /* Cleartext */
+    case ISIS_PASSWD_TYPE_CLEARTXT:
+      if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
+                            circuit->passwd.passwd, circuit->snd_stream))
+        return ISIS_WARNING;
+      break;
 
-  /* or HMAC MD5 */
-  if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
-    {
+    /* HMAC MD5 */
+    case ISIS_PASSWD_TYPE_HMAC_MD5:
       /* Remember where TLV is written so we can later overwrite the MD5 hash */
-      auth_tlv = stream_get_endp (circuit->snd_stream);
+      auth_tlv_offset = stream_get_endp (circuit->snd_stream);
       memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
-      if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
-                          hmac_md5_hash, circuit->snd_stream))
-       return ISIS_WARNING;
+      if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
+                            hmac_md5_hash, circuit->snd_stream))
+        return ISIS_WARNING;
+      break;
+
+    default:
+      break;
+  }
+
+  /*  Area Addresses TLV */
+  if (listcount (circuit->area->area_addrs) == 0)
+    return ISIS_WARNING;
+  if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
+    return ISIS_WARNING;
+
+  /*  LAN Neighbors TLV */
+  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+    {
+      if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] &&
+          listcount (circuit->u.bc.lan_neighs[0]) > 0)
+       if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
+                               circuit->snd_stream))
+         return ISIS_WARNING;
+      if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] &&
+          listcount (circuit->u.bc.lan_neighs[1]) > 0)
+       if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
+                               circuit->snd_stream))
+         return ISIS_WARNING;
     }
 
   /* Protocols Supported TLV */
   if (circuit->nlpids.count > 0)
     if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
       return ISIS_WARNING;
-
-  /*  Area Addresses TLV */
-  assert (circuit->area);
-  if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0)
-    if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
-      return ISIS_WARNING;
-
   /* IP interface Address TLV */
-  if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0)
+  if (circuit->ip_router && circuit->ip_addrs &&
+      listcount (circuit->ip_addrs) > 0)
     if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
       return ISIS_WARNING;
 
 #ifdef HAVE_IPV6
   /* IPv6 Interface Address TLV */
   if (circuit->ipv6_router && circuit->ipv6_link &&
-      circuit->ipv6_link->count > 0)
+      listcount (circuit->ipv6_link) > 0)
     if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
       return ISIS_WARNING;
 #endif /* HAVE_IPV6 */
 
-  /* Restart signaling, vendor C sends it too */
-  retval = add_tlv (211, 3, 0, circuit->snd_stream);
-
-  /*  LAN Neighbors TLV */
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
-    {
-      if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0)
-       if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
-                               circuit->snd_stream))
-         return ISIS_WARNING;
-      if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0)
-       if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
-                               circuit->snd_stream))
-         return ISIS_WARNING;
-    }
-
-  if (circuit->u.bc.pad_hellos)
+  if (circuit->pad_hellos)
     if (tlv_add_padding (circuit->snd_stream))
       return ISIS_WARNING;
 
@@ -2072,16 +2353,15 @@ send_hello (struct isis_circuit *circuit, int level)
   /* For HMAC MD5 we need to compute the md5 hash and store it */
   if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
     {
-      hmac_md5(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash);
+      hmac_md5 (STREAM_DATA (circuit->snd_stream),
+                stream_get_endp (circuit->snd_stream),
+                (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len,
+                (caddr_t) &hmac_md5_hash);
       /* Copy the hash into the stream */
-      memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE);
+      memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
+              hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
     }
 
-  retval = circuit->tx (circuit, level);
-  if (retval)
-    zlog_warn ("sending of LAN Level %d Hello failed", level);
-
-  /* DEBUG_ADJ_PACKETS */
   if (isis->debugs & DEBUG_ADJ_PACKETS)
     {
       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
@@ -2089,24 +2369,26 @@ send_hello (struct isis_circuit *circuit, int level)
          zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
                      circuit->area->area_tag, level, circuit->interface->name,
                      /* FIXME: use %z when we stop supporting old compilers. */
-                     (unsigned long) STREAM_SIZE (circuit->snd_stream));
+                     length);
        }
       else
        {
          zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
                      circuit->area->area_tag, circuit->interface->name,
                      /* FIXME: use %z when we stop supporting old compilers. */
-                     (unsigned long) STREAM_SIZE (circuit->snd_stream));
+                     length);
        }
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+                        stream_get_endp (circuit->snd_stream));
     }
 
-  return retval;
-}
+  retval = circuit->tx (circuit, level);
+  if (retval != ISIS_OK)
+    zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
+              circuit->area->area_tag, level, circuit->interface->name);
 
-static int
-send_lan_hello (struct isis_circuit *circuit, int level)
-{
-  return send_hello (circuit, level);
+  return retval;
 }
 
 int
@@ -2114,32 +2396,20 @@ send_lan_l1_hello (struct thread *thread)
 {
   struct isis_circuit *circuit;
   int retval;
-  unsigned long next_hello;
 
   circuit = THREAD_ARG (thread);
   assert (circuit);
-
-  if (!circuit->area) {
-    return ISIS_OK;
-  }
-
-  /* Pseudonode sends hellos three times more than the other nodes */
-  if (circuit->u.bc.is_dr[0])
-    next_hello=circuit->hello_interval[0]/3+1;
-  else
-    next_hello=circuit->hello_interval[0];
-
   circuit->u.bc.t_send_lan_hello[0] = NULL;
 
   if (circuit->u.bc.run_dr_elect[0])
     retval = isis_dr_elect (circuit, 1);
 
-  retval = send_lan_hello (circuit, 1);
+  retval = send_hello (circuit, 1);
 
   /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
                   send_lan_l1_hello, circuit,
-                  isis_jitter (next_hello, IIH_JITTER));
+                  isis_jitter (circuit->hello_interval[0], IIH_JITTER));
 
   return retval;
 }
@@ -2149,32 +2419,20 @@ send_lan_l2_hello (struct thread *thread)
 {
   struct isis_circuit *circuit;
   int retval;
-  unsigned long next_hello;
 
   circuit = THREAD_ARG (thread);
   assert (circuit);
-
-  if (!circuit->area) {
-    return ISIS_OK;
-  }
-
-  /* Pseudonode sends hellos three times more than the other nodes */
-  if (circuit->u.bc.is_dr[1])
-    next_hello=circuit->hello_interval[1]/3+1;
-  else
-    next_hello=circuit->hello_interval[1];
-
   circuit->u.bc.t_send_lan_hello[1] = NULL;
 
   if (circuit->u.bc.run_dr_elect[1])
     retval = isis_dr_elect (circuit, 2);
 
-  retval = send_lan_hello (circuit, 2);
+  retval = send_hello (circuit, 2);
 
   /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
                   send_lan_l2_hello, circuit,
-                  isis_jitter (next_hello, IIH_JITTER));
+                  isis_jitter (circuit->hello_interval[1], IIH_JITTER));
 
   return retval;
 }
@@ -2204,11 +2462,18 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
 {
   struct isis_fixed_hdr fixed_hdr;
   struct isis_passwd *passwd;
-  int retval = ISIS_OK;
   unsigned long lenp;
   u_int16_t length;
+  unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+  unsigned long auth_tlv_offset = 0;
+  int retval = ISIS_OK;
 
-  if (level == 1)
+  if (circuit->snd_stream == NULL)
+    circuit->snd_stream = stream_new (ISO_MTU (circuit));
+  else
+    stream_reset (circuit->snd_stream);
+
+  if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
                              circuit->snd_stream);
   else
@@ -2232,28 +2497,143 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
   /*
    * And TLVs
    */
-  if (level == 1)
+  if (level == IS_LEVEL_1)
     passwd = &circuit->area->area_passwd;
   else
     passwd = &circuit->area->domain_passwd;
 
   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
-    if (passwd->type)
-      retval = tlv_add_authinfo (passwd->type, passwd->len,
-                                passwd->passwd, circuit->snd_stream);
-
-  if (!retval && lsps)
-    {
-      retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+  {
+    switch (passwd->type)
+    {
+      /* Cleartext */
+      case ISIS_PASSWD_TYPE_CLEARTXT:
+        if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
+                              passwd->passwd, circuit->snd_stream))
+          return ISIS_WARNING;
+        break;
+
+        /* HMAC MD5 */
+      case ISIS_PASSWD_TYPE_HMAC_MD5:
+        /* Remember where TLV is written so we can later overwrite the MD5 hash */
+        auth_tlv_offset = stream_get_endp (circuit->snd_stream);
+        memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+        if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
+                              hmac_md5_hash, circuit->snd_stream))
+          return ISIS_WARNING;
+        break;
+
+      default:
+        break;
     }
+  }
+
+  retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+  if (retval != ISIS_OK)
+    return retval;
+
   length = (u_int16_t) stream_get_endp (circuit->snd_stream);
-  assert (length >= ISIS_CSNP_HDRLEN);
   /* Update PU length */
   stream_putw_at (circuit->snd_stream, lenp, length);
 
+  /* For HMAC MD5 we need to compute the md5 hash and store it */
+  if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
+      passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
+    {
+      hmac_md5 (STREAM_DATA (circuit->snd_stream),
+                stream_get_endp(circuit->snd_stream),
+                (unsigned char *) &passwd->passwd, passwd->len,
+                (caddr_t) &hmac_md5_hash);
+      /* Copy the hash into the stream */
+      memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
+              hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+    }
+
   return retval;
 }
 
+/*
+ * Count the maximum number of lsps that can be accomodated by a given size.
+ */
+static uint16_t
+get_max_lsp_count (uint16_t size)
+{
+  uint16_t tlv_count;
+  uint16_t lsp_count;
+  uint16_t remaining_size;
+
+  /* First count the full size TLVs */
+  tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE;
+  lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN);
+
+  /* The last TLV, if any */
+  remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE;
+  if (remaining_size - 2 >= LSP_ENTRIES_LEN)
+    lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN;
+
+  return lsp_count;
+}
+
+/*
+ * Calculate the length of Authentication Info. TLV.
+ */
+static uint16_t
+auth_tlv_length (int level, struct isis_circuit *circuit)
+{
+  struct isis_passwd *passwd;
+  uint16_t length;
+
+  if (level == IS_LEVEL_1)
+    passwd = &circuit->area->area_passwd;
+  else
+    passwd = &circuit->area->domain_passwd;
+
+  /* Also include the length of TLV header */
+  length = AUTH_INFO_HDRLEN;
+  if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
+  {
+    switch (passwd->type)
+    {
+      /* Cleartext */
+      case ISIS_PASSWD_TYPE_CLEARTXT:
+        length += passwd->len;
+        break;
+
+        /* HMAC MD5 */
+      case ISIS_PASSWD_TYPE_HMAC_MD5:
+        length += ISIS_AUTH_MD5_SIZE;
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  return length;
+}
+
+/*
+ * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
+ */
+static uint16_t
+max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
+{
+  int snp_hdr_len;
+  int auth_tlv_len;
+  uint16_t lsp_count;
+
+  snp_hdr_len = ISIS_FIXED_HDR_LEN;
+  if (snp_type == ISIS_SNP_CSNP_FLAG)
+    snp_hdr_len += ISIS_CSNP_HDRLEN;
+  else
+    snp_hdr_len += ISIS_PSNP_HDRLEN;
+
+  auth_tlv_len = auth_tlv_length (level, circuit);
+  lsp_count = get_max_lsp_count (
+      stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len);
+  return lsp_count;
+}
+
 /*
  * FIXME: support multiple CSNPs
  */
@@ -2261,55 +2641,100 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
 int
 send_csnp (struct isis_circuit *circuit, int level)
 {
-  int retval = ISIS_OK;
   u_char start[ISIS_SYS_ID_LEN + 2];
   u_char stop[ISIS_SYS_ID_LEN + 2];
   struct list *list = NULL;
   struct listnode *node;
   struct isis_lsp *lsp;
+  u_char num_lsps, loop = 1;
+  int i, retval = ISIS_OK;
 
-  if (circuit->state != C_STATE_UP || circuit->interface == NULL)
-    return ISIS_WARNING;
+  if (circuit->area->lspdb[level - 1] == NULL ||
+      dict_count (circuit->area->lspdb[level - 1]) == 0)
+    return retval;
 
   memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
   memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
 
-  if (circuit->area->lspdb[level - 1] &&
-      dict_count (circuit->area->lspdb[level - 1]) > 0)
+  num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit);
+
+  while (loop)
     {
       list = list_new ();
-      lsp_build_list (start, stop, list, circuit->area->lspdb[level - 1]);
-
-      if (circuit->snd_stream == NULL)
-       circuit->snd_stream = stream_new (ISO_MTU (circuit));
+      lsp_build_list (start, stop, num_lsps, list,
+                      circuit->area->lspdb[level - 1]);
+      /*
+       * Update the stop lsp_id before encoding this CSNP.
+       */
+      if (listcount (list) < num_lsps)
+        {
+          memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
+        }
       else
-       stream_reset (circuit->snd_stream);
+        {
+          node = listtail (list);
+          lsp = listgetdata (node);
+          memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
+        }
 
       retval = build_csnp (level, start, stop, list, circuit);
+      if (retval != ISIS_OK)
+        {
+          zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
+                    circuit->area->area_tag, level, circuit->interface->name);
+          list_delete (list);
+          return retval;
+        }
 
       if (isis->debugs & DEBUG_SNP_PACKETS)
-       {
-         zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
-                    circuit->area->area_tag, level, circuit->interface->name,
-                    /* FIXME: use %z when we stop supporting old compilers. */
-                    (unsigned long) STREAM_SIZE (circuit->snd_stream));
-         for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
-         {
-           zlog_debug ("ISIS-Snp (%s):         CSNP entry %s, seq 0x%08x,"
-                       " cksum 0x%04x, lifetime %us",
-                       circuit->area->area_tag,
-                       rawlspid_print (lsp->lsp_header->lsp_id),
-                       ntohl (lsp->lsp_header->seq_num),
-                       ntohs (lsp->lsp_header->checksum),
-                       ntohs (lsp->lsp_header->rem_lifetime));
-         }
-       }
+        {
+          zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
+                      circuit->area->area_tag, level, circuit->interface->name,
+                      stream_get_endp (circuit->snd_stream));
+          for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
+            {
+              zlog_debug ("ISIS-Snp (%s):         CSNP entry %s, seq 0x%08x,"
+                          " cksum 0x%04x, lifetime %us",
+                          circuit->area->area_tag,
+                          rawlspid_print (lsp->lsp_header->lsp_id),
+                          ntohl (lsp->lsp_header->seq_num),
+                          ntohs (lsp->lsp_header->checksum),
+                          ntohs (lsp->lsp_header->rem_lifetime));
+            }
+          if (isis->debugs & DEBUG_PACKET_DUMP)
+            zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+                            stream_get_endp (circuit->snd_stream));
+        }
+
+      retval = circuit->tx (circuit, level);
+      if (retval != ISIS_OK)
+        {
+          zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
+                    circuit->area->area_tag, level,
+                    circuit->interface->name);
+          list_delete (list);
+          return retval;
+        }
 
+      /*
+       * Start lsp_id of the next CSNP should be one plus the
+       * stop lsp_id in this current CSNP.
+       */
+      memcpy (start, stop, ISIS_SYS_ID_LEN + 2);
+      loop = 0;
+      for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i)
+        {
+          if (start[i] < (u_char)0xff)
+            {
+              start[i] += 1;
+              loop = 1;
+              break;
+            }
+        }
+      memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
       list_delete (list);
-
-      if (retval == ISIS_OK)
-       retval = circuit->tx (circuit, level);
     }
+
   return retval;
 }
 
@@ -2325,7 +2750,9 @@ send_l1_csnp (struct thread *thread)
   circuit->t_send_csnp[0] = NULL;
 
   if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
+    {
       send_csnp (circuit, 1);
+    }
   /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
                   isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
@@ -2345,7 +2772,9 @@ send_l2_csnp (struct thread *thread)
   circuit->t_send_csnp[1] = NULL;
 
   if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
+    {
       send_csnp (circuit, 2);
+    }
   /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
                   isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
@@ -2359,12 +2788,19 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
   struct isis_fixed_hdr fixed_hdr;
   unsigned long lenp;
   u_int16_t length;
-  int retval = 0;
   struct isis_lsp *lsp;
   struct isis_passwd *passwd;
   struct listnode *node;
+  unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+  unsigned long auth_tlv_offset = 0;
+  int retval = ISIS_OK;
+
+  if (circuit->snd_stream == NULL)
+    circuit->snd_stream = stream_new (ISO_MTU (circuit));
+  else
+    stream_reset (circuit->snd_stream);
 
-  if (level == 1)
+  if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
                              circuit->snd_stream);
   else
@@ -2383,20 +2819,40 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
    * And TLVs
    */
 
-  if (level == 1)
+  if (level == IS_LEVEL_1)
     passwd = &circuit->area->area_passwd;
   else
     passwd = &circuit->area->domain_passwd;
 
   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
-    if (passwd->type)
-      retval = tlv_add_authinfo (passwd->type, passwd->len,
-                                passwd->passwd, circuit->snd_stream);
-
-  if (!retval && lsps)
-    {
-      retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+  {
+    switch (passwd->type)
+    {
+      /* Cleartext */
+      case ISIS_PASSWD_TYPE_CLEARTXT:
+        if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
+                              passwd->passwd, circuit->snd_stream))
+          return ISIS_WARNING;
+        break;
+
+        /* HMAC MD5 */
+      case ISIS_PASSWD_TYPE_HMAC_MD5:
+        /* Remember where TLV is written so we can later overwrite the MD5 hash */
+        auth_tlv_offset = stream_get_endp (circuit->snd_stream);
+        memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+        if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
+                              hmac_md5_hash, circuit->snd_stream))
+          return ISIS_WARNING;
+        break;
+
+      default:
+        break;
     }
+  }
+
+  retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+  if (retval != ISIS_OK)
+    return retval;
 
   if (isis->debugs & DEBUG_SNP_PACKETS)
     {
@@ -2413,10 +2869,22 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
     }
 
   length = (u_int16_t) stream_get_endp (circuit->snd_stream);
-  assert (length >= ISIS_PSNP_HDRLEN);
   /* Update PDU length */
   stream_putw_at (circuit->snd_stream, lenp, length);
 
+  /* For HMAC MD5 we need to compute the md5 hash and store it */
+  if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
+      passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
+    {
+      hmac_md5 (STREAM_DATA (circuit->snd_stream),
+                stream_get_endp(circuit->snd_stream),
+                (unsigned char *) &passwd->passwd, passwd->len,
+                (caddr_t) &hmac_md5_hash);
+      /* Copy the hash into the stream */
+      memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
+              hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+    }
+
   return ISIS_OK;
 }
 
@@ -2427,57 +2895,74 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
 static int
 send_psnp (int level, struct isis_circuit *circuit)
 {
-  int retval = ISIS_OK;
   struct isis_lsp *lsp;
   struct list *list = NULL;
   struct listnode *node;
+  u_char num_lsps;
+  int retval = ISIS_OK;
 
-  if (circuit->state != C_STATE_UP || circuit->interface == NULL)
-    return ISIS_WARNING;
-
-  if ((circuit->circ_type == CIRCUIT_T_BROADCAST &&
-       !circuit->u.bc.is_dr[level - 1]) ||
-      circuit->circ_type != CIRCUIT_T_BROADCAST)
-    {
+  if (circuit->circ_type == CIRCUIT_T_BROADCAST &&
+      circuit->u.bc.is_dr[level - 1])
+    return ISIS_OK;
 
-      if (circuit->area->lspdb[level - 1] &&
-         dict_count (circuit->area->lspdb[level - 1]) > 0)
-       {
-         list = list_new ();
-         lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level - 1]);
+  if (circuit->area->lspdb[level - 1] == NULL ||
+      dict_count (circuit->area->lspdb[level - 1]) == 0)
+    return ISIS_OK;
 
-         if (listcount (list) > 0)
-           {
-             if (circuit->snd_stream == NULL)
-               circuit->snd_stream = stream_new (ISO_MTU (circuit));
-             else
-               stream_reset (circuit->snd_stream);
+  if (! circuit->snd_stream)
+    return ISIS_ERROR;
 
+  num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
 
-             if (isis->debugs & DEBUG_SNP_PACKETS)
-               zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
-                           circuit->area->area_tag, level,
-                           circuit->interface->name,
-                           /* FIXME: use %z when we stop supporting old
-                            * compilers. */
-                           (unsigned long) STREAM_SIZE (circuit->snd_stream));
+  while (1)
+    {
+      list = list_new ();
+      lsp_build_list_ssn (circuit, num_lsps, list,
+                          circuit->area->lspdb[level - 1]);
+
+      if (listcount (list) == 0)
+        {
+          list_delete (list);
+          return ISIS_OK;
+        }
+
+      retval = build_psnp (level, circuit, list);
+      if (retval != ISIS_OK)
+        {
+          zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
+                    circuit->area->area_tag, level, circuit->interface->name);
+          list_delete (list);
+          return retval;
+        }
 
-             retval = build_psnp (level, circuit, list);
-             if (retval == ISIS_OK)
-               retval = circuit->tx (circuit, level);
+      if (isis->debugs & DEBUG_SNP_PACKETS)
+        {
+          zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
+                      circuit->area->area_tag, level,
+                      circuit->interface->name,
+                      stream_get_endp (circuit->snd_stream));
+          if (isis->debugs & DEBUG_PACKET_DUMP)
+            zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+                            stream_get_endp (circuit->snd_stream));
+        }
+
+      retval = circuit->tx (circuit, level);
+      if (retval != ISIS_OK)
+        {
+          zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
+                    circuit->area->area_tag, level,
+                    circuit->interface->name);
+          list_delete (list);
+          return retval;
+        }
 
-             if (retval == ISIS_OK)
-               {
-                 /*
-                  * sending succeeded, we can clear SSN flags of this circuit
-                  * for the LSPs in list
-                  */
-                 for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
-                    ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
-               }
-           }
-         list_delete (list);
-       }
+      /*
+       * sending succeeded, we can clear SSN flags of this circuit
+       * for the LSPs in list
+       */
+      for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
+        ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
+      list_delete (list);
     }
 
   return retval;
@@ -2536,90 +3021,80 @@ send_lsp (struct thread *thread)
   struct isis_circuit *circuit;
   struct isis_lsp *lsp;
   struct listnode *node;
-  int retval = 0;
+  int retval = ISIS_OK;
 
   circuit = THREAD_ARG (thread);
   assert (circuit);
 
-  if (circuit->state != C_STATE_UP || circuit->interface == NULL)
-    return ISIS_WARNING;
+  if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
+  {
+    return retval;
+  }
 
   lsp = listgetdata ((node = listhead (circuit->lsp_queue)));
 
   /*
    * Do not send if levels do not match
    */
-  if (!(lsp->level & circuit->circuit_is_type))
-    goto dontsend;
+  if (!(lsp->level & circuit->is_type))
+    {
+      list_delete_node (circuit->lsp_queue, node);
+      return retval;
+    }
 
   /*
    * Do not send if we do not have adjacencies in state up on the circuit
    */
   if (circuit->upadjcount[lsp->level - 1] == 0)
-    goto dontsend;
-  /* only send if it needs sending */
-  if ((time (NULL) - lsp->last_sent) >=
-      circuit->area->lsp_gen_interval[lsp->level - 1])
     {
+      list_delete_node (circuit->lsp_queue, node);
+      return retval;
+    }
 
-      if (isis->debugs & DEBUG_UPDATE_PACKETS)
-       {
-         zlog_debug
-           ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
-            " lifetime %us on %s", circuit->area->area_tag, lsp->level,
-            rawlspid_print (lsp->lsp_header->lsp_id),
-            ntohl (lsp->lsp_header->seq_num),
-            ntohs (lsp->lsp_header->checksum),
-            ntohs (lsp->lsp_header->rem_lifetime),
-            circuit->interface->name);
-       }
-       /* copy our lsp to the send buffer */
-       stream_copy (circuit->snd_stream, lsp->pdu);
+  /* copy our lsp to the send buffer */
+  stream_copy (circuit->snd_stream, lsp->pdu);
 
-       retval = circuit->tx (circuit, lsp->level);
+  if (isis->debugs & DEBUG_UPDATE_PACKETS)
+    {
+      zlog_debug
+        ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
+         " lifetime %us on %s", circuit->area->area_tag, lsp->level,
+         rawlspid_print (lsp->lsp_header->lsp_id),
+         ntohl (lsp->lsp_header->seq_num),
+         ntohs (lsp->lsp_header->checksum),
+         ntohs (lsp->lsp_header->rem_lifetime),
+         circuit->interface->name);
+      if (isis->debugs & DEBUG_PACKET_DUMP)
+        zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+                        stream_get_endp (circuit->snd_stream));
+    }
+
+  retval = circuit->tx (circuit, lsp->level);
+  if (retval != ISIS_OK)
+    {
+      zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed",
+                circuit->area->area_tag, lsp->level,
+                circuit->interface->name);
+      return retval;
+    }
 
-      /*
-       * If the sending succeeded, we can del the lsp from circuits
-       * lsp_queue
-       */
-      if (retval == ISIS_OK)
-       {
-         list_delete_node (circuit->lsp_queue, node);
+  /*
+   * If the sending succeeded, we can del the lsp from circuits
+   * lsp_queue
+   */
+  list_delete_node (circuit->lsp_queue, node);
 
-         /*
-          * On broadcast circuits also the SRMflag can be cleared
-          */
-         if (circuit->circ_type == CIRCUIT_T_BROADCAST)
-           ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+  /* Set the last-cleared time if the queue is empty. */
+  /* TODO: Is is possible that new lsps keep being added to the queue
+   * that the queue is never empty? */
+  if (list_isempty (circuit->lsp_queue))
+    circuit->lsp_queue_last_cleared = time (NULL);
 
-         if (flags_any_set (lsp->SRMflags) == 0)
-           {
-             /*
-              * need to remember when we were last sent
-              */
-             lsp->last_sent = time (NULL);
-           }
-       }
-      else
-       {
-         zlog_debug ("sending of level %d link state failed", lsp->level);
-       }
-    }
-  else
-    {
-      /* my belief is that if it wasn't his time, the lsp can be removed
-       * from the queue
-       */
-    dontsend:
-      list_delete_node (circuit->lsp_queue, node);
-    }
-#if 0
   /*
-   * If there are still LSPs send next one after lsp-interval (33 msecs)
+   * On broadcast circuits also the SRMflag can be cleared
    */
-  if (listcount (circuit->lsp_queue) > 0)
-    thread_add_timer (master, send_lsp, circuit, 1);
-#endif
+  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+    ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 
   return retval;
 }
@@ -2638,8 +3113,8 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
   else
     stream_reset (circuit->snd_stream);
 
-//  fill_llc_hdr (stream);
-  if (level == 1)
+  //  fill_llc_hdr (stream);
+  if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
                              circuit->snd_stream);
   else
@@ -2664,7 +3139,10 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
   stream_putw_at (circuit->snd_stream, lenp, length);
 
   retval = circuit->tx (circuit, level);
+  if (retval != ISIS_OK)
+    zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
+              circuit->area->area_tag, level,
+              circuit->interface->name);
 
   return retval;
 }
-
index c4c38e22a2d5e1ecf11b34b0ad79b4658943bd16..3eca7319389144a0b7bd13b635e5980228f9e802 100644 (file)
@@ -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
 
@@ -114,7 +114,7 @@ struct isis_fixed_hdr
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  * |                        Holding  Time                          | 2     
  * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        PDU Lenght                             | 2    
+ * |                        PDU Length                             | 2    
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  * |   R   |                Priority                               | 1
  * +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -142,7 +142,7 @@ struct isis_lan_hello_hdr
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  * +                        Holding  Time                          + 2     
  * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        PDU Lenght                             + 2    
+ * +                        PDU Length                             + 2    
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  * |                        Local Circuit ID                       | 1
  * +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -186,12 +186,23 @@ 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
 /*
  *      L1 and L2 IS to IS complete sequence numbers PDU header
  * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        PDU Lenght                             + 2    
+ * +                        PDU Length                             + 2    
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  * +                        Source ID                              + id_len + 1
  * +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -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,7 +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);
 
-#define ISIS_AUTH_MD5_SIZE       16U
-int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c);
-
 #endif /* _ZEBRA_ISIS_PDU_H */
index 8a5c3ed063088608418917bb7b1f7077a7490c87..42947b22cdeb991ec96d65cdf8146aa92d813c6c 100644 (file)
@@ -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;
@@ -232,19 +231,16 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
                        LLC_LEN, MSG_PEEK,
                        (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
 
-  if (!circuit->area) {
-    return ISIS_OK;
-  }
-
   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;
     }
   /*
@@ -253,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);
@@ -289,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;
     }
 
@@ -313,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
    */
@@ -325,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);
@@ -336,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;
 }
@@ -351,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;
 
index 1286486cec6b95bcca8e22f35152d86088e6a456..c99d95831e5e16c1221474d320138baf4149ade1 100644 (file)
@@ -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)
 {
@@ -246,6 +244,7 @@ adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
        {
          nh = isis_nexthop_create (ipv4_addr,
                                    adj->circuit->interface->ifindex);
+          nh->router_address = adj->router_address;
          listnode_add (nexthops, nh);
        }
     }
@@ -269,6 +268,7 @@ adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
        {
          nh6 = isis_nexthop6_create (ipv6_addr,
                                      adj->circuit->interface->ifindex);
+          nh6->router_address6 = adj->router_address6;
          listnode_add (nexthops6, nh6);
        }
     }
@@ -276,8 +276,8 @@ adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
 #endif /* HAVE_IPV6 */
 
 static struct isis_route_info *
-isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
-                    struct list *adjacencies)
+isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth,
+                     struct list *adjacencies)
 {
   struct isis_route_info *rinfo;
   struct isis_adjacency *adj;
@@ -290,18 +290,34 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
       return NULL;
     }
 
-  if (family == AF_INET)
+  if (prefix->family == AF_INET)
     {
       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);
+          /* update neighbor router address */
+          if (depth == 2 && prefix->prefixlen == 32)
+            adj->router_address = prefix->u.prefix4;
+          adjinfo2nexthop (rinfo->nexthops, adj);
+        }
     }
 #ifdef HAVE_IPV6
-  if (family == AF_INET6)
+  if (prefix->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);
+          /* update neighbor router address */
+          if (depth == 2 && prefix->prefixlen == 128)
+            adj->router_address6 = prefix->u.prefix6;
+          adjinfo2nexthop6 (rinfo->nexthops6, adj);
+        }
     }
 
 #endif /* HAVE_IPV6 */
@@ -353,18 +369,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 +409,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,
@@ -459,7 +423,7 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
   /* for debugs */
   prefix2str (prefix, (char *) buff, BUFSIZ);
 
-  rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
+  rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies);
   if (!rinfo_new)
     {
       zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
@@ -479,68 +443,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 +498,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 +528,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 +636,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)
+{
+  if (area->is_type & IS_LEVEL_1)
+    isis_route_invalidate_table (area, area->route_table[0]);
+  if (area->is_type & IS_LEVEL_2)
+    isis_route_invalidate_table (area, area->route_table[1]);
 }
index 4eac79b863d7093cffb381fb9e99bb2eed8a4bbe..5adea2293b2edf907d19297f2c513e2babd9a9e2 100644 (file)
@@ -30,6 +30,7 @@ struct isis_nexthop6
 {
   unsigned int ifindex;
   struct in6_addr ip6;
+  struct in6_addr router_address6;
   unsigned int lock;
 };
 #endif /* HAVE_IPV6 */
@@ -38,13 +39,15 @@ struct isis_nexthop
 {
   unsigned int ifindex;
   struct in_addr ip;
+  struct in_addr router_address;
   unsigned int lock;
 };
 
 struct isis_route_info
 {
-#define ISIS_ROUTE_FLAG_ZEBRA_SYNC 0x01
-#define ISIS_ROUTE_FLAG_ACTIVE     0x02
+#define ISIS_ROUTE_FLAG_ACTIVE       0x01  /* active route for the prefix */
+#define ISIS_ROUTE_FLAG_ZEBRA_SYNCED 0x02  /* set when route synced to zebra */
+#define ISIS_ROUTE_FLAG_ZEBRA_RESYNC 0x04  /* set when route needs to sync */
   u_char flag;
   u_int32_t cost;
   u_int32_t depth;
@@ -59,6 +62,9 @@ struct isis_route_info *isis_route_create (struct prefix *prefix,
                                           struct list *adjacencies,
                                           struct isis_area *area, int level);
 
-int isis_route_validate (struct thread *thread);
+void isis_route_validate (struct isis_area *area);
+void isis_route_invalidate_table (struct isis_area *area,
+                                  struct route_table *table);
+void isis_route_invalidate (struct isis_area *area);
 
 #endif /* _ZEBRA_ISIS_ROUTE_H */
index cff0fa3ff96b40c8d616ad582819a27280633915..558d3910231f03230d64feb0a6e80e20eab42848 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "isis_constants.h"
 #include "isis_common.h"
+#include "isis_flags.h"
 #include "dict.h"
 #include "isisd.h"
 #include "isis_misc.h"
index 5d0b161f4755672ea05326011fbd4030588482c4..198104a98d22938c211ab27490f70875ea4f23f4 100644 (file)
@@ -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"
 #include "isis_route.h"
 #include "isis_csm.h"
 
-extern struct isis *isis;
-extern struct thread_master *master;
-extern struct host host;
-
 int isis_run_spf_l1 (struct thread *thread);
 int isis_run_spf_l2 (struct thread *thread);
 
@@ -113,7 +110,6 @@ remove_excess_adjs (struct list *adjs)
   return;
 }
 
-#ifdef EXTREME_DEBUG
 static const char *
 vtype2string (enum vertextype vtype)
 {
@@ -164,12 +160,12 @@ vid2string (struct isis_vertex *vertex, u_char * buff)
     {
     case VTYPE_PSEUDO_IS:
     case VTYPE_PSEUDO_TE_IS:
-      return rawlspid_print (vertex->N.id);
+      return print_sys_hostname (vertex->N.id);
       break;
     case VTYPE_NONPSEUDO_IS:
     case VTYPE_NONPSEUDO_TE_IS:
     case VTYPE_ES:
-      return sysid_print (vertex->N.id);
+      return print_sys_hostname (vertex->N.id);
       break;
     case VTYPE_IPREACH_INTERNAL:
     case VTYPE_IPREACH_EXTERNAL:
@@ -186,149 +182,265 @@ vid2string (struct isis_vertex *vertex, u_char * buff)
 
   return (char *) buff;
 }
-#endif /* EXTREME_DEBUG */
 
-static struct isis_spftree *
-isis_spftree_new ()
+static struct isis_vertex *
+isis_vertex_new (void *id, enum vertextype vtype)
 {
-  struct isis_spftree *tree;
+  struct isis_vertex *vertex;
 
-  tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
-  if (tree == NULL)
+  vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
+  if (vertex == NULL)
     {
-      zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
+      zlog_err ("isis_vertex_new Out of memory!");
       return NULL;
     }
 
-  tree->tents = list_new ();
-  tree->paths = list_new ();
-  return tree;
+  vertex->type = vtype;
+  switch (vtype)
+    {
+    case VTYPE_ES:
+    case VTYPE_NONPSEUDO_IS:
+    case VTYPE_NONPSEUDO_TE_IS:
+      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
+      break;
+    case VTYPE_PSEUDO_IS:
+    case VTYPE_PSEUDO_TE_IS:
+      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
+      break;
+    case VTYPE_IPREACH_INTERNAL:
+    case VTYPE_IPREACH_EXTERNAL:
+    case VTYPE_IPREACH_TE:
+#ifdef HAVE_IPV6
+    case VTYPE_IP6REACH_INTERNAL:
+    case VTYPE_IP6REACH_EXTERNAL:
+#endif /* HAVE_IPV6 */
+      memcpy (&vertex->N.prefix, (struct prefix *) id,
+             sizeof (struct prefix));
+      break;
+    default:
+      zlog_err ("WTF!");
+    }
+
+  vertex->Adj_N = list_new ();
+  vertex->parents = list_new ();
+  vertex->children = list_new ();
+
+  return vertex;
 }
 
 static void
 isis_vertex_del (struct isis_vertex *vertex)
 {
   list_delete (vertex->Adj_N);
+  vertex->Adj_N = NULL;
+  list_delete (vertex->parents);
+  vertex->parents = NULL;
+  list_delete (vertex->children);
+  vertex->children = NULL;
 
+  memset(vertex, 0, sizeof(struct isis_vertex));
   XFREE (MTYPE_ISIS_VERTEX, vertex);
 
   return;
 }
 
-#if 0 /* HT: Not used yet. */
 static void
+isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj)
+{
+  struct listnode *node, *nextnode;
+  if (!vertex)
+    return;
+  for (node = listhead (vertex->Adj_N); node; node = nextnode)
+  {
+    nextnode = listnextnode(node);
+    if (listgetdata(node) == adj)
+      list_delete_node(vertex->Adj_N, node);
+  }
+  return;
+}
+
+struct isis_spftree *
+isis_spftree_new (struct isis_area *area)
+{
+  struct isis_spftree *tree;
+
+  tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
+  if (tree == NULL)
+    {
+      zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
+      return NULL;
+    }
+
+  tree->tents = list_new ();
+  tree->paths = list_new ();
+  tree->area = area;
+  tree->last_run_timestamp = 0;
+  tree->last_run_duration = 0;
+  tree->runcount = 0;
+  tree->pending = 0;
+  return tree;
+}
+
+void
 isis_spftree_del (struct isis_spftree *spftree)
 {
+  THREAD_TIMER_OFF (spftree->t_spf);
+
   spftree->tents->del = (void (*)(void *)) isis_vertex_del;
   list_delete (spftree->tents);
+  spftree->tents = NULL;
 
   spftree->paths->del = (void (*)(void *)) isis_vertex_del;
   list_delete (spftree->paths);
+  spftree->paths = NULL;
 
   XFREE (MTYPE_ISIS_SPFTREE, spftree);
 
   return;
 }
-#endif 
+
+void
+isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
+{
+  struct listnode *node;
+  if (!adj)
+    return;
+  for (node = listhead (spftree->tents); node; node = listnextnode (node))
+    isis_vertex_adj_del (listgetdata (node), adj);
+  for (node = listhead (spftree->paths); node; node = listnextnode (node))
+    isis_vertex_adj_del (listgetdata (node), adj);
+  return;
+}
 
 void
 spftree_area_init (struct isis_area *area)
 {
-  if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL)
-    {
-      area->spftree[0] = isis_spftree_new ();
+  if (area->is_type & IS_LEVEL_1)
+  {
+    if (area->spftree[0] == NULL)
+      area->spftree[0] = isis_spftree_new (area);
 #ifdef HAVE_IPV6
-      area->spftree6[0] = isis_spftree_new ();
+    if (area->spftree6[0] == NULL)
+      area->spftree6[0] = isis_spftree_new (area);
 #endif
+  }
 
-      /*    thread_add_timer (master, isis_run_spf_l1, area, 
-         isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
-    }
-
-  if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL)
-    {
-      area->spftree[1] = isis_spftree_new ();
+  if (area->is_type & IS_LEVEL_2)
+  {
+    if (area->spftree[1] == NULL)
+      area->spftree[1] = isis_spftree_new (area);
 #ifdef HAVE_IPV6
-      area->spftree6[1] = isis_spftree_new ();
+    if (area->spftree6[1] == NULL)
+      area->spftree6[1] = isis_spftree_new (area);
 #endif
-      /*    thread_add_timer (master, isis_run_spf_l2, area, 
-         isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
-    }
+  }
 
   return;
 }
 
-static struct isis_vertex *
-isis_vertex_new (void *id, enum vertextype vtype)
+void
+spftree_area_del (struct isis_area *area)
 {
-  struct isis_vertex *vertex;
-
-  vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
-  if (vertex == NULL)
+  if (area->is_type & IS_LEVEL_1)
+  {
+    if (area->spftree[0] != NULL)
     {
-      zlog_err ("isis_vertex_new Out of memory!");
-      return NULL;
+      isis_spftree_del (area->spftree[0]);
+      area->spftree[0] = NULL;
+    }
+#ifdef HAVE_IPV6
+    if (area->spftree6[0])
+    {
+      isis_spftree_del (area->spftree6[0]);
+      area->spftree6[0] = NULL;
     }
+#endif
+  }
 
-  vertex->type = vtype;
-  switch (vtype)
+  if (area->is_type & IS_LEVEL_2)
+  {
+    if (area->spftree[1] != NULL)
     {
-    case VTYPE_ES:
-    case VTYPE_NONPSEUDO_IS:
-    case VTYPE_NONPSEUDO_TE_IS:
-      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
-      break;
-    case VTYPE_PSEUDO_IS:
-    case VTYPE_PSEUDO_TE_IS:
-      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
-      break;
-    case VTYPE_IPREACH_INTERNAL:
-    case VTYPE_IPREACH_EXTERNAL:
-    case VTYPE_IPREACH_TE:
+      isis_spftree_del (area->spftree[1]);
+      area->spftree[1] = NULL;
+    }
 #ifdef HAVE_IPV6
-    case VTYPE_IP6REACH_INTERNAL:
-    case VTYPE_IP6REACH_EXTERNAL:
-#endif /* HAVE_IPV6 */
-      memcpy (&vertex->N.prefix, (struct prefix *) id,
-             sizeof (struct prefix));
-      break;
-    default:
-      zlog_err ("WTF!");
+    if (area->spftree[1] != NULL)
+    {
+      isis_spftree_del (area->spftree6[1]);
+      area->spftree6[1] = NULL;
     }
+#endif
+  }
 
-  vertex->Adj_N = list_new ();
+  return;
+}
 
-  return vertex;
+void
+spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
+{
+  if (area->is_type & IS_LEVEL_1)
+  {
+    if (area->spftree[0] != NULL)
+      isis_spftree_adj_del (area->spftree[0], adj);
+#ifdef HAVE_IPV6
+    if (area->spftree6[0] != NULL)
+      isis_spftree_adj_del (area->spftree6[0], adj);
+#endif
+  }
+
+  if (area->is_type & IS_LEVEL_2)
+  {
+    if (area->spftree[1] != NULL)
+      isis_spftree_adj_del (area->spftree[1], adj);
+#ifdef HAVE_IPV6
+    if (area->spftree6[1] != NULL)
+      isis_spftree_adj_del (area->spftree6[1], adj);
+#endif
+  }
+
+  return;
+}
+
+/* 
+ * Find the system LSP: returns the LSP in our LSP database 
+ * associated with the given system ID.
+ */
+static struct isis_lsp *
+isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
+{
+  struct isis_lsp *lsp;
+  u_char lspid[ISIS_SYS_ID_LEN + 2];
+
+  memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
+  LSP_PSEUDO_ID (lspid) = 0;
+  LSP_FRAGMENT (lspid) = 0;
+  lsp = lsp_search (lspid, area->lspdb[level - 1]);
+  if (lsp && lsp->lsp_header->rem_lifetime != 0)
+    return lsp;
+  return NULL;
 }
 
 /*
  * Add this IS to the root of SPT
  */
-static void
-isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
-                  int level)
+static struct isis_vertex *
+isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
 {
   struct isis_vertex *vertex;
   struct isis_lsp *lsp;
-  u_char lspid[ISIS_SYS_ID_LEN + 2];
 #ifdef EXTREME_DEBUG
   u_char buff[BUFSIZ];
 #endif /* EXTREME_DEBUG */
-  memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
-  LSP_PSEUDO_ID (lspid) = 0;
-  LSP_FRAGMENT (lspid) = 0;
-
-  lsp = lsp_search (lspid, area->lspdb[level - 1]);
 
+  lsp = isis_root_system_lsp (spftree->area, level, sysid);
   if (lsp == NULL)
     zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
 
-  if (!area->oldmetric)
-    vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_TE_IS);
+  if (!spftree->area->oldmetric)
+    vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
   else
-    vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
-
-  vertex->lsp = lsp;
+    vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
 
   listnode_add (spftree->paths, vertex);
 
@@ -338,7 +450,7 @@ isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
              vertex->depth, vertex->d_N);
 #endif /* EXTREME_DEBUG */
 
-  return;
+  return vertex;
 }
 
 static struct isis_vertex *
@@ -390,26 +502,40 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
  */
 static struct isis_vertex *
 isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
-                  void *id, struct isis_adjacency *adj, u_int32_t cost,
-                  int depth, int family)
+                  void *id, uint32_t cost, int depth, int family,
+                  struct isis_adjacency *adj, struct isis_vertex *parent)
 {
   struct isis_vertex *vertex, *v;
   struct listnode *node;
+  struct isis_adjacency *parent_adj;
 #ifdef EXTREME_DEBUG
   u_char buff[BUFSIZ];
 #endif
 
+  assert (isis_find_vertex (spftree->paths, id, vtype) == NULL);
+  assert (isis_find_vertex (spftree->tents, id, vtype) == NULL);
   vertex = isis_vertex_new (id, vtype);
   vertex->d_N = cost;
   vertex->depth = depth;
 
-  if (adj)
+  if (parent) {
+    listnode_add (vertex->parents, parent);
+    if (listnode_lookup (parent->children, vertex) == NULL)
+      listnode_add (parent->children, vertex);
+  }
+
+  if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
+    for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
+      listnode_add (vertex->Adj_N, parent_adj);
+  } else if (adj) {
     listnode_add (vertex->Adj_N, adj);
+  }
 
 #ifdef EXTREME_DEBUG
-  zlog_debug ("ISIS-Spf: add to TENT  %s %s depth %d dist %d",
+  zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
+              print_sys_hostname (vertex->N.id),
              vtype2string (vertex->type), vid2string (vertex, buff),
-             vertex->depth, vertex->d_N);
+             vertex->depth, vertex->d_N, listcount(vertex->Adj_N));
 #endif /* EXTREME_DEBUG */
 
   if (list_isempty (spftree->tents))
@@ -417,8 +543,8 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
       listnode_add (spftree->tents, vertex);
       return vertex;
     }
-  
-  /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */
+
+  /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
   for (node = listhead (spftree->tents); node; node = listnextnode (node))
     {
       v = listgetdata (node);
@@ -427,35 +553,24 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
          list_add_node_prev (spftree->tents, node, vertex);
          break;
        }
-      else if (v->d_N == vertex->d_N)
+      else if (v->d_N == vertex->d_N && v->type > vertex->type)
        {
          /*  Tie break, add according to type */
-         while (v && v->d_N == vertex->d_N && v->type > vertex->type)
-           {
-             if (v->type > vertex->type)
-               {
-                 break;
-               }
-              /* XXX: this seems dubious, node is the loop iterator */
-             node = listnextnode (node);
-             (node) ? (v = listgetdata (node)) : (v = NULL);
-           }
-         list_add_node_prev (spftree->tents, node, vertex);
-         break;
-       }
-      else if (node->next == NULL)
-       {
-         list_add_node_next (spftree->tents, node, vertex);
+          list_add_node_prev (spftree->tents, node, vertex);
          break;
        }
     }
+
+  if (node == NULL)
+      listnode_add (spftree->tents, vertex);
+
   return vertex;
 }
 
-static struct isis_vertex *
+static void
 isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
-                   void *id, struct isis_adjacency *adj, u_int32_t cost,
-                   int family)
+                   void *id, struct isis_adjacency *adj, uint32_t cost,
+                   int family, struct isis_vertex *parent)
 {
   struct isis_vertex *vertex;
 
@@ -471,40 +586,65 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
          /*       d) */
          if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
            remove_excess_adjs (vertex->Adj_N);
+         if (parent && (listnode_lookup (vertex->parents, parent) == NULL))
+           listnode_add (vertex->parents, parent);
+         if (parent && (listnode_lookup (parent->children, vertex) == NULL))
+           listnode_add (parent->children, vertex);
+         return;
        }
-      /*         f) */
-      else if (vertex->d_N > cost)
+      else if (vertex->d_N < cost)
        {
-         listnode_delete (spftree->tents, vertex);
-         goto add2tent;
+         /*       e) do nothing */
+         return;
        }
-      /*       e) do nothing */
-      return vertex;
+      else {  /* vertex->d_N > cost */
+         /*         f) */
+         struct listnode *pnode, *pnextnode;
+         struct isis_vertex *pvertex;
+         listnode_delete (spftree->tents, vertex);
+         assert (listcount (vertex->children) == 0);
+         for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
+           listnode_delete(pvertex->children, vertex);
+         isis_vertex_del (vertex);
+      }
     }
 
-add2tent:
-  return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
+  isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
+  return;
 }
 
 static void
 process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
-          u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
-          int family)
+          uint32_t dist, uint16_t depth, int family,
+          struct isis_vertex *parent)
 {
   struct isis_vertex *vertex;
 #ifdef EXTREME_DEBUG
   u_char buff[255];
 #endif
 
+  assert (spftree && parent);
+
+  /* RFC3787 section 5.1 */
+  if (spftree->area->newmetric == 1)
+    {
+      if (dist > MAX_WIDE_PATH_METRIC)
+        return;
+    }
   /* C.2.6 b)    */
-  if (dist > MAX_PATH_METRIC)
-    return;
+  else if (spftree->area->oldmetric == 1)
+    {
+      if (dist > MAX_NARROW_PATH_METRIC)
+        return;
+    }
+
   /*       c)    */
   vertex = isis_find_vertex (spftree->paths, id, vtype);
   if (vertex)
     {
 #ifdef EXTREME_DEBUG
-      zlog_debug ("ISIS-Spf: process_N  %s %s dist %d already found from PATH",
+      zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
+                 print_sys_hostname (vertex->N.id),
                  vtype2string (vtype), vid2string (vertex, buff), dist);
 #endif /* EXTREME_DEBUG */
       assert (dist >= vertex->d_N);
@@ -517,16 +657,26 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
     {
       /*        1) */
 #ifdef EXTREME_DEBUG
-      zlog_debug ("ISIS-Spf: process_N  %s %s dist %d",
-                 vtype2string (vtype), vid2string (vertex, buff), dist);
+      zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
+                 print_sys_hostname (vertex->N.id),
+                  vtype2string (vtype), vid2string (vertex, buff), dist,
+                  (parent ? print_sys_hostname (parent->N.id) : "null"),
+                  (parent ? listcount (parent->Adj_N) : 0));
 #endif /* EXTREME_DEBUG */
       if (vertex->d_N == dist)
        {
-         if (adj)
-           listnode_add (vertex->Adj_N, adj);
+         struct listnode *node;
+         struct isis_adjacency *parent_adj;
+         for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
+           if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL)
+             listnode_add (vertex->Adj_N, parent_adj);
          /*      2) */
          if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
            remove_excess_adjs (vertex->Adj_N);
+         if (listnode_lookup (vertex->parents, parent) == NULL)
+           listnode_add (vertex->parents, parent);
+         if (listnode_lookup (parent->children, vertex) == NULL)
+           listnode_add (parent->children, vertex);
          /*      3) */
          return;
        }
@@ -537,11 +687,23 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
        }
       else
        {
+         struct listnode *pnode, *pnextnode;
+         struct isis_vertex *pvertex;
          listnode_delete (spftree->tents, vertex);
+         assert (listcount (vertex->children) == 0);
+         for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
+           listnode_delete(pvertex->children, vertex);
+         isis_vertex_del (vertex);
        }
     }
 
-  isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
+#ifdef EXTREME_DEBUG
+  zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
+              print_sys_hostname(id), vtype2string (vtype), dist,
+              (parent ? print_sys_hostname (parent->N.id) : "null"));
+#endif /* EXTREME_DEBUG */
+
+  isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
   return;
 }
 
@@ -551,10 +713,10 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
 static int
 isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
                      uint32_t cost, uint16_t depth, int family,
-                     struct isis_adjacency *adj)
+                     u_char *root_sysid, struct isis_vertex *parent)
 {
   struct listnode *node, *fragnode = NULL;
-  u_int16_t dist;
+  uint32_t dist;
   struct is_neigh *is_neigh;
   struct te_is_neigh *te_is_neigh;
   struct ipv4_reachability *ipreach;
@@ -564,114 +726,121 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
 #ifdef HAVE_IPV6
   struct ipv6_reachability *ip6reach;
 #endif /* HAVE_IPV6 */
+  static const u_char null_sysid[ISIS_SYS_ID_LEN];
 
-  if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family))
+  if (!speaks (lsp->tlv_data.nlpids, family))
     return ISIS_OK;
 
 lspfragloop:
   if (lsp->lsp_header->seq_num == 0)
     {
-      zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
-                " - do not process");
+      zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
       return ISIS_WARNING;
     }
 
+#ifdef EXTREME_DEBUG
+      zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
+#endif /* EXTREME_DEBUG */
+
   if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+  {
+    if (lsp->tlv_data.is_neighs)
     {
-      if (lsp->tlv_data.is_neighs)
-       {
-          for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
-           {
-             /* C.2.6 a) */
-             /* Two way connectivity */
-             if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
-               continue;
-             dist = cost + is_neigh->metrics.metric_default;
-             vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
-               : VTYPE_NONPSEUDO_IS;
-             process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
-                        depth + 1, adj, family);
-           }
-       }
-      if (lsp->tlv_data.te_is_neighs)
-       {
-         for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
-                                    te_is_neigh))
-           {
-             uint32_t metric;
-             if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
-               continue;
-             memcpy (&metric, te_is_neigh->te_metric, 3);
-             dist = cost + ntohl (metric << 8);
-             vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
-               : VTYPE_NONPSEUDO_TE_IS;
-             process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
-                        depth + 1, adj, family);
-           }
-       }
-      if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
-       {
-         prefix.family = AF_INET;
-          for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, 
-                                     node, ipreach))
-           {
-             dist = cost + ipreach->metrics.metric_default;
-             vtype = VTYPE_IPREACH_INTERNAL;
-             prefix.u.prefix4 = ipreach->prefix;
-             prefix.prefixlen = ip_masklen (ipreach->mask);
-             process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                        adj, family);
-           }
-       }
+      for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
+      {
+        /* C.2.6 a) */
+        /* Two way connectivity */
+        if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
+          continue;
+        if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+          continue;
+        dist = cost + is_neigh->metrics.metric_default;
+        vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+          : VTYPE_NONPSEUDO_IS;
+        process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
+            depth + 1, family, parent);
+      }
+    }
+    if (lsp->tlv_data.te_is_neighs)
+    {
+      for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
+            te_is_neigh))
+      {
+        if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
+          continue;
+        if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+          continue;
+        dist = cost + GET_TE_METRIC(te_is_neigh);
+        vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+          : VTYPE_NONPSEUDO_TE_IS;
+        process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
+            depth + 1, family, parent);
+      }
+    }
+  }
 
-      if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
-       {
-         prefix.family = AF_INET;
-          for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs,
-                                     node, ipreach))
-           {
-             dist = cost + ipreach->metrics.metric_default;
-             vtype = VTYPE_IPREACH_EXTERNAL;
-             prefix.u.prefix4 = ipreach->prefix;
-             prefix.prefixlen = ip_masklen (ipreach->mask);
-             process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                        adj, family);
-           }
-       }
-      if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
-       {
-         prefix.family = AF_INET;
-         for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
-                                    node, te_ipv4_reach))
-           {
-             dist = cost + ntohl (te_ipv4_reach->te_metric);
-             vtype = VTYPE_IPREACH_TE;
-             prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
-                                                  te_ipv4_reach->control);
-             prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
-             process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                        adj, family);
-           }
-       }
+  if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
+  {
+    prefix.family = AF_INET;
+    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
+    {
+      dist = cost + ipreach->metrics.metric_default;
+      vtype = VTYPE_IPREACH_INTERNAL;
+      prefix.u.prefix4 = ipreach->prefix;
+      prefix.prefixlen = ip_masklen (ipreach->mask);
+      apply_mask (&prefix);
+      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+                 family, parent);
+    }
+  }
+  if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
+  {
+    prefix.family = AF_INET;
+    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
+    {
+      dist = cost + ipreach->metrics.metric_default;
+      vtype = VTYPE_IPREACH_EXTERNAL;
+      prefix.u.prefix4 = ipreach->prefix;
+      prefix.prefixlen = ip_masklen (ipreach->mask);
+      apply_mask (&prefix);
+      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+                 family, parent);
+    }
+  }
+  if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
+  {
+    prefix.family = AF_INET;
+    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
+                               node, te_ipv4_reach))
+    {
+      dist = cost + ntohl (te_ipv4_reach->te_metric);
+      vtype = VTYPE_IPREACH_TE;
+      prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
+                                           te_ipv4_reach->control);
+      prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
+      apply_mask (&prefix);
+      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+                 family, parent);
+    }
+  }
 #ifdef HAVE_IPV6
-      if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
-       {
-         prefix.family = AF_INET6;
-          for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, 
-                                     node, ip6reach))
-           {
-             dist = cost + ip6reach->metric;
-             vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
-               VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
-             prefix.prefixlen = ip6reach->prefix_len;
-             memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
-                     PSIZE (ip6reach->prefix_len));
-             process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                        adj, family);
-           }
-       }
-#endif /* HAVE_IPV6 */
+  if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
+  {
+    prefix.family = AF_INET6;
+    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
+    {
+      dist = cost + ip6reach->metric;
+      vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
+        VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
+      prefix.prefixlen = ip6reach->prefix_len;
+      memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
+              PSIZE (ip6reach->prefix_len));
+      apply_mask (&prefix);
+      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+                 family, parent);
     }
+  }
+#endif /* HAVE_IPV6 */
 
   if (fragnode == NULL)
     fragnode = listhead (lsp->lspu.frags);
@@ -689,14 +858,16 @@ lspfragloop:
 
 static int
 isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
-                            struct isis_lsp *lsp, uint16_t cost,
+                            struct isis_lsp *lsp, uint32_t cost,
                             uint16_t depth, int family,
-                            struct isis_adjacency *adj)
+                            u_char *root_sysid,
+                            struct isis_vertex *parent)
 {
   struct listnode *node, *fragnode = NULL;
   struct is_neigh *is_neigh;
   struct te_is_neigh *te_is_neigh;
   enum vertextype vtype;
+  uint32_t dist;
 
 pseudofragloop:
 
@@ -707,41 +878,36 @@ pseudofragloop:
       return ISIS_WARNING;
     }
 
+#ifdef EXTREME_DEBUG
+      zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
+                  print_sys_hostname(lsp->lsp_header->lsp_id));
+#endif /* EXTREME_DEBUG */
+
+  /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
+
   if (lsp->tlv_data.is_neighs)
     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
       {
-       vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
-         : VTYPE_NONPSEUDO_IS;
        /* Two way connectivity */
-       if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
+       if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
          continue;
-       if ((depth > 0 || isis_find_vertex
-           (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL)
-           && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id,
-                              vtype) == NULL)
-         {
-           /* C.2.5 i) */
-           isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, adj,
-                            cost, depth, family);
-         }
+        dist = cost + is_neigh->metrics.metric_default;
+        vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+          : VTYPE_NONPSEUDO_IS;
+        process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
+            depth + 1, family, parent);
       }
   if (lsp->tlv_data.te_is_neighs)
     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
       {
-       vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
-         : VTYPE_NONPSEUDO_TE_IS;
        /* Two way connectivity */
-       if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
+       if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
          continue;
-       if ((depth > 0 || isis_find_vertex
-            (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL)
-           && isis_find_vertex (spftree->paths, (void *) te_is_neigh->neigh_id,
-                                vtype) == NULL)
-         {
-           /* C.2.5 i) */
-           isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, adj,
-                              cost, depth, family);
-         }
+        dist = cost + GET_TE_METRIC(te_is_neigh);
+        vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+          : VTYPE_NONPSEUDO_TE_IS;
+        process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
+            depth + 1, family, parent);
       }
 
   if (fragnode == NULL)
@@ -759,10 +925,10 @@ pseudofragloop:
 }
 
 static int
-isis_spf_preload_tent (struct isis_spftree *spftree,
-                      struct isis_area *area, int level, int family)
+isis_spf_preload_tent (struct isis_spftree *spftree, int level,
+                      int family, u_char *root_sysid,
+                      struct isis_vertex *parent)
 {
-  struct isis_vertex *vertex;
   struct isis_circuit *circuit;
   struct listnode *cnode, *anode, *ipnode;
   struct isis_adjacency *adj;
@@ -773,15 +939,16 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
   struct prefix prefix;
   int retval = ISIS_OK;
   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+  static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
 #ifdef HAVE_IPV6
   struct prefix_ipv6 *ipv6;
 #endif /* HAVE_IPV6 */
 
-  for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+  for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
     {
       if (circuit->state != C_STATE_UP)
        continue;
-      if (!(circuit->circuit_is_type & level))
+      if (!(circuit->is_type & level))
        continue;
       if (family == AF_INET && !circuit->ip_router)
        continue;
@@ -799,8 +966,9 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
            {
              prefix.u.prefix4 = ipv4->prefix;
              prefix.prefixlen = ipv4->prefixlen;
+              apply_mask (&prefix);
              isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
-                                 NULL, 0, family);
+                                 NULL, 0, family, parent);
            }
        }
 #ifdef HAVE_IPV6
@@ -811,8 +979,9 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
            {
              prefix.prefixlen = ipv6->prefixlen;
              prefix.u.prefix6 = ipv6->prefix;
+              apply_mask (&prefix);
              isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
-                                 &prefix, NULL, 0, family);
+                                 &prefix, NULL, 0, family, parent);
            }
        }
 #endif /* HAVE_IPV6 */
@@ -832,40 +1001,41 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
                            level, circuit->interface->name);
              continue;
            }
-         anode = listhead (adj_list);
-         while (anode)
+          for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
            {
-             adj = listgetdata (anode);
              if (!speaks (&adj->nlpids, family))
-               {
-                 anode = listnextnode (anode);
                  continue;
-               }
              switch (adj->sys_type)
                {
                case ISIS_SYSTYPE_ES:
                  isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
-                                     circuit->te_metric[level - 1], family);
+                                     circuit->te_metric[level - 1],
+                                     family, parent);
                  break;
                case ISIS_SYSTYPE_IS:
                case ISIS_SYSTYPE_L1_IS:
                case ISIS_SYSTYPE_L2_IS:
-                 vertex =
-                   isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
-                                       adj->sysid, adj,
-                                       circuit->te_metric[level - 1], family);
+                 isis_spf_add_local (spftree,
+                                      spftree->area->oldmetric ?
+                                      VTYPE_NONPSEUDO_IS :
+                                      VTYPE_NONPSEUDO_TE_IS,
+                                      adj->sysid, adj,
+                                      circuit->te_metric[level - 1],
+                                      family, parent);
                  memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
                  LSP_PSEUDO_ID (lsp_id) = 0;
                  LSP_FRAGMENT (lsp_id) = 0;
-                 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
-                 if (!lsp)
-                   zlog_warn ("No lsp found for IS adjacency");
+                 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+                  if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
+                    zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
+                        "L%d on %s (ID %u)",
+                       rawlspid_print (lsp_id), level,
+                       circuit->interface->name, circuit->circuit_id);
                  break;
                case ISIS_SYSTYPE_UNKNOWN:
                default:
                  zlog_warn ("isis_spf_preload_tent unknow adj type");
                }
-             anode = listnextnode (anode);
            }
          list_delete (adj_list);
          /*
@@ -875,23 +1045,36 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
            memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
          else
            memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
-         lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
+         /* can happen during DR reboot */
+         if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
+           {
+             if (isis->debugs & DEBUG_SPF_EVENTS)
+               zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
+                   level, circuit->interface->name, circuit->circuit_id);
+             continue;
+           }
          adj = isis_adj_lookup (lsp_id, adjdb);
          /* if no adj, we are the dis or error */
          if (!adj && !circuit->u.bc.is_dr[level - 1])
            {
-             zlog_warn ("ISIS-Spf: No adjacency found for DR");
-           }
-         else if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
-           {
-             zlog_warn ("ISIS-Spf: No lsp found for DR");
+              zlog_warn ("ISIS-Spf: No adjacency found from root "
+                  "to L%d DR %s on %s (ID %d)",
+                 level, rawlspid_print (lsp_id),
+                 circuit->interface->name, circuit->circuit_id);
+              continue;
            }
-         else
+         lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+         if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
            {
-             isis_spf_process_pseudo_lsp (spftree, lsp,
-                                           circuit->te_metric[level - 1], 0, family, adj);
-
+             zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
+                  "to L%d DR %s on %s (ID %d)",
+                 lsp, level, rawlspid_print (lsp_id), 
+                 circuit->interface->name, circuit->circuit_id);
+              continue;
            }
+         isis_spf_process_pseudo_lsp (spftree, lsp,
+                                       circuit->te_metric[level - 1], 0,
+                                       family, root_sysid, parent);
        }
       else if (circuit->circ_type == CIRCUIT_T_P2P)
        {
@@ -902,28 +1085,36 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
            {
            case ISIS_SYSTYPE_ES:
              isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
-                                 circuit->te_metric[level - 1], family);
+                                 circuit->te_metric[level - 1], family,
+                                 parent);
              break;
            case ISIS_SYSTYPE_IS:
            case ISIS_SYSTYPE_L1_IS:
            case ISIS_SYSTYPE_L2_IS:
              if (speaks (&adj->nlpids, family))
-               isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid,
+               isis_spf_add_local (spftree,
+                                   spftree->area->oldmetric ?
+                                    VTYPE_NONPSEUDO_IS :
+                                   VTYPE_NONPSEUDO_TE_IS,
+                                    adj->sysid,
                                    adj, circuit->te_metric[level - 1],
-                                   family);
+                                   family, parent);
              break;
            case ISIS_SYSTYPE_UNKNOWN:
            default:
-             zlog_warn ("isis_spf_preload_tent unknow adj type");
+             zlog_warn ("isis_spf_preload_tent unknown adj type");
              break;
            }
        }
+      else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
+       {
+          continue;
+        }
       else
        {
          zlog_warn ("isis_spf_preload_tent unsupported media");
          retval = ISIS_WARNING;
        }
-
     }
 
   return retval;
@@ -935,25 +1126,30 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
  */
 static void
 add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
-             struct isis_area *area, int level)
+             int level)
 {
-#ifdef EXTREME_DEBUG
   u_char buff[BUFSIZ];
-#endif /* EXTREME_DEBUG */
+
+  if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
+    return;
   listnode_add (spftree->paths, vertex);
 
 #ifdef EXTREME_DEBUG
-  zlog_debug ("ISIS-Spf: added  %s %s depth %d dist %d to PATHS",
+  zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
+              print_sys_hostname (vertex->N.id),
              vtype2string (vertex->type), vid2string (vertex, buff),
              vertex->depth, vertex->d_N);
 #endif /* EXTREME_DEBUG */
+
   if (vertex->type > VTYPE_ES)
     {
       if (listcount (vertex->Adj_N) > 0)
        isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
-                          vertex->depth, vertex->Adj_N, area, level);
+                          vertex->depth, vertex->Adj_N, spftree->area, level);
       else if (isis->debugs & DEBUG_SPF_EVENTS)
-       zlog_debug ("ISIS-Spf: no adjacencies do not install route");
+       zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
+                    "%s depth %d dist %d", vid2string (vertex, buff),
+                    vertex->depth, vertex->d_N);
     }
 
   return;
@@ -966,23 +1162,27 @@ init_spt (struct isis_spftree *spftree)
   list_delete_all_node (spftree->tents);
   list_delete_all_node (spftree->paths);
   spftree->tents->del = spftree->paths->del = NULL;
-
   return;
 }
 
 static int
-isis_run_spf (struct isis_area *area, int level, int family)
+isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 {
   int retval = ISIS_OK;
   struct listnode *node;
   struct isis_vertex *vertex;
+  struct isis_vertex *root_vertex;
   struct isis_spftree *spftree = NULL;
   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
   struct isis_lsp *lsp;
-  struct isis_adjacency *adj = NULL;
   struct route_table *table = NULL;
-  struct route_node *rode;
-  struct isis_route_info *rinfo;
+  struct timespec time_now;
+  unsigned long long start_time, end_time;
+
+  /* Get time that can't roll backwards. */
+  clock_gettime(CLOCK_MONOTONIC, &time_now);
+  start_time = time_now.tv_sec;
+  start_time = (start_time * 1000000) + (time_now.tv_nsec / 1000);
 
   if (family == AF_INET)
     spftree = area->spftree[level - 1];
@@ -990,8 +1190,8 @@ isis_run_spf (struct isis_area *area, int level, int family)
   else if (family == AF_INET6)
     spftree = area->spftree6[level - 1];
 #endif
-
   assert (spftree);
+  assert (sysid);
 
   /* Make all routes in current route table inactive. */
   if (family == AF_INET)
@@ -1001,71 +1201,66 @@ isis_run_spf (struct isis_area *area, int level, int family)
     table = area->route_table6[level - 1];
 #endif
 
-  for (rode = route_top (table); rode; rode = route_next (rode))
-    {
-      if (rode->info == NULL)
-        continue;
-      rinfo = rode->info;
-
-      UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
-    }
+  isis_route_invalidate_table (area, table);
 
   /*
    * C.2.5 Step 0
    */
   init_spt (spftree);
   /*              a) */
-  isis_spf_add_self (spftree, area, level);
+  root_vertex = isis_spf_add_root (spftree, level, sysid);
   /*              b) */
-  retval = isis_spf_preload_tent (spftree, area, level, family);
+  retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
+  if (retval != ISIS_OK)
+    {
+      zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
+      goto out;
+    }
 
   /*
    * C.2.7 Step 2
    */
   if (listcount (spftree->tents) == 0)
     {
-      zlog_warn ("ISIS-Spf: TENT is empty");
+      zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
       goto out;
     }
 
   while (listcount (spftree->tents) > 0)
     {
-      /* C.2.7 a) 1) */
       node = listhead (spftree->tents);
       vertex = listgetdata (node);
 
-      /* C.2.7 a) 2) */
-      list_delete_node (spftree->tents, node);
-
-      /* C.2.7 a) 3) */
-      if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
-       continue;
-      add_to_paths (spftree, vertex, area, level);
-
-      if (vertex->type == VTYPE_PSEUDO_IS ||
-         vertex->type == VTYPE_NONPSEUDO_IS ||
-         vertex->type == VTYPE_PSEUDO_TE_IS ||
-         vertex->type == VTYPE_NONPSEUDO_TE_IS )
-       {
-         if (listcount(vertex->Adj_N) == 0) {
-           continue;
-         }
-         adj = listgetdata(vertex->Adj_N->head);
+#ifdef EXTREME_DEBUG
+  zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
+              print_sys_hostname (vertex->N.id),
+             vtype2string (vertex->type), vertex->depth, vertex->d_N);
+#endif /* EXTREME_DEBUG */
 
+      /* Remove from tent list and add to paths list */
+      list_delete_node (spftree->tents, node);
+      add_to_paths (spftree, vertex, level);
+      switch (vertex->type)
+        {
+       case VTYPE_PSEUDO_IS:
+       case VTYPE_NONPSEUDO_IS:
+       case VTYPE_PSEUDO_TE_IS:
+       case VTYPE_NONPSEUDO_TE_IS:
          memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
          LSP_FRAGMENT (lsp_id) = 0;
          lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
-         if (lsp)
+         if (lsp && lsp->lsp_header->rem_lifetime != 0)
            {
              if (LSP_PSEUDO_ID (lsp_id))
                {
                  isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
-                                              vertex->depth, family, adj);
+                                              vertex->depth, family, sysid,
+                                              vertex);
                }
              else
                {
                  isis_spf_process_lsp (spftree, lsp, vertex->d_N,
-                                       vertex->depth, family, adj);
+                                       vertex->depth, family, sysid, vertex);
                }
            }
          else
@@ -1073,13 +1268,21 @@ isis_run_spf (struct isis_area *area, int level, int family)
              zlog_warn ("ISIS-Spf: No LSP found for %s",
                         rawlspid_print (lsp_id));
            }
+         break;
+       default:;
        }
     }
 
 out:
-  thread_add_event (master, isis_route_validate, area, 0);
-  spftree->lastrun = time (NULL);
+  isis_route_validate (area);
   spftree->pending = 0;
+  spftree->runcount++;
+  spftree->last_run_timestamp = time (NULL);
+  clock_gettime(CLOCK_MONOTONIC, &time_now);
+  end_time = time_now.tv_sec;
+  end_time = (end_time * 1000000) + (time_now.tv_nsec / 1000);
+  spftree->last_run_duration = end_time - start_time;
+
 
   return retval;
 }
@@ -1094,6 +1297,7 @@ isis_run_spf_l1 (struct thread *thread)
   assert (area);
 
   area->spftree[0]->t_spf = NULL;
+  area->spftree[0]->pending = 0;
 
   if (!(area->is_type & IS_LEVEL_1))
     {
@@ -1107,10 +1311,7 @@ isis_run_spf_l1 (struct thread *thread)
     zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
 
   if (area->ip_circuits)
-    retval = isis_run_spf (area, 1, AF_INET);
-
-  THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area,
-                  isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+    retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
 
   return retval;
 }
@@ -1125,6 +1326,7 @@ isis_run_spf_l2 (struct thread *thread)
   assert (area);
 
   area->spftree[1]->t_spf = NULL;
+  area->spftree[1]->pending = 0;
 
   if (!(area->is_type & IS_LEVEL_2))
     {
@@ -1137,10 +1339,7 @@ isis_run_spf_l2 (struct thread *thread)
     zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
 
   if (area->ip_circuits)
-    retval = isis_run_spf (area, 2, AF_INET);
-
-  THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area,
-                  isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+    retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
 
   return retval;
 }
@@ -1148,53 +1347,40 @@ isis_run_spf_l2 (struct thread *thread)
 int
 isis_spf_schedule (struct isis_area *area, int level)
 {
-  int retval = ISIS_OK;
   struct isis_spftree *spftree = area->spftree[level - 1];
-  time_t diff, now = time (NULL);
+  time_t now = time (NULL);
+  int diff = now - spftree->last_run_timestamp;
 
-  if (spftree->pending)
-    return retval;
+  assert (diff >= 0);
+  assert (area->is_type & level);
 
-  diff = now - spftree->lastrun;
-
-  /* FIXME: let's wait a minute before doing the SPF */
-  if (now - isis->uptime < 60 || isis->uptime == 0)
-    {
-      if (level == 1)
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60);
-      else
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60);
+  if (isis->debugs & DEBUG_SPF_EVENTS)
+    zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
+                area->area_tag, level, diff);
 
-      spftree->pending = 1;
-      return retval;
-    }
+  if (spftree->pending)
+    return ISIS_OK;
 
   THREAD_TIMER_OFF (spftree->t_spf);
 
-  if (diff < MINIMUM_SPF_INTERVAL)
-    {
-      if (level == 1)
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
-                        MINIMUM_SPF_INTERVAL - diff);
-      else
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
-                        MINIMUM_SPF_INTERVAL - diff);
+  /* wait configured min_spf_interval before doing the SPF */
+  if (diff >= area->min_spf_interval[level-1])
+      return isis_run_spf (area, level, AF_INET, isis->sysid);
 
-      spftree->pending = 1;
-    }
+  if (level == 1)
+    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
+                     area->min_spf_interval[0] - diff);
   else
-    {
-      spftree->pending = 0;
-      retval = isis_run_spf (area, level, AF_INET);
-      if (level == 1)
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
-                        isis_jitter (PERIODIC_SPF_INTERVAL, 10));
-      else
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
-                        isis_jitter (PERIODIC_SPF_INTERVAL, 10));
-    }
+    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
+                     area->min_spf_interval[1] - diff);
 
-  return retval;
+  if (isis->debugs & DEBUG_SPF_EVENTS)
+    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+                area->area_tag, level, area->min_spf_interval[level-1] - diff);
+
+  spftree->pending = 1;
+
+  return ISIS_OK;
 }
 
 #ifdef HAVE_IPV6
@@ -1208,11 +1394,12 @@ isis_run_spf6_l1 (struct thread *thread)
   assert (area);
 
   area->spftree6[0]->t_spf = NULL;
+  area->spftree6[0]->pending = 0;
 
   if (!(area->is_type & IS_LEVEL_1))
     {
       if (isis->debugs & DEBUG_SPF_EVENTS)
-       zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
+        zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
       return ISIS_WARNING;
     }
 
@@ -1220,10 +1407,7 @@ isis_run_spf6_l1 (struct thread *thread)
     zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
 
   if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 1, AF_INET6);
-
-  THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area,
-                  isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
 
   return retval;
 }
@@ -1238,6 +1422,7 @@ isis_run_spf6_l2 (struct thread *thread)
   assert (area);
 
   area->spftree6[1]->t_spf = NULL;
+  area->spftree6[1]->pending = 0;
 
   if (!(area->is_type & IS_LEVEL_2))
     {
@@ -1250,10 +1435,7 @@ isis_run_spf6_l2 (struct thread *thread)
     zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
 
   if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 2, AF_INET6);
-
-  THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area,
-                  isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
 
   return retval;
 }
@@ -1263,104 +1445,110 @@ isis_spf_schedule6 (struct isis_area *area, int level)
 {
   int retval = ISIS_OK;
   struct isis_spftree *spftree = area->spftree6[level - 1];
-  time_t diff, now = time (NULL);
+  time_t now = time (NULL);
+  time_t diff = now - spftree->last_run_timestamp;
 
-  if (spftree->pending)
-    return retval;
+  assert (diff >= 0);
+  assert (area->is_type & level);
 
-  diff = now - spftree->lastrun;
+  if (isis->debugs & DEBUG_SPF_EVENTS)
+    zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
+                area->area_tag, level, diff);
 
-  /* FIXME: let's wait a minute before doing the SPF */
-  if (now - isis->uptime < 60 || isis->uptime == 0)
-    {
-      if (level == 1)
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, 60);
-      else
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, 60);
+  if (spftree->pending)
+    return ISIS_OK;
 
-      spftree->pending = 1;
-      return retval;
-    }
-  
   THREAD_TIMER_OFF (spftree->t_spf);
 
-  if (diff < MINIMUM_SPF_INTERVAL)
-    {
-      if (level == 1)
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
-                        MINIMUM_SPF_INTERVAL - diff);
-      else
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
-                        MINIMUM_SPF_INTERVAL - diff);
+  /* wait configured min_spf_interval before doing the SPF */
+  if (diff >= area->min_spf_interval[level-1])
+      return isis_run_spf (area, level, AF_INET6, isis->sysid);
 
-      spftree->pending = 1;
-    }
+  if (level == 1)
+    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+                     area->min_spf_interval[0] - diff);
   else
-    {
-      spftree->pending = 0;
-      retval = isis_run_spf (area, level, AF_INET6);
+    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+                     area->min_spf_interval[1] - diff);
 
-      if (level == 1)
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
-                        isis_jitter (PERIODIC_SPF_INTERVAL, 10));
-      else
-       THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
-                        isis_jitter (PERIODIC_SPF_INTERVAL, 10));
-    }
+  if (isis->debugs & DEBUG_SPF_EVENTS)
+    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+                area->area_tag, level, area->min_spf_interval[level-1] - diff);
+
+  spftree->pending = 1;
 
   return retval;
 }
 #endif
 
 static void
-isis_print_paths (struct vty *vty, struct list *paths)
+isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
 {
   struct listnode *node;
+  struct listnode *anode;
   struct isis_vertex *vertex;
-  struct isis_dynhn *dyn, *nh_dyn = NULL;
   struct isis_adjacency *adj;
-#if 0
   u_char buff[255];
-#endif /* 0 */
 
-  vty_out (vty, "System Id            Metric     Next-Hop"
-          "             Interface   SNPA%s", VTY_NEWLINE);
+  vty_out (vty, "Vertex               Type         Metric "
+                "Next-Hop             Interface Parent%s", VTY_NEWLINE);
+
+  for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) {
+      if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
+       vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid),
+                "", "");
+       vty_out (vty, "%-30s", "");
+      } else {
+       int rows = 0;
+       vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff),
+                vtype2string (vertex->type), vertex->d_N);
+       for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) {
+         if (adj) {
+           if (rows) {
+               vty_out (vty, "%s", VTY_NEWLINE);
+               vty_out (vty, "%-20s %-12s %-6s ", "", "", "");
+           }
+           vty_out (vty, "%-20s %-9s ",
+                    print_sys_hostname (adj->sysid),
+                    adj->circuit->interface->name);
+           ++rows;
+         }
+       }
+       if (rows == 0)
+         vty_out (vty, "%-30s ", "");
+      }
 
-  for (ALL_LIST_ELEMENTS_RO (paths, node, vertex))
-    {
-      if (vertex->type != VTYPE_NONPSEUDO_IS)
-       continue;
-      if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
-       {
-         vty_out (vty, "%s             --%s", host.name?host.name:"",
-                  VTY_NEWLINE);
+      /* Print list of parents for the ECMP DAG */
+      if (listcount (vertex->parents) > 0) {
+       struct listnode *pnode;
+       struct isis_vertex *pvertex;
+       int rows = 0;
+       for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) {
+         if (rows) {
+           vty_out (vty, "%s", VTY_NEWLINE);
+           vty_out (vty, "%-72s", "");
+         }
+         vty_out (vty, "%s(%d)",
+                  vid2string (pvertex, buff), pvertex->type);
+         ++rows;
        }
-      else
-       {
-         dyn = dynhn_find_by_id ((u_char *) vertex->N.id);
-         adj = listgetdata (listhead (vertex->Adj_N));
-         if (adj)
-           {
-             nh_dyn = dynhn_find_by_id (adj->sysid);
-             vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
-                      (dyn != NULL) ? dyn->name.name :
-                      (const u_char *)rawlspid_print ((u_char *) vertex->N.id),
-                      vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
-                      (const u_char *)rawlspid_print (adj->sysid),
-                      adj->circuit->interface->name,
-                      snpa_print (adj->snpa), VTY_NEWLINE);
-           }
-         else
-           {
-             vty_out (vty, "%s              %u %s", dyn ? dyn->name.name :
-                      (const u_char *) rawlspid_print (vertex->N.id),
-                      vertex->d_N, VTY_NEWLINE);
+      } else {
+       vty_out (vty, "  NULL ");
+      }
+
+#if 0
+      if (listcount (vertex->children) > 0) {
+         struct listnode *cnode;
+         struct isis_vertex *cvertex;
+         for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) {
+             vty_out (vty, "%s", VTY_NEWLINE);
+             vty_out (vty, "%-72s", "");
+             vty_out (vty, "%s(%d) ", 
+                      vid2string (cvertex, buff), cvertex->type);
            }
        }
-#if 0
-      vty_out (vty, "%s %s %u %s", vtype2string (vertex->type),
-              vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);
 #endif
+      vty_out (vty, "%s", VTY_NEWLINE);
     }
 }
 
@@ -1390,7 +1578,8 @@ DEFUN (show_isis_topology,
            {
              vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
                       level + 1, VTY_NEWLINE);
-             isis_print_paths (vty, area->spftree[level]->paths);
+             isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
+             vty_out (vty, "%s", VTY_NEWLINE);
            }
 #ifdef HAVE_IPV6
          if (area->ipv6_circuits > 0 && area->spftree6[level]
@@ -1399,10 +1588,13 @@ DEFUN (show_isis_topology,
              vty_out (vty,
                       "IS-IS paths to level-%d routers that speak IPv6%s",
                       level + 1, VTY_NEWLINE);
-             isis_print_paths (vty, area->spftree6[level]->paths);
+             isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
+             vty_out (vty, "%s", VTY_NEWLINE);
            }
 #endif /* HAVE_IPV6 */
        }
+
+      vty_out (vty, "%s", VTY_NEWLINE);
     }
 
   return CMD_SUCCESS;
@@ -1432,7 +1624,8 @@ DEFUN (show_isis_topology_l1,
        {
          vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
                   VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree[0]->paths);
+         isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
+         vty_out (vty, "%s", VTY_NEWLINE);
        }
 #ifdef HAVE_IPV6
       if (area->ipv6_circuits > 0 && area->spftree6[0]
@@ -1440,9 +1633,11 @@ DEFUN (show_isis_topology_l1,
        {
          vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
                   VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree6[0]->paths);
+         isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
+         vty_out (vty, "%s", VTY_NEWLINE);
        }
 #endif /* HAVE_IPV6 */
+      vty_out (vty, "%s", VTY_NEWLINE);
     }
 
   return CMD_SUCCESS;
@@ -1472,7 +1667,8 @@ DEFUN (show_isis_topology_l2,
        {
          vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
                   VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree[1]->paths);
+         isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
+         vty_out (vty, "%s", VTY_NEWLINE);
        }
 #ifdef HAVE_IPV6
       if (area->ipv6_circuits > 0 && area->spftree6[1]
@@ -1480,9 +1676,11 @@ DEFUN (show_isis_topology_l2,
        {
          vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
                   VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree6[1]->paths);
+         isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
+         vty_out (vty, "%s", VTY_NEWLINE);
        }
 #endif /* HAVE_IPV6 */
+      vty_out (vty, "%s", VTY_NEWLINE);
     }
 
   return CMD_SUCCESS;
index 6bdab2da6b9382f6b2b7759c4bc15862594c0ef3..aa543b705d8d095140c0e4af7b3d76491329a7dd 100644 (file)
@@ -54,25 +54,33 @@ struct isis_vertex
     struct prefix prefix;
   } N;
 
-  struct isis_lsp *lsp;
   u_int32_t d_N;               /* d(N) Distance from this IS      */
   u_int16_t depth;             /* The depth in the imaginary tree */
-
-  struct list *Adj_N;          /* {Adj(N)}  */
+  struct list *Adj_N;          /* {Adj(N)} next hop or neighbor list */
+  struct list *parents;         /* list of parents for ECMP */
+  struct list *children;        /* list of children used for tree dump */
 };
 
 struct isis_spftree
 {
   struct thread *t_spf;                /* spf threads */
-  time_t lastrun;              /* for scheduling */
-  int pending;                 /* already scheduled */
   struct list *paths;          /* the SPT */
   struct list *tents;          /* TENT */
-
-  u_int32_t timerun;           /* statistics */
+  struct isis_area *area;       /* back pointer to area */
+  int pending;                 /* already scheduled */
+  unsigned int runcount;        /* number of runs since uptime */
+  time_t last_run_timestamp;    /* last run timestamp for scheduling */
+  time_t last_run_duration;     /* last run duration in msec */
 };
 
+struct isis_spftree * isis_spftree_new (struct isis_area *area);
+void isis_spftree_del (struct isis_spftree *spftree);
+void isis_spftree_adj_del (struct isis_spftree *spftree,
+                           struct isis_adjacency *adj);
 void spftree_area_init (struct isis_area *area);
+void spftree_area_del (struct isis_area *area);
+void spftree_area_adj_del (struct isis_area *area,
+                           struct isis_adjacency *adj);
 int isis_spf_schedule (struct isis_area *area, int level);
 void isis_spf_cmds_init (void);
 #ifdef HAVE_IPV6
index 3fc717e34845879aa55f047fe5174be04694ab35..bb57bd6be4d2f140d7e0d9e94e25443a8920ea6c 100644 (file)
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_lsp.h"
 
-extern struct isis *isis;
-
-/*
- * Prototypes.
- */
-int add_tlv (u_char, u_char, u_char *, struct stream *);
-
 void
 free_tlv (void *val)
 {
@@ -75,10 +68,10 @@ free_tlvs (struct tlvs *tlvs)
     list_delete (tlvs->es_neighs);
   if (tlvs->lsp_entries)
     list_delete (tlvs->lsp_entries);
-  if (tlvs->lan_neighs)
-    list_delete (tlvs->lan_neighs);
   if (tlvs->prefix_neighs)
     list_delete (tlvs->prefix_neighs);
+  if (tlvs->lan_neighs)
+    list_delete (tlvs->lan_neighs);
   if (tlvs->ipv4_addrs)
     list_delete (tlvs->ipv4_addrs);
   if (tlvs->ipv4_int_reachs)
@@ -93,7 +86,9 @@ free_tlvs (struct tlvs *tlvs)
   if (tlvs->ipv6_reachs)
     list_delete (tlvs->ipv6_reachs);
 #endif /* HAVE_IPV6 */
-  
+
+  memset (tlvs, 0, sizeof (struct tlvs));
+
   return;
 }
 
@@ -103,7 +98,7 @@ free_tlvs (struct tlvs *tlvs)
  */
 int
 parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
-           u_int32_t * found, struct tlvs *tlvs)
+           u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
 {
   u_char type, length;
   struct lan_neigh *lan_nei;
@@ -122,7 +117,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
 #endif /* HAVE_IPV6 */
   u_char virtual;
   int value_len, retval = ISIS_OK;
-  u_char *pnt = stream;
+  u_char *start = stream, *pnt = stream;
 
   *found = 0;
   memset (tlvs, 0, sizeof (struct tlvs));
@@ -443,14 +438,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
          if (*expected & TLVFLAG_AUTH_INFO)
            {
              tlvs->auth_info.type = *pnt;
-             tlvs->auth_info.len = length-1;
+              if (length == 0)
+                {
+                  zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
+                             "incorrect.", areatag, type, length);
+                  return ISIS_WARNING;
+                }
+              --length;
+             tlvs->auth_info.len = length;
              pnt++;
-             memcpy (tlvs->auth_info.passwd, pnt, length - 1);
-            /* Fill authentication with 0 for later computation
-             * of MD5 (RFC 5304, 2)
-             */
-            memset (pnt, 0, length - 1);
-             pnt += length - 1;
+             memcpy (tlvs->auth_info.passwd, pnt, length);
+              /* Return the authentication tlv pos for later computation
+               * of MD5 (RFC 5304, 2)
+               */
+              if (auth_tlv_offset)
+                *auth_tlv_offset += (pnt - start - 3);
+              pnt += length;
            }
          else
            {
@@ -734,10 +737,14 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
 int
 add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
 {
-
-  if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2)
+  if ((stream_get_size (stream) - stream_get_endp (stream)) <
+      (((unsigned)len) + 2))
     {
-      zlog_warn ("No room for TLV of type %d", tag);
+      zlog_warn ("No room for TLV of type %d "
+                 "(total size %d available %d required %d)",
+                 tag, (int)stream_get_size (stream),
+                 (int)(stream_get_size (stream) - stream_get_endp (stream)),
+                 len+2);
       return ISIS_WARNING;
     }
 
@@ -745,7 +752,7 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
   stream_putc (stream, len);   /* LENGTH */
   stream_put (stream, value, (int) len);       /* VALUE */
 
-#ifdef EXTREME_TLV_DEBUG
+#ifdef EXTREME_DEBUG
   zlog_debug ("Added TLV %d len %d", tag, len);
 #endif /* EXTREME DEBUG */
   return ISIS_OK;
@@ -877,7 +884,7 @@ tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
 }
 
 int
-tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value,
+tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
                  struct stream *stream)
 {
   u_char value[255];
@@ -1006,7 +1013,6 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
       pos += IPV4_MAX_BYTELEN;
     }
 
-
   return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
 }
 
@@ -1027,7 +1033,7 @@ tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
       if (pos - value + (5 + prefix_size) > 255)
        {
          retval =
-           add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
+           add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
          if (retval != ISIS_OK)
            return retval;
          pos = value;
@@ -1110,7 +1116,7 @@ tlv_add_padding (struct stream *stream)
   /*
    * How many times can we add full padding ?
    */
-  fullpads = (STREAM_SIZE (stream) - stream_get_endp (stream)) / 257;
+  fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
   for (i = 0; i < fullpads; i++)
     {
       if (!stream_putc (stream, (u_char) PADDING))     /* TAG */
@@ -1120,7 +1126,7 @@ tlv_add_padding (struct stream *stream)
       stream_put (stream, NULL, 255);          /* zero padding */
     }
 
-  left = STREAM_SIZE (stream) - stream_get_endp (stream);
+  left = stream_get_size (stream) - stream_get_endp (stream);
 
   if (left < 2)
     return ISIS_OK;
index fc9f35f8ab3a81d5eaa9c174ad2252d9bcba1140..e092f4d6d2d7123adfc23119d3fa30edf432b626 100644 (file)
@@ -30,7 +30,7 @@
  * Name                   Value  IIH LSP SNP Status
  *                               LAN
  * ____________________________________________________________________________
- * 
+ *
  * Area Addresses             1   y   y   n  ISO10589
  * IIS Neighbors              2   n   y   n  ISO10589
  * ES Neighbors               3   n   y   n  ISO10589
  * LSP Entries                9   n   n   y  ISO10589
  * Authentication            10   y   y   y  ISO10589, RFC3567
  * Checksum                  12   y   n   y  RFC3358
- * TE IS Reachability        22   n   y   n  RFC3784
+ * TE IS Reachability        22   n   y   n  RFC5305
  * IS Alias                  24   n   y   n  RFC3786
  * IP Int. Reachability     128   n   y   n  RFC1195
  * Protocols Supported      129   y   y   n  RFC1195
  * IP Ext. Reachability     130   n   y   n  RFC1195
  * IDRPI                    131   n   y   y  RFC1195
  * IP Interface Address     132   y   y   n  RFC1195
- * TE Router ID             134   n   y   n  RFC3784
- * Extended IP Reachability 135   n   y   n  RFC3784
+ * TE Router ID             134   n   y   n  RFC5305
+ * Extended IP Reachability 135   n   y   n  RFC5305
  * Dynamic Hostname         137   n   y   n  RFC2763
- * Shared Risk Link Group   138   n   y   y  draft-ietf-isis-gmpls-extensions
+ * Shared Risk Link Group   138   n   y   y  RFC5307
  * Restart TLV              211   y   n   n  RFC3847
- * MT IS Reachability       222   n   y   n  draft-ietf-isis-wg-multi-topology
- * MT Supported             229   y   y   n  draft-ietf-isis-wg-multi-topology
- * IPv6 Interface Address   232   y   y   n  draft-ietf-isis_ipv6
- * MT IP Reachability       235   n   y   n  draft-ietf-isis-wg-multi-topology
- * IPv6 IP Reachability     236   n   y   n  draft-ietf-isis_ipv6
- * MT IPv6 IP Reachability  237   n   y   n  draft-ietf-isis-wg-multi-topology
+ * MT IS Reachability       222   n   y   n  RFC5120
+ * MT Supported             229   y   y   n  RFC5120
+ * IPv6 Interface Address   232   y   y   n  RFC5308
+ * MT IP Reachability       235   n   y   n  RFC5120
+ * IPv6 IP Reachability     236   n   y   n  RFC5308
+ * MT IPv6 IP Reachability  237   n   y   n  RFC5120
  * P2P Adjacency State      240   y   n   n  RFC3373
  * IIH Sequence Number      241   y   n   n  draft-shen-isis-iih-sequence
  * Router Capability        242   -   -   -  draft-ietf-isis-caps
  *
- * 
+ *
  * IS Reachability sub-TLVs we (should) support.
  * ____________________________________________________________________________
  * Name                           Value   Status
  * ____________________________________________________________________________
- * Administartive group (color)       3   RFC3784
- * Link Local/Remote Identifiers      4   draft-ietf-isis-gmpls-extensions
- * IPv4 interface address             6   RFC3784
- * IPv4 neighbor address              8   RFC3784
- * Maximum link bandwidth             9   RFC3784
- * Reservable link bandwidth         10   RFC3784
- * Unreserved bandwidth              11   RFC3784
- * TE Default metric                 18   RFC3784
- * Link Protection Type              20   draft-ietf-isis-gmpls-extensions
- * Interface Switching Capability    21   draft-ietf-isis-gmpls-extensions
+ * Administartive group (color)       3   RFC5305
+ * Link Local/Remote Identifiers      4   RFC5307
+ * IPv4 interface address             6   RFC5305
+ * IPv4 neighbor address              8   RFC5305
+ * Maximum link bandwidth             9   RFC5305
+ * Reservable link bandwidth         10   RFC5305
+ * Unreserved bandwidth              11   RFC5305
+ * TE Default metric                 18   RFC5305
+ * Link Protection Type              20   RFC5307
+ * Interface Switching Capability    21   RFC5307
+ *
  *
- * 
  * IP Reachability sub-TLVs we (should) support.
  * ____________________________________________________________________________
  * Name                           Value   Status
  * ____________________________________________________________________________
- * 32bit administrative tag           1   draft-ietf-isis-admin-tags
- * 64bit administrative tag           2   draft-ietf-isis-admin-tags
- * Management prefix color          117   draft-ietf-isis-wg-multi-topology
+ * 32bit administrative tag           1   RFC5130
+ * 64bit administrative tag           2   RFC5130
+ * Management prefix color          117   RFC5120
  */
 
 #define AREA_ADDRESSES            1
 #define IPV6_REACHABILITY         236
 #define WAY3_HELLO                240
 
+#define AUTH_INFO_HDRLEN          3
+
 #define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5)
 #define LAN_NEIGHBOURS_LEN 6
 #define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */
 #define IPV4_REACH_LEN 12
 #define IPV6_REACH_LEN 22
+#define TE_IPV4_REACH_LEN 9
 
 /* struct for neighbor */
 struct is_neigh
@@ -131,6 +134,15 @@ struct te_is_neigh
   u_char sub_tlvs_length;
 };
 
+/* Decode and encode three-octet metric into host byte order integer */
+#define GET_TE_METRIC(t) \
+  (((unsigned)(t)->te_metric[0]<<16) | ((t)->te_metric[1]<<8) | \
+   (t)->te_metric[2])
+#define SET_TE_METRIC(t, m) \
+  (((t)->te_metric[0] = (m) >> 16), \
+   ((t)->te_metric[1] = (m) >> 8), \
+   ((t)->te_metric[2] = (m)))
+
 /* struct for es neighbors */
 struct es_neigh
 {
@@ -213,7 +225,6 @@ struct ipv6_reachability
   u_char prefix_len;
   u_char prefix[16];
 };
-#endif /* HAVE_IPV6 */
 
 /* bits in control_info */
 #define CTRL_INFO_DIRECTION    0x80
@@ -223,12 +234,17 @@ struct ipv6_reachability
 #define DISTRIBUTION_INTERNAL  0
 #define DISTRIBUTION_EXTERNAL  1
 #define CTRL_INFO_SUBTLVS      0x20
+#endif /* HAVE_IPV6 */
 
 /*
  * Pointer to each tlv type, filled by parse_tlvs()
  */
 struct tlvs
 {
+  struct checksum *checksum;
+  struct hostname *hostname;
+  struct nlpids *nlpids;
+  struct te_router_id *router_id;
   struct list *area_addrs;
   struct list *is_neighs;
   struct list *te_is_neighs;
@@ -236,14 +252,10 @@ struct tlvs
   struct list *lsp_entries;
   struct list *prefix_neighs;
   struct list *lan_neighs;
-  struct checksum *checksum;
-  struct nlpids *nlpids;
   struct list *ipv4_addrs;
   struct list *ipv4_int_reachs;
   struct list *ipv4_ext_reachs;
   struct list *te_ipv4_reachs;
-  struct hostname *hostname;
-  struct te_router_id *router_id;
 #ifdef HAVE_IPV6
   struct list *ipv6_addrs;
   struct list *ipv6_reachs;
@@ -281,7 +293,9 @@ struct tlvs
 void init_tlvs (struct tlvs *tlvs, uint32_t expected);
 void free_tlvs (struct tlvs *tlvs);
 int parse_tlvs (char *areatag, u_char * stream, int size,
-               u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs);
+               u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs,
+                u_int32_t * auth_tlv_offset);
+int add_tlv (u_char, u_char, u_char *, struct stream *);
 void free_tlv (void *val);
 
 int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
@@ -290,7 +304,7 @@ int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);
 int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream);
 int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
 int tlv_add_checksum (struct checksum *checksum, struct stream *stream);
-int tlv_add_authinfo (char auth_type, char authlen, u_char *auth_value,
+int tlv_add_authinfo (u_char auth_type, u_char authlen, u_char *auth_value,
                      struct stream *stream);
 int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream);
 int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag);
index d5ccef9ea0947eacb9e90203ec8b2ac887099fb9..467122f6586df226badf3ca1216a2fbddf468ab7 100644 (file)
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_csm.h"
+#include "isisd/isis_lsp.h"
 #include "isisd/isis_route.h"
 #include "isisd/isis_zebra.h"
 
 struct zclient *zclient = NULL;
 
-extern struct thread_master *master;
-extern struct isis *isis;
-
-struct in_addr router_id_zebra;
-
 /* Router-id update message from zebra. */
 static int
 isis_router_id_update_zebra (int command, struct zclient *zclient,
                             zebra_size_t length)
 {
+  struct isis_area *area;
+  struct listnode *node;
   struct prefix router_id;
 
-  zebra_router_id_update_read (zclient->ibuf,&router_id);
-  router_id_zebra = router_id.u.prefix4;
+  zebra_router_id_update_read (zclient->ibuf, &router_id);
+  if (isis->router_id == router_id.u.prefix4.s_addr)
+    return 0;
+
+  isis->router_id = router_id.u.prefix4.s_addr;
+  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+    if (listcount (area->area_addrs) > 0)
+      lsp_regenerate_schedule (area, area->is_type, 0);
 
-  /* FIXME: Do we react somehow? */
   return 0;
 }
 
@@ -100,53 +107,28 @@ isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
     zlog_debug ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d",
                ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu);
 
+  isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
 
   /* Cannot call if_delete because we should retain the pseudo interface
      in case there is configuration info attached to it. */
   if_delete_retain(ifp);
 
-  isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
-
   ifp->ifindex = IFINDEX_INTERNAL;
 
   return 0;
 }
 
-static struct interface *
-zebra_interface_if_lookup (struct stream *s)
-{
-  char ifname_tmp[INTERFACE_NAMSIZ];
-
-  /* Read interface name. */
-  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
-
-  /* And look it up. */
-  return if_lookup_by_name_len(ifname_tmp,
-                              strnlen(ifname_tmp, INTERFACE_NAMSIZ));
-}
-
 static int
 isis_zebra_if_state_up (int command, struct zclient *zclient,
                        zebra_size_t length)
 {
   struct interface *ifp;
 
-  ifp = zebra_interface_if_lookup (zclient->ibuf);
+  ifp = zebra_interface_state_read (zclient->ibuf);
 
-  if (!ifp)
+  if (ifp == NULL)
     return 0;
 
-  if (if_is_operative (ifp))
-    {
-      zebra_interface_if_set_value (zclient->ibuf, ifp);
-      /* HT: This is wrong actually. We can't assume that circuit exist
-       * if we delete circuit during if_state_down event. Needs rethink.
-       * TODO */
-      isis_circuit_update_params (circuit_scan_by_ifp (ifp), ifp);
-      return 0;
-    }
-
-  zebra_interface_if_set_value (zclient->ibuf, ifp);
   isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
 
   return 0;
@@ -157,17 +139,17 @@ isis_zebra_if_state_down (int command, struct zclient *zclient,
                          zebra_size_t length)
 {
   struct interface *ifp;
+  struct isis_circuit *circuit;
 
-  ifp = zebra_interface_if_lookup (zclient->ibuf);
+  ifp = zebra_interface_state_read (zclient->ibuf);
 
   if (ifp == NULL)
     return 0;
 
-  if (if_is_operative (ifp))
-    {
-      zebra_interface_if_set_value (zclient->ibuf, ifp);
-      isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
-    }
+  circuit = isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp),
+                                   ifp);
+  if (circuit)
+    SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
 
   return 0;
 }
@@ -251,7 +233,7 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix,
   struct isis_nexthop *nexthop;
   struct listnode *node;
 
-  if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+  if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
     return;
 
   if (zclient->redist[ZEBRA_ROUTE_ISIS])
@@ -274,8 +256,6 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix,
       stream_putc (stream, flags);
       /* message */
       stream_putc (stream, message);
-      /* SAFI */
-      stream_putw (stream, SAFI_UNICAST);
       /* prefix information */
       psize = PSIZE (prefix->prefixlen);
       stream_putc (stream, prefix->prefixlen);
@@ -307,7 +287,8 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix,
 
       stream_putw_at (stream, 0, stream_get_endp (stream));
       zclient_send_message(zclient);
-      SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+      SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+      UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
     }
 }
 
@@ -323,13 +304,12 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix,
       api.type = ZEBRA_ROUTE_ISIS;
       api.flags = 0;
       api.message = 0;
-      api.safi = SAFI_UNICAST;
       prefix4.family = AF_INET;
       prefix4.prefixlen = prefix->prefixlen;
       prefix4.prefix = prefix->u.prefix4;
       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, &api);
     }
-  UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+  UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
 
   return;
 }
@@ -347,13 +327,12 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix,
   struct listnode *node;
   struct prefix_ipv6 prefix6;
 
-  if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+  if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
     return;
 
   api.type = ZEBRA_ROUTE_ISIS;
   api.flags = 0;
   api.message = 0;
-  api.safi = SAFI_UNICAST;
   SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
   SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
   SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
@@ -410,7 +389,8 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix,
       prefix6.prefixlen = prefix->prefixlen;
       memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr));
       zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, &api);
-      SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+      SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+      UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
     }
 
   XFREE (MTYPE_ISIS_TMP, nexthop_list);
@@ -431,13 +411,12 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix,
   struct listnode *node;
   struct prefix_ipv6 prefix6;
 
-  if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+  if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
     return;
 
   api.type = ZEBRA_ROUTE_ISIS;
   api.flags = 0;
   api.message = 0;
-  api.safi = SAFI_UNICAST;
   SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
   SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
   api.nexthop_num = listcount (route_info->nexthops6);
@@ -488,7 +467,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix,
       prefix6.prefixlen = prefix->prefixlen;
       memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr));
       zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, &api);
-      UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+      UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
     }
 
   XFREE (MTYPE_ISIS_TMP, nexthop_list);
index 20a328092100c5a925c75f3c7655c7a6fbb00c78..e8e3d9f0ad9f043c8821e8f80b99848b531da480 100644 (file)
@@ -27,6 +27,7 @@
 #include "command.h"
 #include "log.h"
 #include "memory.h"
+#include "time.h"
 #include "linklist.h"
 #include "if.h"
 #include "hash.h"
@@ -38,8 +39,9 @@
 #include "isisd/include-netbsd/iso.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
-#include "isisd/isis_circuit.h"
 #include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_csm.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_adjacency.h"
@@ -52,7 +54,6 @@
 #include "isisd/isis_route.h"
 #include "isisd/isis_zebra.h"
 #include "isisd/isis_events.h"
-#include "isisd/isis_csm.h"
 
 #ifdef TOPOLOGY_GENERATE
 #include "spgrid.h"
@@ -60,19 +61,17 @@ u_char DEFAULT_TOPOLOGY_BASEIS[6] = { 0xFE, 0xED, 0xFE, 0xED, 0x00, 0x00 };
 #endif /* TOPOLOGY_GENERATE */
 
 struct isis *isis = NULL;
-extern struct thread_master *master;
 
 /*
  * Prototypes.
  */
-void isis_new(unsigned long);
-struct isis_area *isis_area_create(void);
 int isis_area_get(struct vty *, const char *);
 int isis_area_destroy(struct vty *, const char *);
-int area_net_title(struct vty *, const u_char *);
-int area_clear_net_title(struct vty *, const u_char *);
-int show_clns_neigh(struct vty *, char);
-void print_debug(struct vty *, int, int);
+int area_net_title(struct vty *, const char *);
+int area_clear_net_title(struct vty *, const char *);
+int show_isis_interface_common(struct vty *, const char *ifname, char);
+int show_isis_neighbor_common(struct vty *, const char *id, char);
+int clear_isis_neighbor_common(struct vty *, const char *id);
 int isis_config_write(struct vty *);
 
 
@@ -85,8 +84,8 @@ isis_new (unsigned long process_id)
    * Default values
    */
   isis->max_area_addrs = 3;
-
   isis->process_id = process_id;
+  isis->router_id = 0;
   isis->area_list = list_new ();
   isis->init_circ_list = list_new ();
   isis->uptime = time (NULL);
@@ -94,6 +93,7 @@ isis_new (unsigned long process_id)
 #ifdef HAVE_IPV6
   isis->nexthops6 = list_new ();
 #endif /* HAVE_IPV6 */
+  dyn_cache_init ();
   /*
    * uncomment the next line for full debugs
    */
@@ -101,7 +101,7 @@ isis_new (unsigned long process_id)
 }
 
 struct isis_area *
-isis_area_create ()
+isis_area_create (const char *area_tag)
 {
   struct isis_area *area;
 
@@ -115,36 +115,48 @@ isis_area_create ()
     area->is_type = IS_LEVEL_1;
   else
     area->is_type = IS_LEVEL_1_AND_2;
+
   /*
    * intialize the databases
    */
-  area->lspdb[0] = lsp_db_init ();
-  area->lspdb[1] = lsp_db_init ();
-
-  spftree_area_init (area);
-  area->route_table[0] = route_table_init ();
-  area->route_table[1] = route_table_init ();
+  if (area->is_type & IS_LEVEL_1)
+    {
+      area->lspdb[0] = lsp_db_init ();
+      area->route_table[0] = route_table_init ();
+#ifdef HAVE_IPV6
+      area->route_table6[0] = route_table_init ();
+#endif /* HAVE_IPV6 */
+    }
+  if (area->is_type & IS_LEVEL_2)
+    {
+      area->lspdb[1] = lsp_db_init ();
+      area->route_table[1] = route_table_init ();
 #ifdef HAVE_IPV6
-  area->route_table6[0] = route_table_init ();
-  area->route_table6[1] = route_table_init ();
+      area->route_table6[1] = route_table_init ();
 #endif /* HAVE_IPV6 */
+    }
+
+  spftree_area_init (area);
+
   area->circuit_list = list_new ();
   area->area_addrs = list_new ();
   THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
   flags_initialize (&area->flags);
+
   /*
    * Default values
    */
-  area->max_lsp_lifetime[0] = MAX_AGE; /* 1200 */
-  area->max_lsp_lifetime[1] = MAX_AGE; /* 1200 */
-  area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
-  area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
-  area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900 */
-  area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900 */
+  area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME;    /* 1200 */
+  area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME;    /* 1200 */
+  area->lsp_refresh[0] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */
+  area->lsp_refresh[1] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */
+  area->lsp_gen_interval[0] = DEFAULT_MIN_LSP_GEN_INTERVAL;
+  area->lsp_gen_interval[1] = DEFAULT_MIN_LSP_GEN_INTERVAL;
   area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
   area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
   area->dynhostname = 1;
-  area->oldmetric = 1;
+  area->oldmetric = 0;
+  area->newmetric = 1;
   area->lsp_frag_threshold = 90;
 #ifdef TOPOLOGY_GENERATE
   memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
@@ -153,6 +165,10 @@ isis_area_create ()
   /* FIXME: Think of a better way... */
   area->min_bcast_mtu = 1497;
 
+  area->area_tag = strdup (area_tag);
+  listnode_add (isis->area_list, area);
+  area->isis = isis;
+
   return area;
 }
 
@@ -185,9 +201,7 @@ isis_area_get (struct vty *vty, const char *area_tag)
       return CMD_SUCCESS;
     }
 
-  area = isis_area_create ();
-  area->area_tag = strdup (area_tag);
-  listnode_add (isis->area_list, area);
+  area = isis_area_create (area_tag);
 
   if (isis->debugs & DEBUG_EVENTS)
     zlog_debug ("New IS-IS area instance %s", area->area_tag);
@@ -204,50 +218,100 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
   struct isis_area *area;
   struct listnode *node, *nnode;
   struct isis_circuit *circuit;
+  struct area_addr *addr;
 
   area = isis_area_lookup (area_tag);
 
   if (area == NULL)
     {
       vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_NO_MATCH;
     }
 
   if (area->circuit_list)
     {
       for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit))
-       {
-         /* The fact that it's in circuit_list means that it was configured */
-         isis_csm_state_change (ISIS_DISABLE, circuit, area);
-         isis_circuit_down (circuit);
-         isis_circuit_deconfigure (circuit, area);
-       }
-      
+        {
+          circuit->ip_router = 0;
+#ifdef HAVE_IPV6
+          circuit->ipv6_router = 0;
+#endif
+          isis_csm_state_change (ISIS_DISABLE, circuit, area);
+        }
       list_delete (area->circuit_list);
+      area->circuit_list = NULL;
     }
-  listnode_delete (isis->area_list, area);
+
+  if (area->lspdb[0] != NULL)
+    {
+      lsp_db_destroy (area->lspdb[0]);
+      area->lspdb[0] = NULL;
+    }
+  if (area->lspdb[1] != NULL)
+    {
+      lsp_db_destroy (area->lspdb[1]);
+      area->lspdb[1] = NULL;
+    }
+
+  spftree_area_del (area);
+
+  /* invalidate and validate would delete all routes from zebra */
+  isis_route_invalidate (area);
+  isis_route_validate (area);
+
+  if (area->route_table[0])
+    {
+      route_table_finish (area->route_table[0]);
+      area->route_table[0] = NULL;
+    }
+  if (area->route_table[1])
+    {
+      route_table_finish (area->route_table[1]);
+      area->route_table[1] = NULL;
+    }
+#ifdef HAVE_IPV6
+  if (area->route_table6[0])
+    {
+      route_table_finish (area->route_table6[0]);
+      area->route_table6[0] = NULL;
+    }
+  if (area->route_table6[1])
+    {
+      route_table_finish (area->route_table6[1]);
+      area->route_table6[1] = NULL;
+    }
+#endif /* HAVE_IPV6 */
+
+  for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr))
+    {
+      list_delete_node (area->area_addrs, node);
+      XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+    }
+  area->area_addrs = NULL;
 
   THREAD_TIMER_OFF (area->t_tick);
-  if (area->t_remove_aged)
-    thread_cancel (area->t_remove_aged);
   THREAD_TIMER_OFF (area->t_lsp_refresh[0]);
   THREAD_TIMER_OFF (area->t_lsp_refresh[1]);
 
-  THREAD_TIMER_OFF (area->spftree[0]->t_spf);
-  THREAD_TIMER_OFF (area->spftree[1]->t_spf);
+  thread_cancel_event (master, area);
+
+  listnode_delete (isis->area_list, area);
 
-  THREAD_TIMER_OFF (area->t_lsp_l1_regenerate);
-  THREAD_TIMER_OFF (area->t_lsp_l2_regenerate);
+  free (area->area_tag);
 
   XFREE (MTYPE_ISIS_AREA, area);
 
-  isis->sysid_set=0;
+  if (listcount (isis->area_list) == 0)
+    {
+      memset (isis->sysid, 0, ISIS_SYS_ID_LEN);
+      isis->sysid_set = 0;
+    }
 
   return CMD_SUCCESS;
 }
 
 int
-area_net_title (struct vty *vty, const u_char *net_title)
+area_net_title (struct vty *vty, const char *net_title)
 {
   struct isis_area *area;
   struct area_addr *addr;
@@ -260,7 +324,7 @@ area_net_title (struct vty *vty, const u_char *net_title)
   if (!area)
     {
       vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_NO_MATCH;
     }
 
   /* We check that we are not over the maximal number of addresses */
@@ -268,7 +332,7 @@ area_net_title (struct vty *vty, const u_char *net_title)
     {
       vty_out (vty, "Maximum of area addresses (%d) already reached %s",
               isis->max_area_addrs, VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_NOTHING_TODO;
     }
 
   addr = XMALLOC (MTYPE_ISIS_AREA_ADDR, sizeof (struct area_addr));
@@ -280,10 +344,18 @@ area_net_title (struct vty *vty, const u_char *net_title)
 #endif /* EXTREME_DEBUG */
   if (addr->addr_len < 8 || addr->addr_len > 20)
     {
-      zlog_warn ("area address must be at least 8..20 octets long (%d)",
-                addr->addr_len);
+      vty_out (vty, "area address must be at least 8..20 octets long (%d)%s",
+               addr->addr_len, VTY_NEWLINE);
+      XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (addr->area_addr[addr->addr_len-1] != 0)
+    {
+      vty_out (vty, "nsel byte (last byte) in area address must be 0%s",
+               VTY_NEWLINE);
       XFREE (MTYPE_ISIS_AREA_ADDR, addr);
-      return CMD_WARNING;
+      return CMD_ERR_AMBIGUOUS;
     }
 
   if (isis->sysid_set == 0)
@@ -291,7 +363,7 @@ area_net_title (struct vty *vty, const u_char *net_title)
       /*
        * First area address - get the SystemID for this router
        */
-      memcpy (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN), ISIS_SYS_ID_LEN);
+      memcpy (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN);
       isis->sysid_set = 1;
       if (isis->debugs & DEBUG_EVENTS)
        zlog_debug ("Router has SystemID %s", sysid_print (isis->sysid));
@@ -301,20 +373,19 @@ area_net_title (struct vty *vty, const u_char *net_title)
       /*
        * Check that the SystemID portions match
        */
-      if (memcmp (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN),
-                 ISIS_SYS_ID_LEN))
+      if (memcmp (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN))
        {
          vty_out (vty,
                   "System ID must not change when defining additional area"
                   " addresses%s", VTY_NEWLINE);
          XFREE (MTYPE_ISIS_AREA_ADDR, addr);
-         return CMD_WARNING;
+         return CMD_ERR_AMBIGUOUS;
        }
 
       /* now we see that we don't already have this address */
       for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp))
        {
-         if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) != (addr->addr_len))
+         if ((addrp->addr_len + ISIS_SYS_ID_LEN + ISIS_NSEL_LEN) != (addr->addr_len))
            continue;
          if (!memcmp (addrp->area_addr, addr->area_addr, addr->addr_len))
            {
@@ -322,26 +393,28 @@ area_net_title (struct vty *vty, const u_char *net_title)
              return CMD_SUCCESS;       /* silent fail */
            }
        }
-
     }
+
   /*
    * Forget the systemID part of the address
    */
-  addr->addr_len -= (ISIS_SYS_ID_LEN + 1);
+  addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN);
   listnode_add (area->area_addrs, addr);
 
   /* only now we can safely generate our LSPs for this area */
   if (listcount (area->area_addrs) > 0)
     {
-      lsp_l1_generate (area);
-      lsp_l2_generate (area);
+      if (area->is_type & IS_LEVEL_1)
+        lsp_generate (area, IS_LEVEL_1);
+      if (area->is_type & IS_LEVEL_2)
+        lsp_generate (area, IS_LEVEL_2);
     }
 
   return CMD_SUCCESS;
 }
 
 int
-area_clear_net_title (struct vty *vty, const u_char *net_title)
+area_clear_net_title (struct vty *vty, const char *net_title)
 {
   struct isis_area *area;
   struct area_addr addr, *addrp = NULL;
@@ -352,7 +425,7 @@ area_clear_net_title (struct vty *vty, const u_char *net_title)
   if (!area)
     {
       vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_NO_MATCH;
     }
 
   addr.addr_len = dotformat2buff (buff, net_title);
@@ -360,13 +433,13 @@ area_clear_net_title (struct vty *vty, const u_char *net_title)
     {
       vty_out (vty, "Unsupported area address length %d, should be 8...20 %s",
               addr.addr_len, VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_AMBIGUOUS;
     }
 
   memcpy (addr.area_addr, buff, (int) addr.addr_len);
 
   for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp))
-    if (addrp->addr_len == addr.addr_len &&
+    if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len &&
        !memcmp (addrp->area_addr, addr.area_addr, addr.addr_len))
     break;
 
@@ -374,26 +447,36 @@ area_clear_net_title (struct vty *vty, const u_char *net_title)
     {
       vty_out (vty, "No area address %s for area %s %s", net_title,
               area->area_tag, VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_NO_MATCH;
     }
 
   listnode_delete (area->area_addrs, addrp);
+  XFREE (MTYPE_ISIS_AREA_ADDR, addrp);
+
+  /*
+   * Last area address - reset the SystemID for this router
+   */
+  if (listcount (area->area_addrs) == 0)
+    {
+      memset (isis->sysid, 0, ISIS_SYS_ID_LEN);
+      isis->sysid_set = 0;
+      if (isis->debugs & DEBUG_EVENTS)
+        zlog_debug ("Router has no SystemID");
+    }
 
   return CMD_SUCCESS;
 }
 
 /*
- * 'show clns neighbors' command
+ * 'show isis interface' command
  */
 
 int
-show_clns_neigh (struct vty *vty, char detail)
+show_isis_interface_common (struct vty *vty, const char *ifname, char detail)
 {
   struct listnode *anode, *cnode;
   struct isis_area *area;
   struct isis_circuit *circuit;
-  struct list *db;
-  int i;
 
   if (!isis)
     {
@@ -406,92 +489,246 @@ show_clns_neigh (struct vty *vty, char detail)
       vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE);
 
       if (detail == ISIS_UI_LEVEL_BRIEF)
-       vty_out (vty, "  System Id           Interface   L  State        "
-                "Holdtime SNPA%s", VTY_NEWLINE);
+        vty_out (vty, "  Interface   CircId   State    Type     Level%s",
+                 VTY_NEWLINE);
 
       for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
-       {
-         if (circuit->circ_type == CIRCUIT_T_BROADCAST)
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 db = circuit->u.bc.adjdb[i];
-                 if (db && db->count)
-                   {
-                     if (detail == ISIS_UI_LEVEL_BRIEF)
-                       isis_adjdb_iterate (db,
-                                           (void (*)
-                                            (struct isis_adjacency *,
-                                             void *)) isis_adj_print_vty,
-                                           vty);
-                     if (detail == ISIS_UI_LEVEL_DETAIL)
-                       isis_adjdb_iterate (db,
-                                           (void (*)
-                                            (struct isis_adjacency *,
-                                             void *))
-                                           isis_adj_print_vty_detail, vty);
-                     if (detail == ISIS_UI_LEVEL_EXTENSIVE)
-                       isis_adjdb_iterate (db,
-                                           (void (*)
-                                            (struct isis_adjacency *,
-                                             void *))
-                                           isis_adj_print_vty_extensive,
-                                           vty);
-                   }
-               }
-           }
-         else if (circuit->circ_type == CIRCUIT_T_P2P &&
-                  circuit->u.p2p.neighbor)
-           {
-             if (detail == ISIS_UI_LEVEL_BRIEF)
-               isis_adj_p2p_print_vty (circuit->u.p2p.neighbor, vty);
-             if (detail == ISIS_UI_LEVEL_DETAIL)
-               isis_adj_p2p_print_vty_detail (circuit->u.p2p.neighbor, vty);
-             if (detail == ISIS_UI_LEVEL_EXTENSIVE)
-               isis_adj_p2p_print_vty_extensive (circuit->u.p2p.neighbor,
-                                                 vty);
-           }
-       }
+        if (!ifname)
+          isis_circuit_print_vty (circuit, vty, detail);
+        else if (strcmp(circuit->interface->name, ifname) == 0)
+          isis_circuit_print_vty (circuit, vty, detail);
     }
 
   return CMD_SUCCESS;
 }
 
-DEFUN (show_clns_neighbors,
-       show_clns_neighbors_cmd,
-       "show clns neighbors",
+DEFUN (show_isis_interface,
+       show_isis_interface_cmd,
+       "show isis interface",
        SHOW_STR
-       "clns network information\n"
-       "CLNS neighbor adjacencies\n")
+       "ISIS network information\n"
+       "ISIS interface\n")
 {
-  return show_clns_neigh (vty, ISIS_UI_LEVEL_BRIEF);
+  return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_BRIEF);
 }
 
-ALIAS (show_clns_neighbors,
-       show_isis_neighbors_cmd,
-       "show isis neighbors",
+DEFUN (show_isis_interface_detail,
+       show_isis_interface_detail_cmd,
+       "show isis interface detail",
        SHOW_STR
-       "IS-IS network information\n"
-       "IS-IS neighbor adjacencies\n")
+       "ISIS network information\n"
+       "ISIS interface\n"
+       "show detailed information\n")
+{
+  return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_DETAIL);
+}
 
-DEFUN (show_clns_neighbors_detail,
-       show_clns_neighbors_detail_cmd,
-       "show clns neighbors detail",
+DEFUN (show_isis_interface_arg,
+       show_isis_interface_arg_cmd,
+       "show isis interface WORD",
        SHOW_STR
-       "clns network information\n"
-       "CLNS neighbor adjacencies\n"
-       "show detailed information\n")
+       "ISIS network information\n"
+       "ISIS interface\n"
+       "ISIS interface name\n")
+{
+  return show_isis_interface_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
+/*
+ * 'show isis neighbor' command
+ */
+
+int
+show_isis_neighbor_common (struct vty *vty, const char *id, char detail)
+{
+  struct listnode *anode, *cnode, *node;
+  struct isis_area *area;
+  struct isis_circuit *circuit;
+  struct list *adjdb;
+  struct isis_adjacency *adj;
+  struct isis_dynhn *dynhn;
+  u_char sysid[ISIS_SYS_ID_LEN];
+  int i;
+
+  if (!isis)
+    {
+      vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  memset (sysid, 0, ISIS_SYS_ID_LEN);
+  if (id)
+    {
+      if (sysid2buff (sysid, id) == 0)
+        {
+          dynhn = dynhn_find_by_name (id);
+          if (dynhn == NULL)
+            {
+              vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE);
+              return CMD_SUCCESS;
+            }
+          memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN);
+        }
+    }
+
+  for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area))
+    {
+      vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE);
+
+      if (detail == ISIS_UI_LEVEL_BRIEF)
+        vty_out (vty, "  System Id           Interface   L  State"
+                      "        Holdtime SNPA%s", VTY_NEWLINE);
+
+      for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+        {
+          if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  adjdb = circuit->u.bc.adjdb[i];
+                  if (adjdb && adjdb->count)
+                    {
+                      for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
+                        if (!id || !memcmp (adj->sysid, sysid,
+                                            ISIS_SYS_ID_LEN))
+                          isis_adj_print_vty (adj, vty, detail);
+                    }
+                }
+            }
+          else if (circuit->circ_type == CIRCUIT_T_P2P &&
+                   circuit->u.p2p.neighbor)
+            {
+              adj = circuit->u.p2p.neighbor;
+              if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN))
+                isis_adj_print_vty (adj, vty, detail);
+            }
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+/*
+ * 'clear isis neighbor' command
+ */
+int
+clear_isis_neighbor_common (struct vty *vty, const char *id)
+{
+  struct listnode *anode, *cnode, *cnextnode, *node, *nnode;
+  struct isis_area *area;
+  struct isis_circuit *circuit;
+  struct list *adjdb;
+  struct isis_adjacency *adj;
+  struct isis_dynhn *dynhn;
+  u_char sysid[ISIS_SYS_ID_LEN];
+  int i;
+
+  if (!isis)
+    {
+      vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  memset (sysid, 0, ISIS_SYS_ID_LEN);
+  if (id)
+    {
+      if (sysid2buff (sysid, id) == 0)
+        {
+          dynhn = dynhn_find_by_name (id);
+          if (dynhn == NULL)
+            {
+              vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE);
+              return CMD_SUCCESS;
+            }
+          memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN);
+        }
+    }
+
+  for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area))
+    {
+      for (ALL_LIST_ELEMENTS (area->circuit_list, cnode, cnextnode, circuit))
+        {
+          if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+            {
+              for (i = 0; i < 2; i++)
+                {
+                  adjdb = circuit->u.bc.adjdb[i];
+                  if (adjdb && adjdb->count)
+                    {
+                      for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
+                        if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN))
+                          isis_adj_state_change (adj, ISIS_ADJ_DOWN,
+                                                 "clear user request");
+                    }
+                }
+            }
+          else if (circuit->circ_type == CIRCUIT_T_P2P &&
+                   circuit->u.p2p.neighbor)
+            {
+              adj = circuit->u.p2p.neighbor;
+              if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN))
+                isis_adj_state_change (adj, ISIS_ADJ_DOWN,
+                                       "clear user request");
+            }
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_isis_neighbor,
+       show_isis_neighbor_cmd,
+       "show isis neighbor",
+       SHOW_STR
+       "ISIS network information\n"
+       "ISIS neighbor adjacencies\n")
 {
-  return show_clns_neigh (vty, ISIS_UI_LEVEL_DETAIL);
+  return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF);
 }
 
-ALIAS (show_clns_neighbors_detail,
-       show_isis_neighbors_detail_cmd,
-       "show isis neighbors detail",
+DEFUN (show_isis_neighbor_detail,
+       show_isis_neighbor_detail_cmd,
+       "show isis neighbor detail",
        SHOW_STR
-       "IS-IS network information\n"
-       "IS-IS neighbor adjacencies\n"
+       "ISIS network information\n"
+       "ISIS neighbor adjacencies\n"
        "show detailed information\n")
+{
+  return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_DETAIL);
+}
+
+DEFUN (show_isis_neighbor_arg,
+       show_isis_neighbor_arg_cmd,
+       "show isis neighbor WORD",
+       SHOW_STR
+       "ISIS network information\n"
+       "ISIS neighbor adjacencies\n"
+       "System id\n")
+{
+  return show_isis_neighbor_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
+DEFUN (clear_isis_neighbor,
+       clear_isis_neighbor_cmd,
+       "clear isis neighbor",
+       CLEAR_STR
+       "Reset ISIS network information\n"
+       "Reset ISIS neighbor adjacencies\n")
+{
+  return clear_isis_neighbor_common (vty, NULL);
+}
+
+DEFUN (clear_isis_neighbor_arg,
+       clear_isis_neighbor_arg_cmd,
+       "clear isis neighbor WORD",
+       CLEAR_STR
+       "ISIS network information\n"
+       "ISIS neighbor adjacencies\n"
+       "System id\n")
+{
+  return clear_isis_neighbor_common (vty, argv[0]);
+}
+
 /*
  * 'isis debug', 'show debugging'
  */
@@ -535,7 +772,8 @@ print_debug (struct vty *vty, int flags, int onoff)
             VTY_NEWLINE);
   if (flags & DEBUG_EVENTS)
     vty_out (vty, "IS-IS Event debugging is %s%s", onoffs, VTY_NEWLINE);
-
+  if (flags & DEBUG_PACKET_DUMP)
+    vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE);
 }
 
 DEFUN (show_debugging,
@@ -617,6 +855,11 @@ config_write_debug (struct vty *vty)
       vty_out (vty, "debug isis events%s", VTY_NEWLINE);
       write++;
     }
+  if (flags & DEBUG_PACKET_DUMP)
+    {
+      vty_out (vty, "debug isis packet-dump%s", VTY_NEWLINE);
+      write++;
+    }
 
   return write;
 }
@@ -803,7 +1046,6 @@ DEFUN (no_debug_isis_spfevents,
   return CMD_SUCCESS;
 }
 
-
 DEFUN (debug_isis_spfstats,
        debug_isis_spfstats_cmd,
        "debug isis spf-statistics ",
@@ -908,6 +1150,32 @@ DEFUN (no_debug_isis_events,
   return CMD_SUCCESS;
 }
 
+DEFUN (debug_isis_packet_dump,
+       debug_isis_packet_dump_cmd,
+       "debug isis packet-dump",
+       DEBUG_STR
+       "IS-IS information\n"
+       "IS-IS packet dump\n")
+{
+  isis->debugs |= DEBUG_PACKET_DUMP;
+  print_debug (vty, DEBUG_PACKET_DUMP, 1);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_packet_dump,
+       no_debug_isis_packet_dump_cmd,
+       "no debug isis packet-dump",
+       UNDEBUG_STR
+       "IS-IS information\n"
+       "IS-IS packet dump\n")
+{
+  isis->debugs &= ~DEBUG_PACKET_DUMP;
+  print_debug (vty, DEBUG_PACKET_DUMP, 0);
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_hostname,
        show_hostname_cmd,
        "show isis hostname",
@@ -920,100 +1188,334 @@ DEFUN (show_hostname,
   return CMD_SUCCESS;
 }
 
-DEFUN (show_database,
-       show_database_cmd,
-       "show isis database",
-       SHOW_STR "IS-IS information\n" "IS-IS link state database\n")
+static void
+vty_out_timestr(struct vty *vty, time_t uptime)
 {
-  struct listnode *node;
+  struct tm *tm;
+  time_t difftime = time (NULL);
+  difftime -= uptime;
+  tm = gmtime (&difftime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+  if (difftime < ONE_DAY_SECOND)
+    vty_out (vty,  "%02d:%02d:%02d", 
+        tm->tm_hour, tm->tm_min, tm->tm_sec);
+  else if (difftime < ONE_WEEK_SECOND)
+    vty_out (vty, "%dd%02dh%02dm", 
+        tm->tm_yday, tm->tm_hour, tm->tm_min);
+  else
+    vty_out (vty, "%02dw%dd%02dh", 
+        tm->tm_yday/7,
+        tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+  vty_out (vty, " ago");
+}
+
+DEFUN (show_isis_summary,
+       show_isis_summary_cmd,
+       "show isis summary",
+       SHOW_STR "IS-IS information\n" "IS-IS summary\n")
+{
+  struct listnode *node, *node2;
   struct isis_area *area;
-  int level, lsp_count;
+  struct isis_spftree *spftree;
+  int level;
 
-  if (isis->area_list->count == 0)
+  if (isis == NULL)
+  {
+    vty_out (vty, "ISIS is not running%s", VTY_NEWLINE);
     return CMD_SUCCESS;
+  }
+
+  vty_out (vty, "Process Id      : %ld%s", isis->process_id,
+      VTY_NEWLINE);
+  if (isis->sysid_set)
+    vty_out (vty, "System Id       : %s%s", sysid_print (isis->sysid),
+        VTY_NEWLINE);
+
+  vty_out (vty, "Up time         : ");
+  vty_out_timestr(vty, isis->uptime);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  if (isis->area_list)
+    vty_out (vty, "Number of areas : %d%s", isis->area_list->count,
+        VTY_NEWLINE);
 
   for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+  {
+    vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+        VTY_NEWLINE);
+
+    if (listcount (area->area_addrs) > 0)
     {
-      vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
-              VTY_NEWLINE);
-      for (level = 0; level < ISIS_LEVELS; level++)
-       {
-         if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
-           {
-             vty_out (vty, "IS-IS Level-%d link-state database:%s",
-                      level + 1, VTY_NEWLINE);
+      struct area_addr *area_addr;
+      for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr))
+      {
+        vty_out (vty, "  Net: %s%s",
+            isonet_print (area_addr->area_addr,
+              area_addr->addr_len + ISIS_SYS_ID_LEN +
+              1), VTY_NEWLINE);
+      }
+    }
 
-             lsp_count = lsp_print_all (vty, area->lspdb[level],
-                                        ISIS_UI_LEVEL_BRIEF,
-                                        area->dynhostname);
+    for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+    {
+      if ((area->is_type & level) == 0)
+        continue;
 
-             vty_out (vty, "%s    %u LSPs%s%s",
-                      VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE);
-           }
-       }
+      vty_out (vty, "  Level-%d:%s", level, VTY_NEWLINE);
+      spftree = area->spftree[level - 1];
+      if (spftree->pending)
+        vty_out (vty, "    IPv4 SPF: (pending)%s", VTY_NEWLINE);
+      else
+        vty_out (vty, "    IPv4 SPF:%s", VTY_NEWLINE);
+
+      vty_out (vty, "      minimum interval  : %d%s",
+          area->min_spf_interval[level - 1], VTY_NEWLINE);
+
+      vty_out (vty, "      last run elapsed  : ");
+      vty_out_timestr(vty, spftree->last_run_timestamp);
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+      vty_out (vty, "      last run duration : %u usec%s",
+               (u_int32_t)spftree->last_run_duration, VTY_NEWLINE);
+
+      vty_out (vty, "      run count         : %d%s",
+          spftree->runcount, VTY_NEWLINE);
+
+#ifdef HAVE_IPV6
+      spftree = area->spftree6[level - 1];
+      if (spftree->pending)
+        vty_out (vty, "    IPv6 SPF: (pending)%s", VTY_NEWLINE);
+      else
+        vty_out (vty, "    IPv6 SPF:%s", VTY_NEWLINE);
+
+      vty_out (vty, "      minimum interval  : %d%s",
+          area->min_spf_interval[level - 1], VTY_NEWLINE);
+
+      vty_out (vty, "      last run elapsed  : ");
+      vty_out_timestr(vty, spftree->last_run_timestamp);
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+      vty_out (vty, "      last run duration : %u msec%s",
+               spftree->last_run_duration, VTY_NEWLINE);
+
+      vty_out (vty, "      run count         : %d%s",
+          spftree->runcount, VTY_NEWLINE);
+#endif
     }
+  }
+  vty_out (vty, "%s", VTY_NEWLINE);
 
   return CMD_SUCCESS;
 }
 
-DEFUN (show_database_detail,
-       show_database_detail_cmd,
-       "show isis database detail",
-       SHOW_STR
-       "IS-IS information\n"
-       "IS-IS link state database\n")
+/*
+ * This function supports following display options:
+ * [ show isis database [detail] ]
+ * [ show isis database <sysid> [detail] ]
+ * [ show isis database <hostname> [detail] ]
+ * [ show isis database <sysid>.<pseudo-id> [detail] ]
+ * [ show isis database <hostname>.<pseudo-id> [detail] ]
+ * [ show isis database <sysid>.<pseudo-id>-<fragment-number> [detail] ]
+ * [ show isis database <hostname>.<pseudo-id>-<fragment-number> [detail] ]
+ * [ show isis database detail <sysid> ]
+ * [ show isis database detail <hostname> ]
+ * [ show isis database detail <sysid>.<pseudo-id> ]
+ * [ show isis database detail <hostname>.<pseudo-id> ]
+ * [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ]
+ * [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ]
+ */
+static int
+show_isis_database (struct vty *vty, const char *argv, int ui_level)
 {
   struct listnode *node;
   struct isis_area *area;
+  struct isis_lsp *lsp;
+  struct isis_dynhn *dynhn;
+  const char *pos = argv;
+  u_char lspid[ISIS_SYS_ID_LEN+2];
+  char sysid[255];
+  u_char number[3];
   int level, lsp_count;
 
   if (isis->area_list->count == 0)
     return CMD_SUCCESS;
 
+  memset (&lspid, 0, ISIS_SYS_ID_LEN);
+  memset (&sysid, 0, 255);
+
+  /*
+   * extract fragment and pseudo id from the string argv
+   * in the forms:
+   * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
+   * (b) <systemid/hostname>.<pseudo-id> or
+   * (c) <systemid/hostname> or
+   * Where systemid is in the form:
+   * xxxx.xxxx.xxxx
+   */
+  if (argv)
+     strncpy (sysid, argv, 254);
+  if (argv && strlen (argv) > 3)
+    {
+      pos = argv + strlen (argv) - 3;
+      if (strncmp (pos, "-", 1) == 0)
+      {
+        memcpy (number, ++pos, 2);
+        lspid[ISIS_SYS_ID_LEN+1] = (u_char) strtol ((char *)number, NULL, 16);
+        pos -= 4;
+        if (strncmp (pos, ".", 1) != 0)
+          return CMD_ERR_AMBIGUOUS;
+      }
+      if (strncmp (pos, ".", 1) == 0)
+      {
+        memcpy (number, ++pos, 2);
+        lspid[ISIS_SYS_ID_LEN] = (u_char) strtol ((char *)number, NULL, 16);
+        sysid[pos - argv - 1] = '\0';
+      }
+    }
+
   for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
     {
       vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
-              VTY_NEWLINE);
-      for (level = 0; level < ISIS_LEVELS; level++)
-       {
-         if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
-           {
-             vty_out (vty, "IS-IS Level-%d Link State Database:%s",
-                      level + 1, VTY_NEWLINE);
+               VTY_NEWLINE);
 
-             lsp_count = lsp_print_all (vty, area->lspdb[level],
-                                        ISIS_UI_LEVEL_DETAIL,
-                                        area->dynhostname);
-
-             vty_out (vty, "%s    %u LSPs%s%s",
-                      VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE);
-           }
-       }
+      for (level = 0; level < ISIS_LEVELS; level++)
+        {
+          if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
+            {
+              lsp = NULL;
+              if (argv != NULL)
+                {
+                  /*
+                   * Try to find the lsp-id if the argv string is in
+                   * the form hostname.<pseudo-id>-<fragment>
+                   */
+                  if (sysid2buff (lspid, sysid))
+                    {
+                      lsp = lsp_search (lspid, area->lspdb[level]);
+                    }
+                  else if ((dynhn = dynhn_find_by_name (sysid)))
+                    {
+                      memcpy (lspid, dynhn->id, ISIS_SYS_ID_LEN);
+                      lsp = lsp_search (lspid, area->lspdb[level]);
+                    }
+                  else if (strncmp(unix_hostname (), sysid, 15) == 0)
+                    {
+                      memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
+                      lsp = lsp_search (lspid, area->lspdb[level]);
+                    }
+                }
+
+              if (lsp != NULL || argv == NULL)
+                {
+                  vty_out (vty, "IS-IS Level-%d link-state database:%s",
+                           level + 1, VTY_NEWLINE);
+
+                  /* print the title in all cases */
+                  vty_out (vty, "LSP ID                  PduLen  "
+                           "SeqNumber   Chksum  Holdtime  ATT/P/OL%s",
+                           VTY_NEWLINE);
+                }
+
+              if (lsp)
+                {
+                  if (ui_level == ISIS_UI_LEVEL_DETAIL)
+                    lsp_print_detail (lsp, vty, area->dynhostname);
+                  else
+                    lsp_print (lsp, vty, area->dynhostname);
+                }
+              else if (argv == NULL)
+                {
+                  lsp_count = lsp_print_all (vty, area->lspdb[level],
+                                             ui_level,
+                                             area->dynhostname);
+
+                  vty_out (vty, "    %u LSPs%s%s",
+                           lsp_count, VTY_NEWLINE, VTY_NEWLINE);
+                }
+            }
+        }
     }
 
   return CMD_SUCCESS;
 }
 
-/* 
- * 'router isis' command 
- */
-DEFUN (router_isis,
-       router_isis_cmd,
-       "router isis WORD",
-       ROUTER_STR
-       "ISO IS-IS\n"
-       "ISO Routing area tag")
+DEFUN (show_database_brief,
+       show_database_cmd,
+       "show isis database",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS link state database\n")
 {
-  return isis_area_get (vty, argv[0]);
+  return show_isis_database (vty, NULL, ISIS_UI_LEVEL_BRIEF);
 }
 
-/* 
- *'no router isis' command 
- */
-DEFUN (no_router_isis,
-       no_router_isis_cmd,
-       "no router isis WORD",
-       "no\n" ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag")
+DEFUN (show_database_lsp_brief,
+       show_database_arg_cmd,
+       "show isis database WORD",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS link state database\n"
+       "LSP ID\n")
+{
+  return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_BRIEF);
+}
+
+DEFUN (show_database_lsp_detail,
+       show_database_arg_detail_cmd,
+       "show isis database WORD detail",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS link state database\n"
+       "LSP ID\n"
+       "Detailed information\n")
+{
+  return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
+DEFUN (show_database_detail,
+       show_database_detail_cmd,
+       "show isis database detail",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS link state database\n")
+{
+  return show_isis_database (vty, NULL, ISIS_UI_LEVEL_DETAIL);
+}
+
+DEFUN (show_database_detail_lsp,
+       show_database_detail_arg_cmd,
+       "show isis database detail WORD",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS link state database\n"
+       "Detailed information\n"
+       "LSP ID\n")
+{
+  return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
+/* 
+ * 'router isis' command 
+ */
+DEFUN (router_isis,
+       router_isis_cmd,
+       "router isis WORD",
+       ROUTER_STR
+       "ISO IS-IS\n"
+       "ISO Routing area tag")
+{
+  return isis_area_get (vty, argv[0]);
+}
+
+/* 
+ *'no router isis' command 
+ */
+DEFUN (no_router_isis,
+       no_router_isis_cmd,
+       "no router isis WORD",
+       "no\n" ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag")
 {
   return isis_area_destroy (vty, argv[0]);
 }
@@ -1043,10 +1545,69 @@ DEFUN (no_net,
   return area_clear_net_title (vty, argv[0]);
 }
 
-DEFUN (area_passwd,
-       area_passwd_cmd,
-       "area-password WORD",
+DEFUN (area_passwd_md5,
+       area_passwd_md5_cmd,
+       "area-password md5 WORD",
+       "Configure the authentication password for an area\n"
+       "Authentication type\n"
+       "Area password\n")
+{
+  struct isis_area *area;
+  int len;
+
+  area = vty->index;
+
+  if (!area)
+    {
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  len = strlen (argv[0]);
+  if (len > 254)
+    {
+      vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  area->area_passwd.len = (u_char) len;
+  area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+  strncpy ((char *)area->area_passwd.passwd, argv[0], 255);
+
+  if (argc > 1)
+    {
+      SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND);
+      if (strncmp(argv[1], "v", 1) == 0)
+       SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
+      else
+       UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
+    }
+  else
+    {
+      UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND);
+      UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
+    }
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (area_passwd_md5,
+       area_passwd_md5_snpauth_cmd,
+       "area-password md5 WORD authenticate snp (send-only|validate)",
        "Configure the authentication password for an area\n"
+       "Authentication type\n"
+       "Area password\n"
+       "Authentication\n"
+       "SNP PDUs\n"
+       "Send but do not check PDUs on receiving\n"
+       "Send and check PDUs on receiving\n");
+
+DEFUN (area_passwd_clear,
+       area_passwd_clear_cmd,
+       "area-password clear WORD",
+       "Configure the authentication password for an area\n"
+       "Authentication type\n"
        "Area password\n")
 {
   struct isis_area *area;
@@ -1056,16 +1617,17 @@ DEFUN (area_passwd,
 
   if (!area)
     {
-      vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
 
   len = strlen (argv[0]);
   if (len > 254)
     {
       vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_AMBIGUOUS;
     }
+
   area->area_passwd.len = (u_char) len;
   area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
   strncpy ((char *)area->area_passwd.passwd, argv[0], 255);
@@ -1083,14 +1645,16 @@ DEFUN (area_passwd,
       UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND);
       UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
     }
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
 
   return CMD_SUCCESS;
 }
 
-ALIAS (area_passwd,
-       area_passwd_snpauth_cmd,
-       "area-password WORD authenticate snp (send-only|validate)",
+ALIAS (area_passwd_clear,
+       area_passwd_clear_snpauth_cmd,
+       "area-password clear WORD authenticate snp (send-only|validate)",
        "Configure the authentication password for an area\n"
+       "Authentication type\n"
        "Area password\n"
        "Authentication\n"
        "SNP PDUs\n"
@@ -1109,19 +1673,79 @@ DEFUN (no_area_passwd,
 
   if (!area)
     {
-      vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
 
   memset (&area->area_passwd, 0, sizeof (struct isis_passwd));
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (domain_passwd_md5,
+       domain_passwd_md5_cmd,
+       "domain-password md5 WORD",
+       "Set the authentication password for a routing domain\n"
+       "Authentication type\n"
+       "Routing domain password\n")
+{
+  struct isis_area *area;
+  int len;
+
+  area = vty->index;
+
+  if (!area)
+    {
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  len = strlen (argv[0]);
+  if (len > 254)
+    {
+      vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  area->domain_passwd.len = (u_char) len;
+  area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+  strncpy ((char *)area->domain_passwd.passwd, argv[0], 255);
+
+  if (argc > 1)
+    {
+      SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND);
+      if (strncmp(argv[1], "v", 1) == 0)
+       SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
+      else
+       UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
+    }
+  else
+    {
+      UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND);
+      UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
+    }
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
 
   return CMD_SUCCESS;
 }
 
-DEFUN (domain_passwd,
-       domain_passwd_cmd,
-       "domain-password WORD",
+ALIAS (domain_passwd_md5,
+       domain_passwd_md5_snpauth_cmd,
+       "domain-password md5 WORD authenticate snp (send-only|validate)",
+       "Set the authentication password for a routing domain\n"
+       "Authentication type\n"
+       "Routing domain password\n"
+       "Authentication\n"
+       "SNP PDUs\n"
+       "Send but do not check PDUs on receiving\n"
+       "Send and check PDUs on receiving\n");
+
+DEFUN (domain_passwd_clear,
+       domain_passwd_clear_cmd,
+       "domain-password clear WORD",
        "Set the authentication password for a routing domain\n"
+       "Authentication type\n"
        "Routing domain password\n")
 {
   struct isis_area *area;
@@ -1131,16 +1755,17 @@ DEFUN (domain_passwd,
 
   if (!area)
     {
-      vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
 
   len = strlen (argv[0]);
   if (len > 254)
     {
       vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      return CMD_ERR_AMBIGUOUS;
     }
+
   area->domain_passwd.len = (u_char) len;
   area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
   strncpy ((char *)area->domain_passwd.passwd, argv[0], 255);
@@ -1158,14 +1783,16 @@ DEFUN (domain_passwd,
       UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND);
       UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
     }
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
 
   return CMD_SUCCESS;
 }
 
-ALIAS (domain_passwd,
-       domain_passwd_snpauth_cmd,
-       "domain-password WORD authenticate snp (send-only|validate)",
+ALIAS (domain_passwd_clear,
+       domain_passwd_clear_snpauth_cmd,
+       "domain-password clear WORD authenticate snp (send-only|validate)",
        "Set the authentication password for a routing domain\n"
+       "Authentication type\n"
        "Routing domain password\n"
        "Authentication\n"
        "SNP PDUs\n"
@@ -1174,7 +1801,7 @@ ALIAS (domain_passwd,
 
 DEFUN (no_domain_passwd,
        no_domain_passwd_cmd,
-       "no domain-password WORD",
+       "no domain-password",
        NO_STR
        "Set the authentication password for a routing domain\n")
 {
@@ -1184,11 +1811,12 @@ DEFUN (no_domain_passwd,
 
   if (!area)
     {
-      vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
 
   memset (&area->domain_passwd, 0, sizeof (struct isis_passwd));
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
 
   return CMD_SUCCESS;
 }
@@ -1208,8 +1836,8 @@ DEFUN (is_type,
 
   if (!area)
     {
-      vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
     }
 
   type = string2circuit_t (argv[0]);
@@ -1240,8 +1868,9 @@ DEFUN (no_is_type,
   assert (area);
 
   /*
-   * Put the is-type back to default. Which is level-1-2 on first
-   * circuit for the area level-1 for the rest
+   * Put the is-type back to defaults:
+   * - level-1-2 on first area
+   * - level-1 for the rest
    */
   if (listgetdata (listhead (isis->area_list)) == area)
     type = IS_LEVEL_1_AND_2;
@@ -1253,6 +1882,36 @@ DEFUN (no_is_type,
   return CMD_SUCCESS;
 }
 
+static int
+set_lsp_gen_interval (struct vty *vty, struct isis_area *area,
+                      uint16_t interval, int level)
+{
+  int lvl;
+
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
+    {
+      if (!(lvl & level))
+        continue;
+
+      if (interval >= area->lsp_refresh[lvl-1])
+        {
+          vty_out (vty, "LSP gen interval %us must be less than "
+                   "the LSP refresh interval %us%s",
+                   interval, area->lsp_refresh[lvl-1], VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
+    }
+
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
+    {
+      if (!(lvl & level))
+        continue;
+      area->lsp_gen_interval[lvl-1] = interval;
+    }
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (lsp_gen_interval,
        lsp_gen_interval_cmd,
        "lsp-gen-interval <1-120>",
@@ -1261,15 +1920,12 @@ DEFUN (lsp_gen_interval,
 {
   struct isis_area *area;
   uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
   interval = atoi (argv[0]);
-  area->lsp_gen_interval[0] = interval;
-  area->lsp_gen_interval[1] = interval;
-
-  return CMD_SUCCESS;
+  level = IS_LEVEL_1 | IS_LEVEL_2;
+  return set_lsp_gen_interval (vty, area, interval, level);
 }
 
 DEFUN (no_lsp_gen_interval,
@@ -1279,14 +1935,13 @@ DEFUN (no_lsp_gen_interval,
        "Minimum interval between regenerating same LSP\n")
 {
   struct isis_area *area;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
-  area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
-  area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
-
-  return CMD_SUCCESS;
+  interval = DEFAULT_MIN_LSP_GEN_INTERVAL;
+  level = IS_LEVEL_1 | IS_LEVEL_2;
+  return set_lsp_gen_interval (vty, area, interval, level);
 }
 
 ALIAS (no_lsp_gen_interval,
@@ -1305,14 +1960,12 @@ DEFUN (lsp_gen_interval_l1,
 {
   struct isis_area *area;
   uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
   interval = atoi (argv[0]);
-  area->lsp_gen_interval[0] = interval;
-
-  return CMD_SUCCESS;
+  level = IS_LEVEL_1;
+  return set_lsp_gen_interval (vty, area, interval, level);
 }
 
 DEFUN (no_lsp_gen_interval_l1,
@@ -1323,13 +1976,13 @@ DEFUN (no_lsp_gen_interval_l1,
        "Set interval for level 1 only\n")
 {
   struct isis_area *area;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
-  area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
-
-  return CMD_SUCCESS;
+  interval = DEFAULT_MIN_LSP_GEN_INTERVAL;
+  level = IS_LEVEL_1;
+  return set_lsp_gen_interval (vty, area, interval, level);
 }
 
 ALIAS (no_lsp_gen_interval_l1,
@@ -1348,15 +2001,13 @@ DEFUN (lsp_gen_interval_l2,
        "Minimum interval in seconds\n")
 {
   struct isis_area *area;
-  int interval;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
   interval = atoi (argv[0]);
-  area->lsp_gen_interval[1] = interval;
-
-  return CMD_SUCCESS;
+  level = IS_LEVEL_2;
+  return set_lsp_gen_interval (vty, area, interval, level);
 }
 
 DEFUN (no_lsp_gen_interval_l2,
@@ -1367,15 +2018,13 @@ DEFUN (no_lsp_gen_interval_l2,
        "Set interval for level 2 only\n")
 {
   struct isis_area *area;
-  int interval;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
-  interval = atoi (argv[0]);
-  area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
-
-  return CMD_SUCCESS;
+  interval = DEFAULT_MIN_LSP_GEN_INTERVAL;
+  level = IS_LEVEL_2;
+  return set_lsp_gen_interval (vty, area, interval, level);
 }
 
 ALIAS (no_lsp_gen_interval_l2,
@@ -1386,6 +2035,44 @@ ALIAS (no_lsp_gen_interval_l2,
        "Set interval for level 2 only\n"
        "Minimum interval in seconds\n")
 
+static int
+validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
+{
+  struct isis_circuit *circuit;
+  struct listnode *node;
+  
+  if (! vty)
+    return CMD_ERR_AMBIGUOUS;
+
+  if (! area)
+    {
+      vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
+    {
+      if ((area->is_type & IS_LEVEL_1) &&
+          (circuit->is_type & IS_LEVEL_1) &&
+          (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC))
+        {
+          vty_out (vty, "ISIS circuit %s metric is invalid%s",
+                   circuit->interface->name, VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
+      if ((area->is_type & IS_LEVEL_2) &&
+          (circuit->is_type & IS_LEVEL_2) &&
+          (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC))
+        {
+          vty_out (vty, "ISIS circuit %s metric is invalid%s",
+                   circuit->interface->name, VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (metric_style,
        metric_style_cmd,
        "metric-style (narrow|transition|wide)",
@@ -1395,6 +2082,7 @@ DEFUN (metric_style,
        "Use new style of TLVs to carry wider metric\n")
 {
   struct isis_area *area;
+  int ret;
 
   area = vty->index;
   assert (area);
@@ -1411,6 +2099,10 @@ DEFUN (metric_style,
     }
   else if (strncmp (argv[0], "n", 1) == 0)
     {
+      ret = validate_metric_style_narrow (vty, area);
+      if (ret != CMD_SUCCESS)
+        return ret;
+
       area->newmetric = 0;
       area->oldmetric = 1;
     }
@@ -1425,10 +2117,15 @@ DEFUN (no_metric_style,
        "Use old-style (ISO 10589) or new-style packet formats\n")
 {
   struct isis_area *area;
+  int ret;
 
   area = vty->index;
   assert (area);
 
+  ret = validate_metric_style_narrow (vty, area);
+  if (ret != CMD_SUCCESS)
+    return ret;
+
   /* Default is narrow metric. */
   area->newmetric = 0;
   area->oldmetric = 1;
@@ -1436,6 +2133,40 @@ DEFUN (no_metric_style,
   return CMD_SUCCESS;
 }
 
+DEFUN (set_overload_bit,
+       set_overload_bit_cmd,
+       "set-overload-bit",
+       "Set overload bit to avoid any transit traffic\n"
+       "Set overload bit\n")
+{
+  struct isis_area *area;
+
+  area = vty->index;
+  assert (area);
+
+  area->overload_bit = LSPBIT_OL;
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_set_overload_bit,
+       no_set_overload_bit_cmd,
+       "no set-overload-bit",
+       "Reset overload bit to accept transit traffic\n"
+       "Reset overload bit\n")
+{
+  struct isis_area *area;
+
+  area = vty->index;
+  assert (area);
+
+  area->overload_bit = 0;
+  lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (dynamic_hostname,
        dynamic_hostname_cmd,
        "hostname dynamic",
@@ -1447,7 +2178,11 @@ DEFUN (dynamic_hostname,
   area = vty->index;
   assert (area);
 
-  area->dynhostname = 1;
+  if (!area->dynhostname)
+   {
+     area->dynhostname = 1;
+     lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+   }
 
   return CMD_SUCCESS;
 }
@@ -1464,7 +2199,11 @@ DEFUN (no_dynamic_hostname,
   area = vty->index;
   assert (area);
 
-  area->dynhostname = 0;
+  if (area->dynhostname)
+    {
+      area->dynhostname = 0;
+      lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+    }
 
   return CMD_SUCCESS;
 }
@@ -1591,308 +2330,487 @@ ALIAS (no_spf_interval,
        "Set interval for level 2 only\n"
        "Minimum interval between consecutive SPFs in seconds\n")
 
-#ifdef TOPOLOGY_GENERATE
-DEFUN (topology_generate_grid,
-       topology_generate_grid_cmd,
-       "topology generate grid <1-100> <1-100> <1-65000> [param] [param] "
-       "[param]",
-       "Topology generation for IS-IS\n"
-       "Topology generation\n"
-       "Grid topology\n"
-       "X parameter of the grid\n"
-       "Y parameter of the grid\n"
-       "Random seed\n"
-       "Optional param 1\n"
-       "Optional param 2\n"
-       "Optional param 3\n"
-       "Topology\n")
+static int
+set_lsp_max_lifetime (struct vty *vty, struct isis_area *area,
+                      uint16_t interval, int level)
 {
-  struct isis_area *area;
+  int lvl;
+  int set_refresh_interval[ISIS_LEVELS] = {0, 0};
+  uint16_t refresh_interval;
 
-  area = vty->index;
-  assert (area);
+  refresh_interval = interval - 300;
 
-  if (!spgrid_check_params (vty, argc, argv))
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
     {
-      if (area->topology)
-       list_delete (area->topology);
-      area->topology = list_new ();
-      memcpy (area->top_params, vty->buf, 200);
-      gen_spgrid_topology (vty, area->topology);
-      remove_topology_lsps (area);
-      generate_topology_lsps (area);
-      /* Regenerate L1 LSP to get two way connection to the generated
-       * topology. */
-      lsp_regenerate_schedule (area);
+      if (!(lvl & level))
+        continue;
+      if (refresh_interval < area->lsp_refresh[lvl-1])
+        {
+          vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than "
+                   "the configured LSP refresh interval %us%s",
+                   lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE);
+          vty_out (vty, "Automatically reducing level %d LSP refresh interval "
+                   "to %us%s", lvl, refresh_interval, VTY_NEWLINE);
+          set_refresh_interval[lvl-1] = 1;
+
+          if (refresh_interval <= area->lsp_gen_interval[lvl-1])
+            {
+              vty_out (vty, "LSP refresh interval %us must be greater than "
+                       "the configured LSP gen interval %us%s",
+                       refresh_interval, area->lsp_gen_interval[lvl-1],
+                       VTY_NEWLINE);
+              return CMD_ERR_AMBIGUOUS;
+            }
+        }
+    }
+
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
+    {
+      if (!(lvl & level))
+        continue;
+      area->max_lsp_lifetime[lvl-1] = interval;
+      /* Automatically reducing lsp_refresh_interval to interval - 300 */
+      if (set_refresh_interval[lvl-1])
+        area->lsp_refresh[lvl-1] = refresh_interval;
     }
 
+  lsp_regenerate_schedule (area, level, 1);
+
   return CMD_SUCCESS;
 }
 
-DEFUN (show_isis_generated_topology,
-       show_isis_generated_topology_cmd,
-       "show isis generated-topologies",
-       SHOW_STR
-       "CLNS network information\n"
-       "Show generated topologies\n")
+DEFUN (max_lsp_lifetime,
+       max_lsp_lifetime_cmd,
+       "max-lsp-lifetime <350-65535>",
+       "Maximum LSP lifetime\n"
+       "LSP lifetime in seconds\n")
 {
   struct isis_area *area;
-  struct listnode *node;
-  struct listnode *node2;
-  struct arc *arc;
-
-  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
-    {
-      if (!area->topology)
-       continue;
-
-      vty_out (vty, "Topology for isis area: %s%s", area->area_tag,
-              VTY_NEWLINE);
-      vty_out (vty, "From node     To node     Distance%s", VTY_NEWLINE);
+  uint16_t interval;
+  int level;
 
-      for (ALL_LIST_ELEMENTS_RO (area->topology, node2, arc))
-       vty_out (vty, "%9ld %11ld %12ld%s", arc->from_node, arc->to_node,
-                arc->distance, VTY_NEWLINE);
-    }
-  return CMD_SUCCESS;
+  area = vty->index;
+  interval = atoi (argv[0]);
+  level = IS_LEVEL_1 | IS_LEVEL_2;
+  return set_lsp_max_lifetime (vty, area, interval, level);
 }
 
-/* Base IS for topology generation. */
-DEFUN (topology_baseis,
-       topology_baseis_cmd,
-       "topology base-is WORD",
-       "Topology generation for IS-IS\n"
-       "A Network IS Base for this topology\n"
-       "XXXX.XXXX.XXXX Network entity title (NET)\n")
+DEFUN (no_max_lsp_lifetime,
+       no_max_lsp_lifetime_cmd,
+       "no max-lsp-lifetime",
+       NO_STR
+       "LSP lifetime in seconds\n")
 {
   struct isis_area *area;
-  u_char buff[ISIS_SYS_ID_LEN];
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
-  if (sysid2buff (buff, argv[0]))
-    sysid2buff (area->topology_baseis, argv[0]);
-
-  return CMD_SUCCESS;
+  interval = DEFAULT_LSP_LIFETIME;
+  level = IS_LEVEL_1 | IS_LEVEL_2;
+  return set_lsp_max_lifetime (vty, area, interval, level);
 }
 
-DEFUN (no_topology_baseis,
-       no_topology_baseis_cmd,
-       "no topology base-is WORD",
+ALIAS (no_max_lsp_lifetime,
+       no_max_lsp_lifetime_arg_cmd,
+       "no max-lsp-lifetime <350-65535>",
        NO_STR
-       "Topology generation for IS-IS\n"
-       "A Network IS Base for this topology\n"
-       "XXXX.XXXX.XXXX Network entity title (NET)\n")
+       "Maximum LSP lifetime\n"
+       "LSP lifetime in seconds\n")
+
+DEFUN (max_lsp_lifetime_l1,
+       max_lsp_lifetime_l1_cmd,
+       "max-lsp-lifetime level-1 <350-65535>",
+       "Maximum LSP lifetime for Level 1 only\n"
+       "LSP lifetime for Level 1 only in seconds\n")
 {
   struct isis_area *area;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
-  memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
-  return CMD_SUCCESS;
+  interval = atoi (argv[0]);
+  level = IS_LEVEL_1;
+  return set_lsp_max_lifetime (vty, area, interval, level);
 }
 
-ALIAS (no_topology_baseis,
-       no_topology_baseis_noid_cmd,
-       "no topology base-is",
+DEFUN (no_max_lsp_lifetime_l1,
+       no_max_lsp_lifetime_l1_cmd,
+       "no max-lsp-lifetime level-1",
        NO_STR
-       "Topology generation for IS-IS\n"
-       "A Network IS Base for this topology\n")
-
-DEFUN (topology_basedynh,
-       topology_basedynh_cmd,
-       "topology base-dynh WORD",
-       "Topology generation for IS-IS\n"
-       "Dynamic hostname base for this topology\n"
-       "Dynamic hostname base\n")
+       "LSP lifetime for Level 1 only in seconds\n")
 {
   struct isis_area *area;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
-  /* I hope that it's enough. */
-  area->topology_basedynh = strndup (argv[0], 16); 
-  return CMD_SUCCESS;
+  interval = DEFAULT_LSP_LIFETIME;
+  level = IS_LEVEL_1;
+  return set_lsp_max_lifetime (vty, area, interval, level);
 }
-#endif /* TOPOLOGY_GENERATE */
 
-DEFUN (lsp_lifetime,
-       lsp_lifetime_cmd,
-       "lsp-lifetime <380-65535>",
-       "Maximum LSP lifetime\n"
-       "LSP lifetime in seconds\n")
+ALIAS (no_max_lsp_lifetime_l1,
+       no_max_lsp_lifetime_l1_arg_cmd,
+       "no max-lsp-lifetime level-1 <350-65535>",
+       NO_STR
+       "Maximum LSP lifetime for Level 1 only\n"
+       "LSP lifetime for Level 1 only in seconds\n")
+
+DEFUN (max_lsp_lifetime_l2,
+       max_lsp_lifetime_l2_cmd,
+       "max-lsp-lifetime level-2 <350-65535>",
+       "Maximum LSP lifetime for Level 2 only\n"
+       "LSP lifetime for Level 2 only in seconds\n")
 {
   struct isis_area *area;
   uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
-
   interval = atoi (argv[0]);
+  level = IS_LEVEL_2;
+  return set_lsp_max_lifetime (vty, area, interval, level);
+}
 
-  if (interval < ISIS_MIN_LSP_LIFETIME)
-    {
-      vty_out (vty, "LSP lifetime (%us) below %us%s",
-              interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE);
+DEFUN (no_max_lsp_lifetime_l2,
+       no_max_lsp_lifetime_l2_cmd,
+       "no max-lsp-lifetime level-2",
+       NO_STR
+       "LSP lifetime for Level 2 only in seconds\n")
+{
+  struct isis_area *area;
+  uint16_t interval;
+  int level;
 
-      return CMD_WARNING;
-    }
+  area = vty->index;
+  interval = DEFAULT_LSP_LIFETIME;
+  level = IS_LEVEL_2;
+  return set_lsp_max_lifetime (vty, area, interval, level);
+}
 
+ALIAS (no_max_lsp_lifetime_l2,
+       no_max_lsp_lifetime_l2_arg_cmd,
+       "no max-lsp-lifetime level-2 <350-65535>",
+       NO_STR
+       "Maximum LSP lifetime for Level 2 only\n"
+       "LSP lifetime for Level 2 only in seconds\n")
 
-  area->max_lsp_lifetime[0] = interval;
-  area->max_lsp_lifetime[1] = interval;
-  area->lsp_refresh[0] = interval - 300;
-  area->lsp_refresh[1] = interval - 300;
+static int
+set_lsp_refresh_interval (struct vty *vty, struct isis_area *area,
+                          uint16_t interval, int level)
+{
+  int lvl;
 
-  if (area->t_lsp_refresh[0])
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
     {
-      thread_cancel (area->t_lsp_refresh[0]);
-      thread_execute (master, lsp_refresh_l1, area, 0);
+      if (!(lvl & level))
+        continue;
+      if (interval <= area->lsp_gen_interval[lvl-1])
+        {
+          vty_out (vty, "LSP refresh interval %us must be greater than "
+                   "the configured LSP gen interval %us%s",
+                   interval, area->lsp_gen_interval[lvl-1],
+                   VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
+      if (interval > (area->max_lsp_lifetime[lvl-1] - 300))
+        {
+          vty_out (vty, "LSP refresh interval %us must be less than "
+                   "the configured LSP lifetime %us less 300%s",
+                   interval, area->max_lsp_lifetime[lvl-1],
+                   VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
     }
 
-  if (area->t_lsp_refresh[1])
+  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
     {
-      thread_cancel (area->t_lsp_refresh[1]);
-      thread_execute (master, lsp_refresh_l2, area, 0);
+      if (!(lvl & level))
+        continue;
+      area->lsp_refresh[lvl-1] = interval;
     }
-
+  lsp_regenerate_schedule (area, level, 1);
 
   return CMD_SUCCESS;
 }
 
-DEFUN (no_lsp_lifetime,
-       no_lsp_lifetime_cmd,
-       "no lsp-lifetime",
-       NO_STR
-       "LSP lifetime in seconds\n")
+DEFUN (lsp_refresh_interval,
+       lsp_refresh_interval_cmd,
+       "lsp-refresh-interval <1-65235>",
+       "LSP refresh interval\n"
+       "LSP refresh interval in seconds\n")
 {
   struct isis_area *area;
+  uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
+  interval = atoi (argv[0]);
+  level = IS_LEVEL_1 | IS_LEVEL_2;
+  return set_lsp_refresh_interval (vty, area, interval, level);
+}
 
-  area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */
-  area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */
-  area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /*  900s */
-  area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /*  900s */
+DEFUN (no_lsp_refresh_interval,
+       no_lsp_refresh_interval_cmd,
+       "no lsp-refresh-interval",
+       NO_STR
+       "LSP refresh interval in seconds\n")
+{
+  struct isis_area *area;
+  uint16_t interval;
+  int level;
 
-  return CMD_SUCCESS;
+  area = vty->index;
+  interval = DEFAULT_MAX_LSP_GEN_INTERVAL;
+  level = IS_LEVEL_1 | IS_LEVEL_2;
+  return set_lsp_refresh_interval (vty, area, interval, level);
 }
 
-ALIAS (no_lsp_lifetime,
-       no_lsp_lifetime_arg_cmd,
-       "no lsp-lifetime <380-65535>",
+ALIAS (no_lsp_refresh_interval,
+       no_lsp_refresh_interval_arg_cmd,
+       "no lsp-refresh-interval <1-65235>",
        NO_STR
-       "Maximum LSP lifetime\n"
-       "LSP lifetime in seconds\n")
+       "LSP refresh interval\n"
+       "LSP refresh interval in seconds\n")
 
-DEFUN (lsp_lifetime_l1,
-       lsp_lifetime_l1_cmd,
-       "lsp-lifetime level-1 <380-65535>",
-       "Maximum LSP lifetime for Level 1 only\n"
-       "LSP lifetime for Level 1 only in seconds\n")
+DEFUN (lsp_refresh_interval_l1,
+       lsp_refresh_interval_l1_cmd,
+       "lsp-refresh-interval level-1 <1-65235>",
+       "LSP refresh interval for Level 1 only\n"
+       "LSP refresh interval for Level 1 only in seconds\n")
 {
   struct isis_area *area;
   uint16_t interval;
+  int level;
 
   area = vty->index;
-  assert (area);
+  interval = atoi (argv[0]);
+  level = IS_LEVEL_1;
+  return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+DEFUN (no_lsp_refresh_interval_l1,
+       no_lsp_refresh_interval_l1_cmd,
+       "no lsp-refresh-interval level-1",
+       NO_STR
+       "LSP refresh interval for Level 1 only in seconds\n")
+{
+  struct isis_area *area;
+  uint16_t interval;
+  int level;
+
+  area = vty->index;
+  interval = DEFAULT_MAX_LSP_GEN_INTERVAL;
+  level = IS_LEVEL_1;
+  return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+ALIAS (no_lsp_refresh_interval_l1,
+       no_lsp_refresh_interval_l1_arg_cmd,
+       "no lsp-refresh-interval level-1 <1-65235>",
+       NO_STR
+       "LSP refresh interval for Level 1 only\n"
+       "LSP refresh interval for Level 1 only in seconds\n")
+
+DEFUN (lsp_refresh_interval_l2,
+       lsp_refresh_interval_l2_cmd,
+       "lsp-refresh-interval level-2 <1-65235>",
+       "LSP refresh interval for Level 2 only\n"
+       "LSP refresh interval for Level 2 only in seconds\n")
+{
+  struct isis_area *area;
+  uint16_t interval;
+  int level;
 
+  area = vty->index;
   interval = atoi (argv[0]);
+  level = IS_LEVEL_2;
+  return set_lsp_refresh_interval (vty, area, interval, level);
+}
 
-  if (interval < ISIS_MIN_LSP_LIFETIME)
-    {
-      vty_out (vty, "Level-1 LSP lifetime (%us) below %us%s",
-              interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE);
+DEFUN (no_lsp_refresh_interval_l2,
+       no_lsp_refresh_interval_l2_cmd,
+       "no lsp-refresh-interval level-2",
+       NO_STR
+       "LSP refresh interval for Level 2 only in seconds\n")
+{
+  struct isis_area *area;
+  uint16_t interval;
+  int level;
 
-      return CMD_WARNING;
-    }
+  area = vty->index;
+  interval = DEFAULT_MAX_LSP_GEN_INTERVAL;
+  level = IS_LEVEL_2;
+  return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+ALIAS (no_lsp_refresh_interval_l2,
+       no_lsp_refresh_interval_l2_arg_cmd,
+       "no lsp-refresh-interval level-2 <1-65235>",
+       NO_STR
+       "LSP refresh interval for Level 2 only\n"
+       "LSP refresh interval for Level 2 only in seconds\n")
+
+DEFUN (log_adj_changes,
+       log_adj_changes_cmd,
+       "log-adjacency-changes",
+       "Log changes in adjacency state\n")
+{
+  struct isis_area *area;
 
+  area = vty->index;
+  assert (area);
 
-  area->max_lsp_lifetime[0] = interval;
-  area->lsp_refresh[0] = interval - 300;
+  area->log_adj_changes = 1;
 
   return CMD_SUCCESS;
 }
 
-DEFUN (no_lsp_lifetime_l1,
-       no_lsp_lifetime_l1_cmd,
-       "no lsp-lifetime level-1",
-       NO_STR
-       "LSP lifetime for Level 1 only in seconds\n")
+DEFUN (no_log_adj_changes,
+       no_log_adj_changes_cmd,
+       "no log-adjacency-changes",
+       "Stop logging changes in adjacency state\n")
 {
   struct isis_area *area;
 
   area = vty->index;
   assert (area);
 
-  area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */
-  area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /*  900s */
+  area->log_adj_changes = 0;
 
   return CMD_SUCCESS;
 }
 
-ALIAS (no_lsp_lifetime_l1,
-       no_lsp_lifetime_l1_arg_cmd,
-       "no lsp-lifetime level-1 <380-65535>",
-       NO_STR
-       "Maximum LSP lifetime for Level 1 only\n"
-       "LSP lifetime for Level 1 only in seconds\n")
+#ifdef TOPOLOGY_GENERATE
 
-DEFUN (lsp_lifetime_l2,
-       lsp_lifetime_l2_cmd,
-       "lsp-lifetime level-2 <380-65535>",
-       "Maximum LSP lifetime for Level 2 only\n"
-       "LSP lifetime for Level 2 only in seconds\n")
+DEFUN (topology_generate_grid,
+       topology_generate_grid_cmd,
+       "topology generate grid <1-100> <1-100> <1-65000> [param] [param] "
+       "[param]",
+       "Topology generation for IS-IS\n"
+       "Topology generation\n"
+       "Grid topology\n"
+       "X parameter of the grid\n"
+       "Y parameter of the grid\n"
+       "Random seed\n"
+       "Optional param 1\n"
+       "Optional param 2\n"
+       "Optional param 3\n"
+       "Topology\n")
 {
   struct isis_area *area;
-  uint16_t interval;
 
   area = vty->index;
   assert (area);
 
-  interval = atoi (argv[0]);
+  if (!spgrid_check_params (vty, argc, argv))
+    {
+      if (area->topology)
+       list_delete (area->topology);
+      area->topology = list_new ();
+      memcpy (area->top_params, vty->buf, 200);
+      gen_spgrid_topology (vty, area->topology);
+      remove_topology_lsps (area);
+      generate_topology_lsps (area);
+      /* Regenerate L1 LSP to get two way connection to the generated
+       * topology. */
+      lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_isis_generated_topology,
+       show_isis_generated_topology_cmd,
+       "show isis generated-topologies",
+       SHOW_STR
+       "ISIS network information\n"
+       "Show generated topologies\n")
+{
+  struct isis_area *area;
+  struct listnode *node;
+  struct listnode *node2;
+  struct arc *arc;
 
-  if (interval < ISIS_MIN_LSP_LIFETIME)
+  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
     {
-      vty_out (vty, "Level-2 LSP lifetime (%us) below %us%s",
-              interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE);
+      if (!area->topology)
+       continue;
+
+      vty_out (vty, "Topology for isis area: %s%s", area->area_tag,
+              VTY_NEWLINE);
+      vty_out (vty, "From node     To node     Distance%s", VTY_NEWLINE);
 
-      return CMD_WARNING;
+      for (ALL_LIST_ELEMENTS_RO (area->topology, node2, arc))
+       vty_out (vty, "%9ld %11ld %12ld%s", arc->from_node, arc->to_node,
+                arc->distance, VTY_NEWLINE);
     }
+  return CMD_SUCCESS;
+}
+
+/* Base IS for topology generation. */
+DEFUN (topology_baseis,
+       topology_baseis_cmd,
+       "topology base-is WORD",
+       "Topology generation for IS-IS\n"
+       "A Network IS Base for this topology\n"
+       "XXXX.XXXX.XXXX Network entity title (NET)\n")
+{
+  struct isis_area *area;
+  u_char buff[ISIS_SYS_ID_LEN];
 
-  area->max_lsp_lifetime[1] = interval;
-  area->lsp_refresh[1] = interval - 300;
+  area = vty->index;
+  assert (area);
+
+  if (sysid2buff (buff, argv[0]))
+    sysid2buff (area->topology_baseis, argv[0]);
 
   return CMD_SUCCESS;
 }
 
-DEFUN (no_lsp_lifetime_l2,
-       no_lsp_lifetime_l2_cmd,
-       "no lsp-lifetime level-2",
+DEFUN (no_topology_baseis,
+       no_topology_baseis_cmd,
+       "no topology base-is WORD",
        NO_STR
-       "LSP lifetime for Level 2 only in seconds\n")
+       "Topology generation for IS-IS\n"
+       "A Network IS Base for this topology\n"
+       "XXXX.XXXX.XXXX Network entity title (NET)\n")
 {
   struct isis_area *area;
 
   area = vty->index;
   assert (area);
 
-  area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */
-  area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /*  900s */
-
+  memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
   return CMD_SUCCESS;
 }
 
-ALIAS (no_lsp_lifetime_l2,
-       no_lsp_lifetime_l2_arg_cmd,
-       "no lsp-lifetime level-2 <380-65535>",
+ALIAS (no_topology_baseis,
+       no_topology_baseis_noid_cmd,
+       "no topology base-is",
        NO_STR
-       "Maximum LSP lifetime for Level 2 only\n"
-       "LSP lifetime for Level 2 only in seconds\n")
+       "Topology generation for IS-IS\n"
+       "A Network IS Base for this topology\n")
+
+DEFUN (topology_basedynh,
+       topology_basedynh_cmd,
+       "topology base-dynh WORD",
+       "Topology generation for IS-IS\n"
+       "Dynamic hostname base for this topology\n"
+       "Dynamic hostname base\n")
+{
+  struct isis_area *area;
+
+  area = vty->index;
+  assert (area);
+
+  /* I hope that it's enough. */
+  area->topology_basedynh = strndup (argv[0], 16); 
+  return CMD_SUCCESS;
+}
+
+#endif /* TOPOLOGY_GENERATE */
 
 /* IS-IS configuration write function */
 int
@@ -1939,25 +2857,27 @@ isis_config_write (struct vty *vty)
              vty_out (vty, " metric-style transition%s", VTY_NEWLINE);
            write++;
          }
-
+       /* ISIS - overload-bit */
+       if (area->overload_bit)
+         {
+           vty_out (vty, " set-overload-bit%s", VTY_NEWLINE);
+           write++;
+         }
        /* ISIS - Area is-type (level-1-2 is default) */
        if (area->is_type == IS_LEVEL_1)
          {
            vty_out (vty, " is-type level-1%s", VTY_NEWLINE);
            write++;
          }
-       else
+       else if (area->is_type == IS_LEVEL_2)
          {
-           if (area->is_type == IS_LEVEL_2)
-             {
-               vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE);
-               write++;
-             }
+           vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE);
+           write++;
          }
        /* ISIS - Lsp generation interval */
        if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1])
          {
-           if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT)
+           if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL)
              {
                vty_out (vty, " lsp-gen-interval %d%s",
                         area->lsp_gen_interval[0], VTY_NEWLINE);
@@ -1966,13 +2886,13 @@ isis_config_write (struct vty *vty)
          }
        else
          {
-           if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT)
+           if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL)
              {
                vty_out (vty, " lsp-gen-interval level-1 %d%s",
                         area->lsp_gen_interval[0], VTY_NEWLINE);
                write++;
              }
-           if (area->lsp_gen_interval[1] != LSP_GEN_INTERVAL_DEFAULT)
+           if (area->lsp_gen_interval[1] != DEFAULT_MIN_LSP_GEN_INTERVAL)
              {
                vty_out (vty, " lsp-gen-interval level-2 %d%s",
                         area->lsp_gen_interval[1], VTY_NEWLINE);
@@ -1982,28 +2902,53 @@ isis_config_write (struct vty *vty)
        /* ISIS - LSP lifetime */
        if (area->max_lsp_lifetime[0] == area->max_lsp_lifetime[1])
          {
-           if (area->max_lsp_lifetime[0] != MAX_AGE)
+           if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME)
              {
-               vty_out (vty, " lsp-lifetime %u%s", area->max_lsp_lifetime[0],
+               vty_out (vty, " max-lsp-lifetime %u%s", area->max_lsp_lifetime[0],
                         VTY_NEWLINE);
                write++;
              }
          }
        else
          {
-           if (area->max_lsp_lifetime[0] != MAX_AGE)
+           if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME)
              {
-               vty_out (vty, " lsp-lifetime level-1 %u%s",
+               vty_out (vty, " max-lsp-lifetime level-1 %u%s",
                         area->max_lsp_lifetime[0], VTY_NEWLINE);
                write++;
              }
-           if (area->max_lsp_lifetime[1] != MAX_AGE)
+           if (area->max_lsp_lifetime[1] != DEFAULT_LSP_LIFETIME)
              {
-               vty_out (vty, " lsp-lifetime level-2 %u%s",
+               vty_out (vty, " max-lsp-lifetime level-2 %u%s",
                         area->max_lsp_lifetime[1], VTY_NEWLINE);
                write++;
              }
          }
+       /* ISIS - LSP refresh interval */
+       if (area->lsp_refresh[0] == area->lsp_refresh[1])
+         {
+           if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL)
+             {
+               vty_out (vty, " lsp-refresh-interval %u%s", area->lsp_refresh[0],
+                        VTY_NEWLINE);
+               write++;
+             }
+         }
+       else
+         {
+           if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL)
+             {
+               vty_out (vty, " lsp-refresh-interval level-1 %u%s",
+                        area->lsp_refresh[0], VTY_NEWLINE);
+               write++;
+             }
+           if (area->lsp_refresh[1] != DEFAULT_MAX_LSP_GEN_INTERVAL)
+             {
+               vty_out (vty, " lsp-refresh-interval level-2 %u%s",
+                        area->lsp_refresh[1], VTY_NEWLINE);
+               write++;
+             }
+         }
        /* Minimum SPF interval. */
        if (area->min_spf_interval[0] == area->min_spf_interval[1])
          {
@@ -2030,9 +2975,23 @@ isis_config_write (struct vty *vty)
              }
          }
        /* Authentication passwords. */
-       if (area->area_passwd.len > 0)
+       if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
          {
-           vty_out(vty, " area-password %s", area->area_passwd.passwd);
+           vty_out(vty, " area-password md5 %s", area->area_passwd.passwd);
+           if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND))
+             {
+               vty_out(vty, " authenticate snp ");
+               if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV))
+                 vty_out(vty, "validate");
+               else
+                 vty_out(vty, "send-only");
+             }
+           vty_out(vty, "%s", VTY_NEWLINE);
+           write++; 
+         }
+        else if (area->area_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+          {
+           vty_out(vty, " area-password clear %s", area->area_passwd.passwd);
            if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND))
              {
                vty_out(vty, " authenticate snp ");
@@ -2043,10 +3002,26 @@ isis_config_write (struct vty *vty)
              }
            vty_out(vty, "%s", VTY_NEWLINE);
            write++; 
-         }  
-       if (area->domain_passwd.len > 0)
+          }
+       if (area->domain_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
          {
-           vty_out(vty, " domain-password %s", area->domain_passwd.passwd);
+            vty_out(vty, " domain-password md5 %s",
+                    area->domain_passwd.passwd);
+           if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND))
+             {
+               vty_out(vty, " authenticate snp ");
+               if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV))
+                 vty_out(vty, "validate");
+               else
+                 vty_out(vty, "send-only");
+             }
+           vty_out(vty, "%s", VTY_NEWLINE);
+           write++;
+         }
+        else if (area->domain_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+         {
+           vty_out(vty, " domain-password clear %s",
+                    area->domain_passwd.passwd); 
            if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND))
              {
                vty_out(vty, " authenticate snp ");
@@ -2059,12 +3034,18 @@ isis_config_write (struct vty *vty)
            write++;
          }
 
+       if (area->log_adj_changes)
+         {
+           vty_out (vty, " log-adjacency-changes%s", VTY_NEWLINE);
+           write++;
+         }
+
 #ifdef TOPOLOGY_GENERATE
        if (memcmp (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS,
                    ISIS_SYS_ID_LEN))
          {
            vty_out (vty, " topology base-is %s%s",
-                    sysid_print (area->topology_baseis), VTY_NEWLINE);
+                    sysid_print ((u_char *)area->topology_baseis), VTY_NEWLINE);
            write++;
          }
        if (area->topology_basedynh)
@@ -2087,7 +3068,7 @@ isis_config_write (struct vty *vty)
   return write;
 }
 
-static struct cmd_node isis_node = {
+struct cmd_node isis_node = {
   ISIS_NODE,
   "%s(config-router)# ",
   1
@@ -2099,23 +3080,43 @@ isis_init ()
   /* Install IS-IS top node */
   install_node (&isis_node, isis_config_write);
 
-  install_element (VIEW_NODE, &show_clns_neighbors_cmd);
-  install_element (VIEW_NODE, &show_isis_neighbors_cmd);
-  install_element (VIEW_NODE, &show_clns_neighbors_detail_cmd);
-  install_element (VIEW_NODE, &show_isis_neighbors_detail_cmd);
+  install_element (VIEW_NODE, &show_isis_summary_cmd);
+
+  install_element (VIEW_NODE, &show_isis_interface_cmd);
+  install_element (VIEW_NODE, &show_isis_interface_detail_cmd);
+  install_element (VIEW_NODE, &show_isis_interface_arg_cmd);
+
+  install_element (VIEW_NODE, &show_isis_neighbor_cmd);
+  install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd);
+  install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd);
+  install_element (VIEW_NODE, &clear_isis_neighbor_cmd);
+  install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd);
 
   install_element (VIEW_NODE, &show_hostname_cmd);
   install_element (VIEW_NODE, &show_database_cmd);
+  install_element (VIEW_NODE, &show_database_arg_cmd);
+  install_element (VIEW_NODE, &show_database_arg_detail_cmd);
   install_element (VIEW_NODE, &show_database_detail_cmd);
+  install_element (VIEW_NODE, &show_database_detail_arg_cmd);
+
+  install_element (ENABLE_NODE, &show_isis_summary_cmd);
 
-  install_element (ENABLE_NODE, &show_clns_neighbors_cmd);
-  install_element (ENABLE_NODE, &show_isis_neighbors_cmd);
-  install_element (ENABLE_NODE, &show_clns_neighbors_detail_cmd);
-  install_element (ENABLE_NODE, &show_isis_neighbors_detail_cmd);
+  install_element (ENABLE_NODE, &show_isis_interface_cmd);
+  install_element (ENABLE_NODE, &show_isis_interface_detail_cmd);
+  install_element (ENABLE_NODE, &show_isis_interface_arg_cmd);
+
+  install_element (ENABLE_NODE, &show_isis_neighbor_cmd);
+  install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd);
+  install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd);
+  install_element (ENABLE_NODE, &clear_isis_neighbor_cmd);
+  install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd);
 
   install_element (ENABLE_NODE, &show_hostname_cmd);
   install_element (ENABLE_NODE, &show_database_cmd);
+  install_element (ENABLE_NODE, &show_database_arg_cmd);
+  install_element (ENABLE_NODE, &show_database_arg_detail_cmd);
   install_element (ENABLE_NODE, &show_database_detail_cmd);
+  install_element (ENABLE_NODE, &show_database_detail_arg_cmd);
   install_element (ENABLE_NODE, &show_debugging_cmd);
 
   install_node (&debug_node, config_write_debug);
@@ -2142,6 +3143,8 @@ isis_init ()
   install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd);
   install_element (ENABLE_NODE, &debug_isis_events_cmd);
   install_element (ENABLE_NODE, &no_debug_isis_events_cmd);
+  install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd);
+  install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd);
 
   install_element (CONFIG_NODE, &debug_isis_adj_cmd);
   install_element (CONFIG_NODE, &no_debug_isis_adj_cmd);
@@ -2165,6 +3168,8 @@ isis_init ()
   install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd);
   install_element (CONFIG_NODE, &debug_isis_events_cmd);
   install_element (CONFIG_NODE, &no_debug_isis_events_cmd);
+  install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd);
+  install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd);
 
   install_element (CONFIG_NODE, &router_isis_cmd);
   install_element (CONFIG_NODE, &no_router_isis_cmd);
@@ -2177,12 +3182,16 @@ isis_init ()
   install_element (ISIS_NODE, &is_type_cmd);
   install_element (ISIS_NODE, &no_is_type_cmd);
 
-  install_element (ISIS_NODE, &area_passwd_cmd);
-  install_element (ISIS_NODE, &area_passwd_snpauth_cmd);
+  install_element (ISIS_NODE, &area_passwd_md5_cmd);
+  install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd);
+  install_element (ISIS_NODE, &area_passwd_clear_cmd);
+  install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd);
   install_element (ISIS_NODE, &no_area_passwd_cmd);
 
-  install_element (ISIS_NODE, &domain_passwd_cmd);
-  install_element (ISIS_NODE, &domain_passwd_snpauth_cmd);
+  install_element (ISIS_NODE, &domain_passwd_md5_cmd);
+  install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd);
+  install_element (ISIS_NODE, &domain_passwd_clear_cmd);
+  install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd);
   install_element (ISIS_NODE, &no_domain_passwd_cmd);
 
   install_element (ISIS_NODE, &lsp_gen_interval_cmd);
@@ -2205,21 +3214,38 @@ isis_init ()
   install_element (ISIS_NODE, &no_spf_interval_l2_cmd);
   install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd);
 
-  install_element (ISIS_NODE, &lsp_lifetime_cmd);
-  install_element (ISIS_NODE, &no_lsp_lifetime_cmd);
-  install_element (ISIS_NODE, &no_lsp_lifetime_arg_cmd);
-  install_element (ISIS_NODE, &lsp_lifetime_l1_cmd);
-  install_element (ISIS_NODE, &no_lsp_lifetime_l1_cmd);
-  install_element (ISIS_NODE, &no_lsp_lifetime_l1_arg_cmd);
-  install_element (ISIS_NODE, &lsp_lifetime_l2_cmd);
-  install_element (ISIS_NODE, &no_lsp_lifetime_l2_cmd);
-  install_element (ISIS_NODE, &no_lsp_lifetime_l2_arg_cmd);
+  install_element (ISIS_NODE, &max_lsp_lifetime_cmd);
+  install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd);
+  install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd);
+  install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd);
+  install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd);
+  install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd);
+  install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd);
+  install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd);
+  install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd);
+
+  install_element (ISIS_NODE, &lsp_refresh_interval_cmd);
+  install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd);
+  install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd);
+  install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd);
+  install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd);
+  install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd);
+  install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd);
+  install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd);
+  install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd);
+
+  install_element (ISIS_NODE, &set_overload_bit_cmd);
+  install_element (ISIS_NODE, &no_set_overload_bit_cmd);
 
   install_element (ISIS_NODE, &dynamic_hostname_cmd);
   install_element (ISIS_NODE, &no_dynamic_hostname_cmd);
 
   install_element (ISIS_NODE, &metric_style_cmd);
   install_element (ISIS_NODE, &no_metric_style_cmd);
+
+  install_element (ISIS_NODE, &log_adj_changes_cmd);
+  install_element (ISIS_NODE, &no_log_adj_changes_cmd);
+
 #ifdef TOPOLOGY_GENERATE
   install_element (ISIS_NODE, &topology_generate_grid_cmd);
   install_element (ISIS_NODE, &topology_baseis_cmd);
@@ -2229,9 +3255,4 @@ isis_init ()
   install_element (VIEW_NODE, &show_isis_generated_topology_cmd);
   install_element (ENABLE_NODE, &show_isis_generated_topology_cmd);
 #endif /* TOPOLOGY_GENERATE */
-
-  isis_new (0);
-  isis_circuit_init ();
-  isis_zebra_init ();
-  isis_spf_cmds_init ();
 }
index b17982e2522a194a1f7c1de85a1aa644dba19b6e..5db485f47265b5899a91cd8c0b2636f141894d18 100644 (file)
@@ -40,6 +40,7 @@ struct isis
   u_long process_id;
   int sysid_set;
   u_char sysid[ISIS_SYS_ID_LEN];       /* SystemID for this IS */
+  u_int32_t router_id;          /* Router ID from zebra */
   struct list *area_list;      /* list of IS-IS areas */
   struct list *init_circ_list;
   struct list *nexthops;       /* IPv4 next hops from this IS */
@@ -78,6 +79,8 @@ struct isis
 #endif
 };
 
+extern struct isis *isis;
+
 struct isis_area
 {
   struct isis *isis;                             /* back pointer */
@@ -92,11 +95,8 @@ struct isis_area
   struct list *circuit_list;   /* IS-IS circuits */
   struct flags flags;
   struct thread *t_tick;       /* LSP walker */
-  struct thread *t_remove_aged;
-  struct thread *t_lsp_l1_regenerate;
-  struct thread *t_lsp_l2_regenerate;
-  int lsp_regenerate_pending[ISIS_LEVELS];
   struct thread *t_lsp_refresh[ISIS_LEVELS];
+  int lsp_regenerate_pending[ISIS_LEVELS];
 
   /*
    * Configurables 
@@ -114,6 +114,8 @@ struct isis_area
   struct list *area_addrs;
   u_int16_t max_lsp_lifetime[ISIS_LEVELS];
   char is_type;                        /* level-1 level-1-2 or level-2-only */
+  /* are we overloaded? */
+  char overload_bit;
   u_int16_t lsp_refresh[ISIS_LEVELS];
   /* minimum time allowed before lsp retransmission */
   u_int16_t lsp_gen_interval[ISIS_LEVELS];
@@ -122,6 +124,8 @@ struct isis_area
   /* the percentage of LSP mtu size used, before generating a new frag */
   int lsp_frag_threshold;
   int ip_circuits;
+  /* logging adjacency changes? */
+  u_char log_adj_changes;
 #ifdef HAVE_IPV6
   int ipv6_circuits;
 #endif                         /* HAVE_IPV6 */
@@ -130,14 +134,21 @@ struct isis_area
 
 #ifdef TOPOLOGY_GENERATE
   struct list *topology;
-  char topology_baseis[ISIS_SYS_ID_LEN];  /* IS for the first IS emulated. */
+  u_char topology_baseis[ISIS_SYS_ID_LEN];  /* IS for the first IS emulated. */
   char *topology_basedynh;                /* Dynamic hostname base. */
   char top_params[200];                   /* FIXME: what is reasonable? */
 #endif /* TOPOLOGY_GENERATE */
 };
 
 void isis_init (void);
+void isis_new(unsigned long);
+struct isis_area *isis_area_create(const char *);
 struct isis_area *isis_area_lookup (const char *);
+int isis_area_get (struct vty *vty, const char *area_tag);
+void print_debug(struct vty *, int, int);
+
+/* Master of threads. */
+extern struct thread_master *master;
 
 #define DEBUG_ADJ_PACKETS                (1<<0)
 #define DEBUG_CHECKSUM_ERRORS            (1<<1)
@@ -151,5 +162,6 @@ struct isis_area *isis_area_lookup (const char *);
 #define DEBUG_RTE_EVENTS                 (1<<9)
 #define DEBUG_EVENTS                     (1<<10)
 #define DEBUG_ZEBRA                      (1<<11)
+#define DEBUG_PACKET_DUMP                (1<<12)
 
 #endif /* ISISD_H */
diff --git a/isisd/topology/.cvsignore b/isisd/topology/.cvsignore
new file mode 100644 (file)
index 0000000..b0ae823
--- /dev/null
@@ -0,0 +1,9 @@
+Makefile
+Makefile.in
+*.o
+tags
+TAGS
+.deps
+.nfs*
+.arch-inventory
+.arch-ids
index 1e99ffbca561a96d72f9d189f00e49e7618e05ad..e26aa046f8fff39ba0fcd4b921255d4a5b1cf713 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -146,7 +146,7 @@ if_delete_retain (struct interface *ifp)
     (*if_master.if_delete_hook) (ifp);
 
   /* Free connected address list */
-  list_delete (ifp->connected);
+  list_delete_all_node (ifp->connected);
 }
 
 /* Delete and free interface structure. */
@@ -157,6 +157,8 @@ if_delete (struct interface *ifp)
 
   if_delete_retain(ifp);
 
+  list_free (ifp->connected);
+
   XFREE (MTYPE_IF, ifp);
 }
 
index cc6867cd4881356b474f8e33c70cd38cd25269d5..f0ae36256d12dc620f2b66764cd6478e8e892172 100644 (file)
@@ -54,9 +54,9 @@ struct list
   void (*del) (void *val);
 };
 
-#define listnextnode(X) ((X)->next)
-#define listhead(X) ((X)->head)
-#define listtail(X) ((X)->tail)
+#define listnextnode(X) ((X) ? ((X)->next) : NULL)
+#define listhead(X) ((X) ? ((X)->head) : NULL)
+#define listtail(X) ((X) ? ((X)->tail) : NULL)
 #define listcount(X) ((X)->count)
 #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
 #define listgetdata(X) (assert((X)->data != NULL), (X)->data)
@@ -88,10 +88,10 @@ extern void list_add_list (struct list *, struct list *);
  * It is safe to delete the listnode using this macro.
  */
 #define ALL_LIST_ELEMENTS(list,node,nextnode,data) \
-  (node) = listhead(list); \
+  (node) = listhead(list), ((data) = NULL); \
   (node) != NULL && \
     ((data) = listgetdata(node),(nextnode) = listnextnode(node), 1); \
-  (node) = (nextnode)
+  (node) = (nextnode), ((data) = NULL)
 
 /* read-only list iteration macro.
  * Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only
@@ -100,9 +100,9 @@ extern void list_add_list (struct list *, struct list *);
  * of previous macro.
  */
 #define ALL_LIST_ELEMENTS_RO(list,node,data) \
-  (node) = listhead(list)\
+  (node) = listhead(list), ((data) = NULL);\
   (node) != NULL && ((data) = listgetdata(node), 1); \
-  (node) = listnextnode(node)
+  (node) = listnextnode(node), ((data) = NULL)
 
 /* these *do not* cleanup list nodes and referenced data, as the functions
  * do - these macros simply {de,at}tach a listnode from/to a list.
index 3ce83a63aca18829a5f0399b3d2442cd7f196c5d..a03bf22a22cd09a9c3bbdbb909776772bafd665d 100644 (file)
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -83,6 +83,7 @@ do {                          \
 } while (0)
 
 /* From RFC 2104 */
-void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, caddr_t digest);
+void hmac_md5(unsigned char* text, int text_len, unsigned char* key,
+              int key_len, caddr_t digest);
 
 #endif /* ! _LIBZEBRA_MD5_H_*/
index cd39c9969dbae302b191d581edab0f98f8fa1e0b..2ded1d6c05b58fa18b3b3b8c415e15b5b159930b 100644 (file)
@@ -247,6 +247,8 @@ struct memory_list memory_list_isis[] =
   { MTYPE_ISIS_ROUTE_INFO,    "ISIS route info"                        },
   { MTYPE_ISIS_NEXTHOP,       "ISIS nexthop"                   },
   { MTYPE_ISIS_NEXTHOP6,      "ISIS nexthop6"                  },
+  { MTYPE_ISIS_DICT,          "ISIS dictionary"                        },
+  { MTYPE_ISIS_DICT_NODE,     "ISIS dictionary node"           },
   { -1, NULL },
 };
 
index 983330ffb4a3b19ac0a6e7a668aebe76b953f197..b226a25ea544ad8601979b8cfd9a35b2dbf77ae9 100644 (file)
@@ -52,7 +52,7 @@
  * using stream_put..._at() functions.
  */
 #define STREAM_WARN_OFFSETS(S) \
-  zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \
+  zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
              (S), \
              (unsigned long) (S)->size, \
              (unsigned long) (S)->getp, \
@@ -214,6 +214,20 @@ stream_set_getp (struct stream *s, size_t pos)
   s->getp = pos;
 }
 
+void
+stream_set_endp (struct stream *s, size_t pos)
+{
+  STREAM_VERIFY_SANE(s);
+
+  if (!GETP_VALID (s, pos))
+    {
+      STREAM_BOUND_WARN (s, "set endp");
+      pos = s->endp;
+    }
+
+  s->endp = pos;
+}
+
 /* Forward pointer. */
 void
 stream_forward_getp (struct stream *s, size_t size)
@@ -934,9 +948,9 @@ stream_fifo_pop (struct stream_fifo *fifo)
 
       if (fifo->head == NULL)
        fifo->tail = NULL;
-    }
 
-  fifo->count--;
+      fifo->count--;
+    }
 
   return s; 
 }
index 3e4ba7b41af27abc8ebbabfde0c15de162efa217..f10aa6d417125ea8ac77448b5e2ad2f836b6f402 100644 (file)
@@ -146,6 +146,7 @@ extern size_t stream_get_size (struct stream *);
 extern u_char *stream_get_data (struct stream *);
 
 extern void stream_set_getp (struct stream *, size_t);
+extern void stream_set_endp (struct stream *, size_t);
 extern void stream_forward_getp (struct stream *, size_t);
 extern void stream_forward_endp (struct stream *, size_t);
 
index 3521d99eee55693990bd922623f6a60fb0a654f2..61c6f73003b92f08a7d10743229ba416fa6bc535 100644 (file)
@@ -654,24 +654,8 @@ zebra_interface_add_read (struct stream *s)
   /* Lookup/create interface by name. */
   ifp = if_get_by_name_len (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ));
 
-  /* Read interface's index. */
-  ifp->ifindex = stream_getl (s);
+  zebra_interface_if_set_value (s, ifp);
 
-  /* Read interface's value. */
-  ifp->status = stream_getc (s);
-  ifp->flags = stream_getq (s);
-  ifp->metric = stream_getl (s);
-  ifp->mtu = stream_getl (s);
-  ifp->mtu6 = stream_getl (s);
-  ifp->bandwidth = stream_getl (s);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  stream_get (&ifp->sdl, s, sizeof (ifp->sdl));
-#else
-  ifp->hw_addr_len = stream_getl (s);
-  if (ifp->hw_addr_len)
-    stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
-  
   return ifp;
 }
 
@@ -699,16 +683,7 @@ zebra_interface_state_read (struct stream *s)
   if (! ifp)
      return NULL;
 
-  /* Read interface's index. */
-  ifp->ifindex = stream_getl (s);
-
-  /* Read interface's value. */
-  ifp->status = stream_getc (s);
-  ifp->flags = stream_getq (s);
-  ifp->metric = stream_getl (s);
-  ifp->mtu = stream_getl (s);
-  ifp->mtu6 = stream_getl (s);
-  ifp->bandwidth = stream_getl (s);
+  zebra_interface_if_set_value (s, ifp);
 
   return ifp;
 }
@@ -758,6 +733,13 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
   ifp->mtu = stream_getl (s);
   ifp->mtu6 = stream_getl (s);
   ifp->bandwidth = stream_getl (s);
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+  stream_get (&ifp->sdl, s, sizeof (ifp->sdl));
+#else
+  ifp->hw_addr_len = stream_getl (s);
+  if (ifp->hw_addr_len)
+    stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
 }
 
 static int
index 2872fc030914ddc6a2e5d138d92dbdede3a95559..1b85c81ed1fbd6b7dd188e57c6d3bcf0a60bbf83 100644 (file)
@@ -225,6 +225,10 @@ extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
 extern struct nexthop *nexthop_blackhole_add (struct rib *);
 extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
                                         struct in_addr *);
+extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *,
+                                                 struct in_addr *,
+                                                 struct in_addr *,
+                                                 unsigned int);
 extern void rib_lookup_and_dump (struct prefix_ipv4 *);
 extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
 extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
index f48df2bf9baa75d54efb97cda8a88f71b5d142b3..73097bf6ed27ceffd3a9c084d491b87455a04139 100644 (file)
@@ -32,6 +32,7 @@
 #include "prefix.h"
 #include "connected.h"
 #include "table.h"
+#include "memory.h"
 #include "rib.h"
 #include "thread.h"
 #include "privs.h"
@@ -426,6 +427,37 @@ netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
     }
 }
 
+/* Utility function to parse hardware link-layer address and update ifp */
+static void
+netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
+{
+  int i;
+
+  if (tb[IFLA_ADDRESS])
+    {
+      int hw_addr_len;
+
+      hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
+
+      if (hw_addr_len > INTERFACE_HWADDR_MAX)
+        zlog_warn ("Hardware address is too large: %d", hw_addr_len);
+      else
+        {
+          ifp->hw_addr_len = hw_addr_len;
+          memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
+
+          for (i = 0; i < hw_addr_len; i++)
+            if (ifp->hw_addr[i] != 0)
+              break;
+
+          if (i == hw_addr_len)
+            ifp->hw_addr_len = 0;
+          else
+            ifp->hw_addr_len = hw_addr_len;
+        }
+    }
+}
+
 /* Called from interface_lookup_netlink().  This function is only used
    during bootstrap. */
 static int
@@ -436,7 +468,6 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
   struct rtattr *tb[IFLA_MAX + 1];
   struct interface *ifp;
   char *name;
-  int i;
 
   ifi = NLMSG_DATA (h);
 
@@ -474,30 +505,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
 
   /* Hardware type and address. */
   ifp->hw_type = ifi->ifi_type;
-
-  if (tb[IFLA_ADDRESS])
-    {
-      int hw_addr_len;
-
-      hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
-
-      if (hw_addr_len > INTERFACE_HWADDR_MAX)
-        zlog_warn ("Hardware address is too large: %d", hw_addr_len);
-      else
-        {
-          ifp->hw_addr_len = hw_addr_len;
-          memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
-
-          for (i = 0; i < hw_addr_len; i++)
-            if (ifp->hw_addr[i] != 0)
-              break;
-
-          if (i == hw_addr_len)
-            ifp->hw_addr_len = 0;
-          else
-            ifp->hw_addr_len = hw_addr_len;
-        }
-    }
+  netlink_interface_update_hw_addr (tb, ifp);
 
   if_add_update (ifp);
 
@@ -709,7 +717,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
   if (tb[RTA_PREFSRC])
     src = RTA_DATA (tb[RTA_PREFSRC]);
 
-  /* Multipath treatment is needed. */
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
 
@@ -723,7 +730,64 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
       memcpy (&p.prefix, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
 
-      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0, SAFI_UNICAST);
+      if (!tb[RTA_MULTIPATH])
+          rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
+                        table, metric, 0, SAFI_UNICAST);
+      else
+        {
+          /* This is a multipath route */
+
+          struct rib *rib;
+          struct rtnexthop *rtnh =
+            (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+          len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+          rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+          rib->type = ZEBRA_ROUTE_KERNEL;
+          rib->distance = 0;
+          rib->flags = flags;
+          rib->metric = metric;
+          rib->table = table;
+          rib->nexthop_num = 0;
+          rib->uptime = time (NULL);
+
+          for (;;)
+            {
+              if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+                break;
+
+              rib->nexthop_num++;
+              index = rtnh->rtnh_ifindex;
+              gate = 0;
+              if (rtnh->rtnh_len > sizeof (*rtnh))
+                {
+                  memset (tb, 0, sizeof (tb));
+                  netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+                                        rtnh->rtnh_len - sizeof (*rtnh));
+                  if (tb[RTA_GATEWAY])
+                    gate = RTA_DATA (tb[RTA_GATEWAY]);
+                }
+
+              if (gate)
+                {
+                  if (index)
+                    nexthop_ipv4_ifindex_add (rib, gate, src, index);
+                  else
+                    nexthop_ipv4_add (rib, gate, src);
+                }
+              else
+                nexthop_ifindex_add (rib, index);
+
+              len -= NLMSG_ALIGN(rtnh->rtnh_len);
+              rtnh = RTNH_NEXT(rtnh);
+            }
+
+          if (rib->nexthop_num == 0)
+            XFREE (MTYPE_RIB, rib);
+          else
+            rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
+        }
     }
 #ifdef HAVE_IPV6
   if (rtm->rtm_family == AF_INET6)
@@ -867,7 +931,66 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
         }
 
       if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0, SAFI_UNICAST);
+        {
+          if (!tb[RTA_MULTIPATH])
+            rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
+                          metric, 0, SAFI_UNICAST);
+          else
+            {
+              /* This is a multipath route */
+
+              struct rib *rib;
+              struct rtnexthop *rtnh =
+                (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+              len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+              rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+              rib->type = ZEBRA_ROUTE_KERNEL;
+              rib->distance = 0;
+              rib->flags = 0;
+              rib->metric = metric;
+              rib->table = table;
+              rib->nexthop_num = 0;
+              rib->uptime = time (NULL);
+
+              for (;;)
+                {
+                  if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+                    break;
+
+                  rib->nexthop_num++;
+                  index = rtnh->rtnh_ifindex;
+                  gate = 0;
+                  if (rtnh->rtnh_len > sizeof (*rtnh))
+                    {
+                      memset (tb, 0, sizeof (tb));
+                      netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+                                            rtnh->rtnh_len - sizeof (*rtnh));
+                      if (tb[RTA_GATEWAY])
+                        gate = RTA_DATA (tb[RTA_GATEWAY]);
+                    }
+
+                  if (gate)
+                    {
+                      if (index)
+                        nexthop_ipv4_ifindex_add (rib, gate, src, index);
+                      else
+                        nexthop_ipv4_add (rib, gate, src);
+                    }
+                  else
+                    nexthop_ifindex_add (rib, index);
+
+                  len -= NLMSG_ALIGN(rtnh->rtnh_len);
+                  rtnh = RTNH_NEXT(rtnh);
+                }
+
+              if (rib->nexthop_num == 0)
+                XFREE (MTYPE_RIB, rib);
+              else
+                rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
+            }
+        }
       else
         rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
     }
@@ -960,6 +1083,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
           ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
           ifp->metric = 1;
 
+          netlink_interface_update_hw_addr (tb, ifp);
+
           /* If new link is added. */
           if_add_update (ifp);
         }
@@ -970,6 +1095,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
           ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
           ifp->metric = 1;
 
+          netlink_interface_update_hw_addr (tb, ifp);
+
           if (if_is_operative (ifp))
             {
               ifp->flags = ifi->ifi_flags & 0x0000fffff;
index f7f4d0a21543349216e7c20e63f84d6463127aff..2fa439c0a136202889b569217c94ef31cf6a6101 100644 (file)
@@ -232,7 +232,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
   return nexthop;
 }
 
-static struct nexthop *
+struct nexthop *
 nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, 
                           struct in_addr *src, unsigned int ifindex)
 {
@@ -1279,14 +1279,30 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)
 static void
 rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
 {
+  char buf[INET_ADDRSTRLEN];
+  assert (zebra && rn);
   
   if (IS_ZEBRA_DEBUG_RIB_Q)
+    inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN);
+
+  /* Pointless to queue a route_node with no RIB entries to add or remove */
+  if (!rn->info)
     {
-      char buf[INET6_ADDRSTRLEN];
+      zlog_debug ("%s: called for route_node (%p, %d) with no ribs",
+                  __func__, rn, rn->lock);
+      zlog_backtrace(LOG_DEBUG);
+      return;
+    }
+
+  if (IS_ZEBRA_DEBUG_RIB_Q)
+    zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen);
 
-      zlog_info ("%s: %s/%d: work queue added", __func__,
-                inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN),
-                rn->p.prefixlen);
+  assert (zebra);
+
+  if (zebra->ribq == NULL)
+    {
+      zlog_err ("%s: work_queue does not exist!", __func__);
+      return;
     }
 
   /*
@@ -1301,6 +1317,11 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
     work_queue_add (zebra->ribq, zebra->mq);
 
   rib_meta_queue_add (zebra->mq, rn);
+
+  if (IS_ZEBRA_DEBUG_RIB_Q)
+    zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn);
+
+  return;
 }
 
 /* Create new meta queue.
@@ -1328,6 +1349,8 @@ meta_queue_new (void)
 static void
 rib_queue_init (struct zebra_t *zebra)
 {
+  assert (zebra);
+  
   if (! (zebra->ribq = work_queue_new (zebra->master, 
                                        "route_node processing")))
     {
@@ -1343,7 +1366,11 @@ rib_queue_init (struct zebra_t *zebra)
   zebra->ribq->spec.hold = rib_process_hold_time;
   
   if (!(zebra->mq = meta_queue_new ()))
+  {
     zlog_err ("%s: could not initialise meta queue!", __func__);
+    return;
+  }
+  return;
 }
 
 /* RIB updates are processed via a queue of pointers to route_nodes.
@@ -2893,6 +2920,62 @@ rib_sweep_route (void)
   rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
   rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
 }
+\f
+/* Delete routes learned from a given client.  */
+/* TODO(wsun) May need to split the sweep process into multiple batches,
+ * so that the process won't take too long if the table is large. */
+static void
+rib_sweep_client_table (struct route_table *table, int rib_type)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *next;
+  int ret = 0;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = next)
+       {
+         next = rib->next;
+
+         if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+           continue;
+
+         if (rib->type == rib_type)
+            if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+             {
+                /* TODO(wsun) Is this mandatory? What about graceful restart/
+                 * non-stop forwarding */
+               ret = rib_uninstall_kernel (rn, rib);
+               if (! ret)
+                  rib_delnode (rn, rib);
+                else
+                  zlog_err ("%s: could not delete routes from kernel!",
+                            __func__);
+             }
+            else
+              {
+                /* Always delete the node. */
+                rib_delnode (rn, rib);
+              }
+       }
+}
+
+/* Sweep all routes learned from a given client from RIB tables.  */
+void
+rib_sweep_client_route (struct zserv *client)
+{
+  assert(client);
+  int route_type = client->route_type;
+  if (route_type != ZEBRA_ROUTE_MAX)
+    {
+      zlog_debug ("%s: Removing existing routes from client type %d",
+                  __func__, route_type);
+      rib_sweep_client_table (vrf_table (AFI_IP, SAFI_UNICAST, 0), route_type);
+      rib_sweep_client_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0), route_type);
+    }
+}
+\f
 
 /* Remove specific by protocol routes from 'table'. */
 static unsigned long
index 672dee881d6d02595cd4270722b9ce485e519166..b1f539d3aa1d870eb68868705a3bb934682b1cee 100644 (file)
@@ -140,6 +140,30 @@ zserv_create_header (struct stream *s, uint16_t cmd)
   stream_putw (s, cmd);
 }
 
+static void
+zserv_encode_interface (struct stream *s, struct interface *ifp)
+{
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putc (s, ifp->status);
+  stream_putq (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->mtu6);
+  stream_putl (s, ifp->bandwidth);
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+  stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
+#else
+  stream_putl (s, ifp->hw_addr_len);
+  if (ifp->hw_addr_len)
+    stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+}
+
 /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
 /*
  * This function is called in the following situations:
@@ -163,28 +187,8 @@ zsend_interface_add (struct zserv *client, struct interface *ifp)
   s = client->obuf;
   stream_reset (s);
 
-  /* Message type. */
   zserv_create_header (s, ZEBRA_INTERFACE_ADD);
-
-  /* Interface information. */
-  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
-  stream_putl (s, ifp->ifindex);
-  stream_putc (s, ifp->status);
-  stream_putq (s, ifp->flags);
-  stream_putl (s, ifp->metric);
-  stream_putl (s, ifp->mtu);
-  stream_putl (s, ifp->mtu6);
-  stream_putl (s, ifp->bandwidth);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
-#else
-  stream_putl (s, ifp->hw_addr_len);
-  if (ifp->hw_addr_len)
-    stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
-
-  /* Write packet size. */
-  stream_putw_at (s, 0, stream_get_endp (s));
+  zserv_encode_interface (s, ifp);
 
   return zebra_server_send_message(client);
 }
@@ -201,21 +205,9 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp)
 
   s = client->obuf;
   stream_reset (s);
-  
-  zserv_create_header (s, ZEBRA_INTERFACE_DELETE);
-  
-  /* Interface information. */
-  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
-  stream_putl (s, ifp->ifindex);
-  stream_putc (s, ifp->status);
-  stream_putq (s, ifp->flags);
-  stream_putl (s, ifp->metric);
-  stream_putl (s, ifp->mtu);
-  stream_putl (s, ifp->mtu6);
-  stream_putl (s, ifp->bandwidth);
 
-  /* Write packet length. */
-  stream_putw_at (s, 0, stream_get_endp (s));
+  zserv_create_header (s, ZEBRA_INTERFACE_DELETE);
+  zserv_encode_interface (s, ifp);
 
   return zebra_server_send_message (client);
 }
@@ -328,19 +320,7 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp)
   stream_reset (s);
 
   zserv_create_header (s, cmd);
-
-  /* Interface information. */
-  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
-  stream_putl (s, ifp->ifindex);
-  stream_putc (s, ifp->status);
-  stream_putq (s, ifp->flags);
-  stream_putl (s, ifp->metric);
-  stream_putl (s, ifp->mtu);
-  stream_putl (s, ifp->mtu6);
-  stream_putl (s, ifp->bandwidth);
-
-  /* Write packet size. */
-  stream_putw_at (s, 0, stream_get_endp (s));
+  zserv_encode_interface (s, ifp);
 
   return zebra_server_send_message(client);
 }
@@ -761,6 +741,13 @@ zread_ipv4_add (struct zserv *client, u_short length)
   
   /* Type, flags, message. */
   rib->type = stream_getc (s);
+  /* Update client's route type if it is not done yet. */
+  /* It is done here since only zread_ipv4/6_add() and
+   * zread_ipv4/6_delete() decode Zebra messages and retrieve
+   * route types. */
+  if (client->route_type == ZEBRA_ROUTE_MAX)
+    client->route_type = rib->type;
+
   rib->flags = stream_getc (s);
   message = stream_getc (s); 
   safi = stream_getw (s);
@@ -798,10 +785,10 @@ zread_ipv4_add (struct zserv *client, u_short length)
            case ZEBRA_NEXTHOP_IPV6:
              stream_forward_getp (s, IPV6_MAX_BYTELEN);
              break;
-      case ZEBRA_NEXTHOP_BLACKHOLE:
-        nexthop_blackhole_add (rib);
-        break;
-           }
+            case ZEBRA_NEXTHOP_BLACKHOLE:
+              nexthop_blackhole_add (rib);
+              break;
+            }
        }
     }
 
@@ -826,7 +813,7 @@ zread_ipv4_delete (struct zserv *client, u_short length)
   int i;
   struct stream *s;
   struct zapi_ipv4 api;
-  struct in_addr nexthop;
+  struct in_addr nexthop, *nexthop_p;
   unsigned long ifindex;
   struct prefix_ipv4 p;
   u_char nexthop_num;
@@ -836,6 +823,7 @@ zread_ipv4_delete (struct zserv *client, u_short length)
   s = client->ibuf;
   ifindex = 0;
   nexthop.s_addr = 0;
+  nexthop_p = NULL;
 
   /* Type, flags, message. */
   api.type = stream_getc (s);
@@ -869,6 +857,7 @@ zread_ipv4_delete (struct zserv *client, u_short length)
              break;
            case ZEBRA_NEXTHOP_IPV4:
              nexthop.s_addr = stream_get_ipv4 (s);
+             nexthop_p = &nexthop;
              break;
            case ZEBRA_NEXTHOP_IPV6:
              stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -889,7 +878,7 @@ zread_ipv4_delete (struct zserv *client, u_short length)
   else
     api.metric = 0;
     
-  rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
+  rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
                   client->rtm_table, api.safi);
   return 0;
 }
@@ -935,6 +924,11 @@ zread_ipv6_add (struct zserv *client, u_short length)
 
   /* Type, flags, message. */
   api.type = stream_getc (s);
+  /* Update the route type of the client. 
+   * Same as in zread_ipv4_add(). */
+  if (client->route_type == ZEBRA_ROUTE_MAX)
+    client->route_type = api.type;
+
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
   api.safi = stream_getw (s);
@@ -1133,6 +1127,14 @@ zebra_score_rib (int client_sock)
 static void
 zebra_client_close (struct zserv *client)
 {
+  struct stream *s;
+
+  /* Sweep all routes learned from the client first. */
+  rib_sweep_client_route(client);
+  /* Reset the route type. It may not be necessary since the
+   * whole client will be freed. */
+  client->route_type = ZEBRA_ROUTE_MAX;
+
   /* Close file descriptor. */
   if (client->sock)
     {
@@ -1172,6 +1174,9 @@ zebra_client_create (int sock)
 
   /* Make client input/output buffer. */
   client->sock = sock;
+  /* Set the default route type to ZEBRA_ROUTE_MAX; it will be updated
+   * once new routes are received. */
+  client->route_type = ZEBRA_ROUTE_MAX;
   client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
   client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
   client->wb = buffer_new(0);
index 5e8bccac31247b2146066f499c4d13b8d4086720..3d7ebbcd85da9b1ee885cc486c4853b3b692775e 100644 (file)
@@ -38,6 +38,10 @@ struct zserv
   /* Client file descriptor. */
   int sock;
 
+  /* Client route type. */
+  /* Assuming each client contains only one type of route. */
+  int route_type;
+
   /* Input/output buffer to the client. */
   struct stream *ibuf;
   struct stream *obuf;