diff options
| -rw-r--r-- | isisd/AUTHORS | 7 | ||||
| -rw-r--r-- | isisd/isis_adjacency.c | 98 | ||||
| -rw-r--r-- | isisd/isis_adjacency.h | 3 | ||||
| -rw-r--r-- | isisd/isis_circuit.c | 10 | ||||
| -rw-r--r-- | isisd/isis_events.c | 47 | ||||
| -rw-r--r-- | isisd/isis_lsp.c | 42 | ||||
| -rw-r--r-- | isisd/isis_pdu.c | 138 | ||||
| -rw-r--r-- | isisd/isis_pdu.h | 6 | ||||
| -rw-r--r-- | isisd/isis_route.c | 18 | ||||
| -rw-r--r-- | isisd/isis_route.h | 2 | ||||
| -rw-r--r-- | isisd/isis_spf.c | 84 | ||||
| -rw-r--r-- | isisd/isis_spf.h | 3 | ||||
| -rw-r--r-- | isisd/isisd.c | 105 | 
13 files changed, 348 insertions, 215 deletions
diff --git a/isisd/AUTHORS b/isisd/AUTHORS index d9f98b22aa..05fc0a5073 100644 --- a/isisd/AUTHORS +++ b/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> diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 10bce3e8ab..468b0a69c6 100644 --- a/isisd/isis_adjacency.c +++ b/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); +        }        }      } diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 04a9250592..caa3107db2 100644 --- a/isisd/isis_adjacency.h +++ b/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 */ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index cb439e8774..c09c3a2826 100644 --- a/isisd/isis_circuit.c +++ b/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); diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 750a4c3847..3887b7c5a2 100644 --- a/isisd/isis_events.c +++ b/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)  	{ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index f71794323e..5c1e9931dc 100644 --- a/isisd/isis_lsp.c +++ b/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); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index fe943bbaa8..497fad20fd 100644 --- a/isisd/isis_pdu.c +++ b/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) diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h index 9e215535e4..3eca731938 100644 --- a/isisd/isis_pdu.h +++ b/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   * +-------+-------+-------+-------+-------+-------+-------+-------+ diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 96d8df8fa1..c99d95831e 100644 --- a/isisd/isis_route.c +++ b/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!", diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 1312400c86..5adea2293b 100644 --- a/isisd/isis_route.h +++ b/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;  }; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index a91742b62a..198104a98d 100644 --- a/isisd/isis_spf.c +++ b/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;  } diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index f31b510569..aa543b705d 100644 --- a/isisd/isis_spf.h +++ b/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); diff --git a/isisd/isisd.c b/isisd/isisd.c index 6cbb85b1b6..e8e3d9f0ad 100644 --- a/isisd/isisd.c +++ b/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++;  | 
