isisd: couple of bug fixes
diff --git a/isisd/AUTHORS b/isisd/AUTHORS
index d9f98b2..05fc0a5 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 10bce3e..468b0a6 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -220,29 +220,33 @@
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 @@
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 04a9250..caa3107 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -44,6 +44,7 @@
enum isis_adj_state
{
+ ISIS_ADJ_UNKNOWN,
ISIS_ADJ_INITIALIZING,
ISIS_ADJ_UP,
ISIS_ADJ_DOWN
@@ -83,8 +84,10 @@
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 cb439e8..c09c3a2 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -2720,6 +2720,15 @@
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 @@
/* 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 750a4c3..3887b7c 100644
--- a/isisd/isis_events.c
+++ b/isisd/isis_events.c
@@ -130,20 +130,16 @@
{
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 @@
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 @@
{
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 @@
}
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 f717943..5c1e993 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -441,6 +441,19 @@
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 @@
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 @@
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 @@
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_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_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->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_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 = 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 @@
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 fe943bb..497fad2 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 @@
{
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 @@
"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 @@
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 @@
* Get the header
*/
hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
- stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
+ pdu_len = ntohs (hdr->pdu_len);
- /* 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); */
-
- 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 @@
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 @@
" 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 @@
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 @@
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 @@
/* 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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 9e21553..3eca731 100644
--- a/isisd/isis_pdu.h
+++ b/isisd/isis_pdu.h
@@ -114,7 +114,7 @@
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Holding Time | 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
- * | PDU Lenght | 2
+ * | PDU Length | 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | R | Priority | 1
* +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -142,7 +142,7 @@
* +-------+-------+-------+-------+-------+-------+-------+-------+
* + Holding Time + 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
- * + PDU Lenght + 2
+ * + PDU Length + 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Local Circuit ID | 1
* +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -202,7 +202,7 @@
/*
* 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 96d8df8..c99d958 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -244,6 +244,7 @@
{
nh = isis_nexthop_create (ipv4_addr,
adj->circuit->interface->ifindex);
+ nh->router_address = adj->router_address;
listnode_add (nexthops, nh);
}
}
@@ -267,6 +268,7 @@
{
nh6 = isis_nexthop6_create (ipv6_addr,
adj->circuit->interface->ifindex);
+ nh6->router_address6 = adj->router_address6;
listnode_add (nexthops6, nh6);
}
}
@@ -274,8 +276,8 @@
#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 @@
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 @@
/* 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 @@
/* 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 @@
/* 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 1312400..5adea22 100644
--- a/isisd/isis_route.h
+++ b/isisd/isis_route.h
@@ -30,6 +30,7 @@
{
unsigned int ifindex;
struct in6_addr ip6;
+ struct in6_addr router_address6;
unsigned int lock;
};
#endif /* HAVE_IPV6 */
@@ -38,6 +39,7 @@
{
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 a91742b..198104a 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -274,7 +274,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
{
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;
- else
- diff = now - spftree->lastrun;
+ /* 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 (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);
-
- spftree->pending = 1;
- }
+ if (level == 1)
+ THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+ area->min_spf_interval[0] - diff);
else
- {
- retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
- }
+ THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+ 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, area->min_spf_interval[level-1] - diff);
+
+ spftree->pending = 1;
return retval;
}
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index f31b510..aa543b7 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -68,8 +68,9 @@
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 6cbb85b..e8e3d9f 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -720,7 +720,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
"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 @@
"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 @@
}
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 @@
"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 @@
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++;