Browse Source

isisd: couple of bug fixes

Subbaiah Venkata 7 years ago
parent
commit
e38e0df01a
13 changed files with 348 additions and 215 deletions
  1. 4 3
      isisd/AUTHORS
  2. 51 47
      isisd/isis_adjacency.c
  3. 3 0
      isisd/isis_adjacency.h
  4. 10 0
      isisd/isis_circuit.c
  5. 21 26
      isisd/isis_events.c
  6. 26 16
      isisd/isis_lsp.c
  7. 94 44
      isisd/isis_pdu.c
  8. 3 3
      isisd/isis_pdu.h
  9. 13 5
      isisd/isis_route.c
  10. 2 0
      isisd/isis_route.h
  11. 52 32
      isisd/isis_spf.c
  12. 2 1
      isisd/isis_spf.h
  13. 67 38
      isisd/isisd.c

+ 4 - 3
isisd/AUTHORS

@@ -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>

+ 51 - 47
isisd/isis_adjacency.c

@@ -220,29 +220,33 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state
         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++;
-	  }
+        {
+          circuit->upadjcount[level - 1]++;
+          isis_event_adjacency_state_change (adj, new_state);
+          /* update counter & timers for debugging purposes */
+          adj->last_flap = time (NULL);
+          adj->flaps++;
+        }
         else if (new_state == ISIS_ADJ_DOWN)
-	  {
-	    listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
-	    circuit->upadjcount[level - 1]--;
-	    if (circuit->upadjcount[level - 1] == 0)
-	      {
-		/* Clean lsp_queue when no adj is up. */
-		if (circuit->lsp_queue)
-		  list_delete_all_node (circuit->lsp_queue);
-	      }
-	    isis_event_adjacency_state_change (adj, new_state);
-	    isis_delete_adj (adj);
-	  }
-        list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
-        isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
-                                   circuit->u.bc.lan_neighs[level - 1]);
+        {
+          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])
@@ -256,35 +260,35 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state
         if ((adj->level & level) == 0)
           continue;
         if (new_state == ISIS_ADJ_UP)
-	  {
-	    circuit->upadjcount[level - 1]++;
-	    isis_event_adjacency_state_change (adj, new_state);
+        {
+          circuit->upadjcount[level - 1]++;
+          isis_event_adjacency_state_change (adj, new_state);
 
-	    if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
-	      send_hello (circuit, level);
+          if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
+            send_hello (circuit, level);
 
-	    /* update counter & timers for debugging purposes */
-	    adj->last_flap = time (NULL);
-	    adj->flaps++;
+          /* 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);
-	  }
+          /* 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);
-	  }
+        {
+          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);
+        }
       }
     }
 

+ 3 - 0
isisd/isis_adjacency.h

@@ -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 */

+ 10 - 0
isisd/isis_circuit.c

@@ -2720,6 +2720,15 @@ isis_if_new_hook (struct interface *ifp)
 int
 isis_if_delete_hook (struct interface *ifp)
 {
+  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;
 }
 
@@ -2734,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);

+ 21 - 26
isisd/isis_events.c

@@ -130,20 +130,16 @@ isis_event_system_type_change (struct isis_area *area, int newtype)
   {
     case IS_LEVEL_1:
       if (newtype == IS_LEVEL_2)
-      {
         area_resign_level (area, IS_LEVEL_1);
-      }
-      else
-      {
-        if (area->lspdb[1] == NULL)
-          area->lspdb[1] = lsp_db_init ();
-        if (area->route_table[1] == NULL)
-          area->route_table[1] = route_table_init ();
+
+      if (area->lspdb[1] == NULL)
+        area->lspdb[1] = lsp_db_init ();
+      if (area->route_table[1] == NULL)
+        area->route_table[1] = route_table_init ();
 #ifdef HAVE_IPV6
-        if (area->route_table6[1] == NULL)
-          area->route_table6[1] = route_table_init ();
+      if (area->route_table6[1] == NULL)
+        area->route_table6[1] = route_table_init ();
 #endif /* HAVE_IPV6 */
-      }
       break;
 
     case IS_LEVEL_1_AND_2:
@@ -155,21 +151,18 @@ isis_event_system_type_change (struct isis_area *area, int newtype)
 
     case IS_LEVEL_2:
       if (newtype == IS_LEVEL_1)
-      {
         area_resign_level (area, IS_LEVEL_2);
-      }
-      else
-      {
-        if (area->lspdb[0] == NULL)
-          area->lspdb[0] = lsp_db_init ();
-        if (area->route_table[0] == NULL)
-          area->route_table[0] = route_table_init ();
+
+      if (area->lspdb[0] == NULL)
+        area->lspdb[0] = lsp_db_init ();
+      if (area->route_table[0] == NULL)
+        area->route_table[0] = route_table_init ();
 #ifdef HAVE_IPV6
-        if (area->route_table6[0] == NULL)
-          area->route_table6[0] = route_table_init ();
+      if (area->route_table6[0] == NULL)
+        area->route_table6[0] = route_table_init ();
 #endif /* HAVE_IPV6 */
-      }
       break;
+
     default:
       break;
   }
@@ -199,8 +192,9 @@ 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)
 	{
@@ -217,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)
 	{

+ 26 - 16
isisd/isis_lsp.c

@@ -441,6 +441,19 @@ lsp_seqnum_update (struct isis_lsp *lsp0)
   return;
 }
 
+static u_int8_t
+lsp_bits_generate (int level, int overload_bit)
+{
+  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, int level)
@@ -470,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;
@@ -503,10 +514,9 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
 
   if ((found & TLVFLAG_DYN_HOSTNAME) && (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;
@@ -1125,7 +1135,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
       return lsp;
     }
   lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
-                 area->is_type | area->overload_bit, 0, level);
+                 lsp_bits_generate (level, area->overload_bit), 0, level);
   lsp->area = area;
   lsp->own_lsp = 1;
   lsp_insert (lsp, area->lspdb[level - 1]);
@@ -1644,7 +1654,7 @@ lsp_regenerate (struct isis_area *area, int level)
 
   lsp_clear_data (lsp);
   lsp_build (lsp, area);
-  lsp->lsp_header->lsp_bits = area->is_type | area->overload_bit;
+  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);
@@ -1653,7 +1663,8 @@ lsp_regenerate (struct isis_area *area, int level)
   lsp_set_all_srmflags (lsp);
   for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
     {
-      frag->lsp_header->lsp_bits = area->is_type | area->overload_bit;
+      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.
        */
@@ -1803,10 +1814,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
 
   lsp->level = level;
   /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-  if (level == IS_LEVEL_1)
-    lsp->lsp_header->lsp_bits |= IS_LEVEL_1;
-  else
-    lsp->lsp_header->lsp_bits |= IS_LEVEL_2;
+  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0);
 
   /*
    * add self to IS neighbours 
@@ -2002,7 +2010,7 @@ lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
   lsp_build_pseudo (lsp, circuit, level);
 
   /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-  lsp->lsp_header->lsp_bits = circuit->area->is_type;
+  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);
@@ -2321,7 +2329,8 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
    */
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
   lsp->area = area;
-  lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;
+  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);
@@ -2404,7 +2413,8 @@ top_lsp_refresh (struct thread *thread)
   isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
 		     IS_LEVEL_1);
 
-  lsp->lsp_header->lsp_bits = lsp->area->is_type | lsp->area->overload_bit;
+  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);
 

+ 94 - 44
isisd/isis_pdu.c

@@ -62,7 +62,7 @@
 #endif /* PNBBY */
 
 /* Utility mask array. */
-static const u_char maskbit[] = {
+static u_char maskbit[] = {
   0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
 };
 
@@ -225,16 +225,16 @@ lsp_authentication_check (struct stream *stream, struct isis_area *area,
 {
   struct isis_link_state_hdr *hdr;
   uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
-  uint16_t checksum, rem_lifetime;
+  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,
-                       ntohs (hdr->pdu_len) - ISIS_FIXED_HDR_LEN -
-                       ISIS_LSP_HDR_LEN,
+                       pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
                        &expected, &found, &tlvs, &auth_tlv_offset);
 
   if (retval != ISIS_OK)
@@ -243,7 +243,7 @@ lsp_authentication_check (struct stream *stream, struct isis_area *area,
                 "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), ntohs (hdr->pdu_len));
+                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));
@@ -397,6 +397,7 @@ process_p2p_hello (struct isis_circuit *circuit)
   struct isis_p2p_hello_hdr *hdr;
   struct isis_adjacency *adj;
   u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
+  uint16_t pdu_len;
   struct tlvs tlvs;
 
   if (isis->debugs & DEBUG_ADJ_PACKETS)
@@ -439,24 +440,27 @@ process_p2p_hello (struct isis_circuit *circuit)
    * Get the header
    */
   hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
-  stream_forward_getp (circuit->rcv_stream, 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);
 
-  if (ntohs (hdr->pdu_len) > ISO_MTU(circuit))
+  if (pdu_len > ISO_MTU(circuit) ||
+      pdu_len > stream_get_endp (circuit->rcv_stream))
     {
       zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
                  "invalid pdu length %d",
-                 circuit->area->area_tag, circuit->interface->name,
-                 ntohs (hdr->pdu_len));
+                 circuit->area->area_tag, circuit->interface->name, 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);
+
+  stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
+
+  /*
    * Lets get the TLVS now
    */
   expected |= TLVFLAG_AREA_ADDRS;
@@ -468,9 +472,8 @@ process_p2p_hello (struct isis_circuit *circuit)
   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,
-                       &auth_tlv_offset);
+		       pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
+                       &expected, &found, &tlvs, &auth_tlv_offset);
 
   if (retval > ISIS_WARNING)
     {
@@ -821,7 +824,7 @@ process_p2p_hello (struct isis_circuit *circuit)
 		  " cir id %02d, length %d",
 		  circuit->area->area_tag, circuit->interface->name,
 		  circuit_t2string (circuit->is_type),
-		  circuit->circuit_id, ntohs (hdr->pdu_len));
+		  circuit->circuit_id, pdu_len);
     }
 
   free_tlvs (&tlvs);
@@ -906,15 +909,23 @@ 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.pdu_len > ISO_MTU(circuit))
+  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);
-      hdr.pdu_len = stream_get_endp (circuit->rcv_stream);
+      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 &&
@@ -1167,6 +1178,7 @@ 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)
     {
@@ -1187,6 +1199,26 @@ 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)
     {
@@ -1198,24 +1230,25 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 		  ntohl (hdr->seq_num),
 		  ntohs (hdr->checksum),
 		  ntohs (hdr->rem_lifetime),
-		  ntohs (hdr->pdu_len),
+		  pdu_len,
 		  circuit->interface->name);
     }
 
-  if (ntohs (hdr->pdu_len) <= ISIS_LSP_HDR_LEN ||
-      ntohs (hdr->pdu_len)  > ISO_MTU(circuit))
+  /* 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 length %d",
+      zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
 		  circuit->area->area_tag,
-		  rawlspid_print (hdr->lsp_id), ntohs (hdr->pdu_len));
-
-      return ISIS_WARNING;
+		  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,
@@ -1403,17 +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_inc_seqnum (lsp, ntohl (hdr->seq_num));
-          lsp_set_all_srmflags (lsp);
 	  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));
 	}
+      /* If the received LSP is older or equal,
+       * resend the LSP which will act as ACK */
+      lsp_set_all_srmflags (lsp);
     }
   else
     {
@@ -1440,7 +1475,7 @@ dontcheckadj:
 	  if (!lsp)
             {
 	      lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
-                                             ntohs (hdr->pdu_len), lsp0,
+                                             pdu_len, lsp0,
                                              circuit->area, level);
               lsp_insert (lsp, circuit->area->lspdb[level - 1]);
             }
@@ -1489,7 +1524,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   int retval = ISIS_OK;
   int cmp, own_lsp;
   char typechar = ' ';
-  unsigned int len;
+  uint16_t pdu_len;
   struct isis_adjacency *adj;
   struct isis_complete_seqnum_hdr *chdr = NULL;
   struct isis_partial_seqnum_hdr *phdr = NULL;
@@ -1508,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 || len > ISO_MTU(circuit))
+      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 %d", len);
-	  return ISIS_OK;
+	  zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
+	  return ISIS_WARNING;
 	}
     }
   else
@@ -1521,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 || len > ISO_MTU(circuit))
+      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 %d", len);
-	  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)
     {
@@ -1617,7 +1663,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
   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,
+		       pdu_len - stream_get_getp (circuit->rcv_stream),
 		       &expected, &found, &tlvs, &auth_tlv_offset);
 
   if (retval > ISIS_WARNING)
@@ -2585,6 +2631,7 @@ max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
   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;
 }
 
 /*
@@ -2862,6 +2909,9 @@ send_psnp (int level, struct isis_circuit *circuit)
       dict_count (circuit->area->lspdb[level - 1]) == 0)
     return ISIS_OK;
 
+  if (! circuit->snd_stream)
+    return ISIS_ERROR;
+
   num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
 
   while (1)

+ 3 - 3
isisd/isis_pdu.h

@@ -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
  * +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -202,7 +202,7 @@ struct isis_link_state_hdr
 /*
  *      L1 and L2 IS to IS complete sequence numbers PDU header
  * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        PDU Lenght                             + 2    
+ * +                        PDU Length                             + 2    
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  * +                        Source ID                              + id_len + 1
  * +-------+-------+-------+-------+-------+-------+-------+-------+

+ 13 - 5
isisd/isis_route.c

@@ -244,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);
 	}
     }
@@ -267,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);
 	}
     }
@@ -274,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;
@@ -288,7 +290,7 @@ 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))
@@ -296,11 +298,14 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
           /* 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))
@@ -308,6 +313,9 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
           /* 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);
         }
     }
@@ -415,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!",

+ 2 - 0
isisd/isis_route.h

@@ -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,6 +39,7 @@ struct isis_nexthop
 {
   unsigned int ifindex;
   struct in_addr ip;
+  struct in_addr router_address;
   unsigned int lock;
 };
 

+ 52 - 32
isisd/isis_spf.c

@@ -274,7 +274,8 @@ isis_spftree_new (struct isis_area *area)
   tree->tents = list_new ();
   tree->paths = list_new ();
   tree->area = area;
-  tree->lastrun = 0;
+  tree->last_run_timestamp = 0;
+  tree->last_run_duration = 0;
   tree->runcount = 0;
   tree->pending = 0;
   return tree;
@@ -408,12 +409,16 @@ spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
 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;
-  return (lsp_search (lspid, area->lspdb[level - 1]));
+  lsp = lsp_search (lspid, area->lspdb[level - 1]);
+  if (lsp && lsp->lsp_header->rem_lifetime != 0)
+    return lsp;
+  return NULL;
 }
 
 /*
@@ -1021,7 +1026,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
 		  LSP_PSEUDO_ID (lsp_id) = 0;
 		  LSP_FRAGMENT (lsp_id) = 0;
 		  lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
-		  if (!lsp)
+                  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,
@@ -1171,6 +1176,13 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
   struct isis_lsp *lsp;
   struct route_table *table = NULL;
+  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];
@@ -1237,7 +1249,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 	  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))
 		{
@@ -1263,9 +1275,14 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 
 out:
   isis_route_validate (area);
-  spftree->lastrun = time (NULL);
-  spftree->runcount++;
   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;
 }
@@ -1332,7 +1349,7 @@ isis_spf_schedule (struct isis_area *area, int level)
 {
   struct isis_spftree *spftree = area->spftree[level - 1];
   time_t now = time (NULL);
-  int diff = now - spftree->lastrun;
+  int diff = now - spftree->last_run_timestamp;
 
   assert (diff >= 0);
   assert (area->is_type & level);
@@ -1346,20 +1363,20 @@ isis_spf_schedule (struct isis_area *area, int level)
 
   THREAD_TIMER_OFF (spftree->t_spf);
 
-  /* wait MINIMUM_SPF_INTERVAL before doing the SPF */
-  if (diff >= MINIMUM_SPF_INTERVAL)
+  /* 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);
 
   if (level == 1)
     THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
-                     MINIMUM_SPF_INTERVAL - diff);
+                     area->min_spf_interval[0] - diff);
   else
     THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
-                     MINIMUM_SPF_INTERVAL - diff);
+                     area->min_spf_interval[1] - diff);
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
     zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
-                area->area_tag, level, MINIMUM_SPF_INTERVAL - diff);
+                area->area_tag, level, area->min_spf_interval[level-1] - diff);
 
   spftree->pending = 1;
 
@@ -1428,34 +1445,37 @@ 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;
+
+  assert (diff >= 0);
+  assert (area->is_type & level);
+
+  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);
 
   if (spftree->pending)
-    return retval;
+    return ISIS_OK;
 
   THREAD_TIMER_OFF (spftree->t_spf);
 
-  /* FIXME: let's wait MINIMUM_SPF_INTERVAL before doing the SPF */
-  if (now - isis->uptime < MINIMUM_SPF_INTERVAL || isis->uptime == 0)
-      diff = 0;
+  /* 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);
+
+  if (level == 1)
+    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+                     area->min_spf_interval[0] - diff);
   else
-      diff = now - spftree->lastrun;
+    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+                     area->min_spf_interval[1] - diff);
 
-  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);
+  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;
-    }
-  else
-    {
-      retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
-    }
+  spftree->pending = 1;
 
   return retval;
 }

+ 2 - 1
isisd/isis_spf.h

@@ -68,8 +68,9 @@ struct isis_spftree
   struct list *tents;		/* TENT */
   struct isis_area *area;       /* back pointer to area */
   int pending;			/* already scheduled */
-  time_t lastrun;		/* for scheduling */
   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);

+ 67 - 38
isisd/isisd.c

@@ -720,7 +720,7 @@ DEFUN (clear_isis_neighbor,
 
 DEFUN (clear_isis_neighbor_arg,
        clear_isis_neighbor_arg_cmd,
-       "claer isis neighbor WORD",
+       "clear isis neighbor WORD",
        CLEAR_STR
        "ISIS network information\n"
        "ISIS neighbor adjacencies\n"
@@ -1273,10 +1273,13 @@ DEFUN (show_isis_summary,
       vty_out (vty, "      minimum interval  : %d%s",
           area->min_spf_interval[level - 1], VTY_NEWLINE);
 
-      vty_out (vty, "      last run          : ");
-      vty_out_timestr(vty, spftree->lastrun);
+      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);
 
@@ -1290,10 +1293,13 @@ DEFUN (show_isis_summary,
       vty_out (vty, "      minimum interval  : %d%s",
           area->min_spf_interval[level - 1], VTY_NEWLINE);
 
-      vty_out (vty, "      last run          : ");
-      vty_out_timestr(vty, spftree->lastrun);
+      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
@@ -1329,7 +1335,7 @@ show_isis_database (struct vty *vty, const char *argv, int ui_level)
   struct isis_dynhn *dynhn;
   const char *pos = argv;
   u_char lspid[ISIS_SYS_ID_LEN+2];
-  char sysid[15]; /* len of xxxx.xxxx.xxxx + place for #0 termination */
+  char sysid[255];
   u_char number[3];
   int level, lsp_count;
 
@@ -1337,13 +1343,7 @@ show_isis_database (struct vty *vty, const char *argv, int ui_level)
     return CMD_SUCCESS;
 
   memset (&lspid, 0, ISIS_SYS_ID_LEN);
-  memset (&sysid, 0, 15);
-
-  if (argv)
-    {
-      strncpy (sysid, argv, 15);
-      sysid[14] = '\0';
-    }
+  memset (&sysid, 0, 255);
 
   /*
    * extract fragment and pseudo id from the string argv
@@ -1354,6 +1354,8 @@ show_isis_database (struct vty *vty, const char *argv, int ui_level)
    * 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;
@@ -2033,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)",
@@ -2042,8 +2082,7 @@ DEFUN (metric_style,
        "Use new style of TLVs to carry wider metric\n")
 {
   struct isis_area *area;
-  struct isis_circuit *circuit;
-  struct listnode *node;
+  int ret;
 
   area = vty->index;
   assert (area);
@@ -2060,25 +2099,10 @@ DEFUN (metric_style,
     }
   else if (strncmp (argv[0], "n", 1) == 0)
     {
-      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;
-            }
-        }
+      ret = validate_metric_style_narrow (vty, area);
+      if (ret != CMD_SUCCESS)
+        return ret;
+
       area->newmetric = 0;
       area->oldmetric = 1;
     }
@@ -2093,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;
@@ -2819,11 +2848,11 @@ isis_config_write (struct vty *vty)
 	    vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE);
 	    write++;
 	  }
-	/* ISIS - Metric-Style - when true displays narrow */
-	if (area->oldmetric)
+	/* ISIS - Metric-Style - when true displays wide */
+	if (area->newmetric)
 	  {
-	    if (!area->newmetric)
-	      vty_out (vty, " metric-style narrow%s", VTY_NEWLINE);
+	    if (!area->oldmetric)
+	      vty_out (vty, " metric-style wide%s", VTY_NEWLINE);
 	    else
 	      vty_out (vty, " metric-style transition%s", VTY_NEWLINE);
 	    write++;