From e38e0df01ad305ad48ecf816b52fa99fd3f2a4e1 Mon Sep 17 00:00:00 2001 From: Subbaiah Venkata Date: Tue, 27 Mar 2012 23:48:05 -0700 Subject: isisd: couple of bug fixes --- isisd/AUTHORS | 7 +-- isisd/isis_adjacency.c | 98 ++++++++++++++++++----------------- isisd/isis_adjacency.h | 3 ++ isisd/isis_circuit.c | 10 ++++ isisd/isis_events.c | 47 ++++++++--------- isisd/isis_lsp.c | 42 +++++++++------ isisd/isis_pdu.c | 138 +++++++++++++++++++++++++++++++++---------------- isisd/isis_pdu.h | 6 +-- isisd/isis_route.c | 18 +++++-- isisd/isis_route.h | 2 + isisd/isis_spf.c | 84 ++++++++++++++++++------------ isisd/isis_spf.h | 3 +- isisd/isisd.c | 105 +++++++++++++++++++++++-------------- 13 files changed, 348 insertions(+), 215 deletions(-) diff --git a/isisd/AUTHORS b/isisd/AUTHORS index d9f98b22..05fc0a50 100644 --- a/isisd/AUTHORS +++ b/isisd/AUTHORS @@ -1,3 +1,4 @@ -Sampo Saaristo -Ofer Wald -Hannes Gredler +Sampo Saaristo +Ofer Wald +Hannes Gredler +Subbaiah Venkata diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 10bce3e8..468b0a69 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 04a92505..caa3107d 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 cb439e87..c09c3a28 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 750a4c38..3887b7c5 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 f7179432..5c1e9931 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 fe943bba..497fad20 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,23 +440,26 @@ 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 */ @@ -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 9e215535..3eca7319 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 96d8df8f..c99d9583 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 1312400c..5adea229 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 a91742b6..198104a9 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 f31b5105..aa543b70 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 6cbb85b1..e8e3d9f0 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++; -- cgit v1.2.1