isisd: couple of bug fixes

This commit is contained in:
Subbaiah Venkata 2012-03-27 23:48:05 -07:00 committed by Avneesh Sachdev
parent 3f045a0881
commit e38e0df01a
13 changed files with 349 additions and 216 deletions

View file

@ -1,3 +1,4 @@
Sampo Saaristo <sambo@cs.tut.fi>
Ofer Wald <ofersf@islands.co.il>
Hannes Gredler <hannes@gredler.at>
Subbaiah Venkata <svenkata@google.com>

View file

@ -240,9 +240,13 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state
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])

View file

@ -44,6 +44,7 @@ enum isis_system_type
enum isis_adj_state
{
ISIS_ADJ_UNKNOWN,
ISIS_ADJ_INITIALIZING,
ISIS_ADJ_UP,
ISIS_ADJ_DOWN
@ -83,8 +84,10 @@ struct isis_adjacency
struct list *area_addrs; /* areaAdressesOfNeighbour */
struct nlpids nlpids; /* protocols spoken ... */
struct list *ipv4_addrs;
struct in_addr router_address;
#ifdef HAVE_IPV6
struct list *ipv6_addrs;
struct in6_addr router_address6;
#endif /* HAVE_IPV6 */
u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */
int circuit_t; /* from hello PDU hdr */

View file

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

View file

@ -130,11 +130,8 @@ 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)
@ -143,7 +140,6 @@ isis_event_system_type_change (struct isis_area *area, int newtype)
if (area->route_table6[1] == NULL)
area->route_table6[1] = route_table_init ();
#endif /* HAVE_IPV6 */
}
break;
case IS_LEVEL_1_AND_2:
@ -155,11 +151,8 @@ 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)
@ -168,8 +161,8 @@ isis_event_system_type_change (struct isis_area *area, int newtype)
if (area->route_table6[0] == NULL)
area->route_table6[0] = route_table_init ();
#endif /* HAVE_IPV6 */
}
break;
default:
break;
}
@ -199,6 +192,7 @@ circuit_commence_level (struct isis_circuit *circuit, int level)
{
if (level == 1)
{
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));
@ -217,6 +211,7 @@ circuit_commence_level (struct isis_circuit *circuit, int level)
}
else
{
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));

View file

@ -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;
@ -505,8 +516,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
{
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));
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);

View file

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

View file

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

View file

@ -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,7 +276,7 @@ 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,
isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth,
struct list *adjacencies)
{
struct isis_route_info *rinfo;
@ -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!",

View file

@ -30,6 +30,7 @@ struct isis_nexthop6
{
unsigned int ifindex;
struct in6_addr ip6;
struct in6_addr router_address6;
unsigned int lock;
};
#endif /* HAVE_IPV6 */
@ -38,6 +39,7 @@ struct isis_nexthop
{
unsigned int ifindex;
struct in_addr ip;
struct in_addr router_address;
unsigned int lock;
};

View file

@ -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;
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);
area->min_spf_interval[0] - diff);
else
THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_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, area->min_spf_interval[level-1] - diff);
spftree->pending = 1;
}
else
{
retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
}
return retval;
}

View file

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

View file

@ -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,33 +2035,21 @@ ALIAS (no_lsp_gen_interval_l2,
"Set interval for level 2 only\n"
"Minimum interval in seconds\n")
DEFUN (metric_style,
metric_style_cmd,
"metric-style (narrow|transition|wide)",
"Use old-style (ISO 10589) or new-style packet formats\n"
"Use old style of TLVs with narrow metric\n"
"Send and accept both styles of TLVs during transition\n"
"Use new style of TLVs to carry wider metric\n")
static int
validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
{
struct isis_area *area;
struct isis_circuit *circuit;
struct listnode *node;
area = vty->index;
assert (area);
if (! vty)
return CMD_ERR_AMBIGUOUS;
if (strncmp (argv[0], "w", 1) == 0)
if (! area)
{
area->newmetric = 1;
area->oldmetric = 0;
vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
else if (strncmp (argv[0], "t", 1) == 0)
{
area->newmetric = 1;
area->oldmetric = 1;
}
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) &&
@ -2079,6 +2069,40 @@ DEFUN (metric_style,
return CMD_ERR_AMBIGUOUS;
}
}
return CMD_SUCCESS;
}
DEFUN (metric_style,
metric_style_cmd,
"metric-style (narrow|transition|wide)",
"Use old-style (ISO 10589) or new-style packet formats\n"
"Use old style of TLVs with narrow metric\n"
"Send and accept both styles of TLVs during transition\n"
"Use new style of TLVs to carry wider metric\n")
{
struct isis_area *area;
int ret;
area = vty->index;
assert (area);
if (strncmp (argv[0], "w", 1) == 0)
{
area->newmetric = 1;
area->oldmetric = 0;
}
else if (strncmp (argv[0], "t", 1) == 0)
{
area->newmetric = 1;
area->oldmetric = 1;
}
else if (strncmp (argv[0], "n", 1) == 0)
{
ret = validate_metric_style_narrow (vty, area);
if (ret != CMD_SUCCESS)
return ret;
area->newmetric = 0;
area->oldmetric = 1;
}
@ -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++;