2 * IS-IS Rout(e)ing protocol - isis_lsp.c
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 #include "isisd/dict.h"
42 #include "isisd/isis_constants.h"
43 #include "isisd/isis_common.h"
44 #include "isisd/isis_flags.h"
45 #include "isisd/isis_circuit.h"
46 #include "isisd/isisd.h"
47 #include "isisd/isis_tlv.h"
48 #include "isisd/isis_lsp.h"
49 #include "isisd/isis_pdu.h"
50 #include "isisd/isis_dynhn.h"
51 #include "isisd/isis_misc.h"
52 #include "isisd/isis_csm.h"
53 #include "isisd/isis_adjacency.h"
54 #include "isisd/isis_spf.h"
55 #include "isisd/isis_te.h"
57 /* staticly assigned vars for printing purposes */
58 char lsp_bits_string
[200]; /* FIXME: enough ? */
60 static int lsp_l1_refresh (struct thread
*thread
);
61 static int lsp_l2_refresh (struct thread
*thread
);
62 static int lsp_l1_refresh_pseudo (struct thread
*thread
);
63 static int lsp_l2_refresh_pseudo (struct thread
*thread
);
66 lsp_id_cmp (u_char
* id1
, u_char
* id2
)
68 return memcmp (id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
76 dict
= dict_create (DICTCOUNT_T_MAX
, (dict_comp_t
) lsp_id_cmp
);
82 lsp_search (u_char
* id
, dict_t
* lspdb
)
89 zlog_debug ("searching db");
90 for (dn
= dict_first (lspdb
); dn
; dn
= dict_next (lspdb
, dn
))
92 zlog_debug ("%s\t%pX", rawlspid_print ((u_char
*) dnode_getkey (dn
)),
95 #endif /* EXTREME DEBUG */
97 node
= dict_lookup (lspdb
, id
);
100 return (struct isis_lsp
*) dnode_get (node
);
106 lsp_clear_data (struct isis_lsp
*lsp
)
111 if (lsp
->tlv_data
.hostname
)
112 isis_dynhn_remove (lsp
->lsp_header
->lsp_id
);
116 if (lsp
->tlv_data
.nlpids
)
117 XFREE (MTYPE_ISIS_TLV
, lsp
->tlv_data
.nlpids
);
118 if (lsp
->tlv_data
.hostname
)
119 XFREE (MTYPE_ISIS_TLV
, lsp
->tlv_data
.hostname
);
120 if (lsp
->tlv_data
.router_id
)
121 XFREE (MTYPE_ISIS_TLV
, lsp
->tlv_data
.router_id
);
124 free_tlvs (&lsp
->tlv_data
);
128 lsp_destroy (struct isis_lsp
*lsp
)
130 struct listnode
*cnode
, *lnode
, *lnnode
;
131 struct isis_lsp
*lsp_in_list
;
132 struct isis_circuit
*circuit
;
137 if (lsp
->area
->circuit_list
) {
138 for (ALL_LIST_ELEMENTS_RO (lsp
->area
->circuit_list
, cnode
, circuit
))
140 if (circuit
->lsp_queue
== NULL
)
142 for (ALL_LIST_ELEMENTS (circuit
->lsp_queue
, lnode
, lnnode
, lsp_in_list
))
143 if (lsp_in_list
== lsp
)
144 list_delete_node(circuit
->lsp_queue
, lnode
);
147 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
);
148 ISIS_FLAGS_CLEAR_ALL (lsp
->SRMflags
);
150 lsp_clear_data (lsp
);
152 if (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) == 0 && lsp
->lspu
.frags
)
154 list_delete (lsp
->lspu
.frags
);
155 lsp
->lspu
.frags
= NULL
;
158 isis_spf_schedule (lsp
->area
, lsp
->level
);
160 isis_spf_schedule6 (lsp
->area
, lsp
->level
);
164 stream_free (lsp
->pdu
);
165 XFREE (MTYPE_ISIS_LSP
, lsp
);
169 lsp_db_destroy (dict_t
* lspdb
)
171 dnode_t
*dnode
, *next
;
172 struct isis_lsp
*lsp
;
174 dnode
= dict_first (lspdb
);
177 next
= dict_next (lspdb
, dnode
);
178 lsp
= dnode_get (dnode
);
180 dict_delete_free (lspdb
, dnode
);
190 * Remove all the frags belonging to the given lsp
193 lsp_remove_frags (struct list
*frags
, dict_t
* lspdb
)
196 struct listnode
*lnode
, *lnnode
;
197 struct isis_lsp
*lsp
;
199 for (ALL_LIST_ELEMENTS (frags
, lnode
, lnnode
, lsp
))
201 dnode
= dict_lookup (lspdb
, lsp
->lsp_header
->lsp_id
);
203 dnode_destroy (dict_delete (lspdb
, dnode
));
206 list_delete_all_node (frags
);
212 lsp_search_and_destroy (u_char
* id
, dict_t
* lspdb
)
215 struct isis_lsp
*lsp
;
217 node
= dict_lookup (lspdb
, id
);
220 node
= dict_delete (lspdb
, node
);
221 lsp
= dnode_get (node
);
223 * If this is a zero lsp, remove all the frags now
225 if (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) == 0)
228 lsp_remove_frags (lsp
->lspu
.frags
, lspdb
);
233 * else just remove this frag, from the zero lsps' frag list
235 if (lsp
->lspu
.zero_lsp
&& lsp
->lspu
.zero_lsp
->lspu
.frags
)
236 listnode_delete (lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
239 dnode_destroy (node
);
244 * Compares a LSP to given values
245 * Params are given in net order
248 lsp_compare (char *areatag
, struct isis_lsp
*lsp
, u_int32_t seq_num
,
249 u_int16_t checksum
, u_int16_t rem_lifetime
)
251 /* no point in double ntohl on seqnum */
252 if (lsp
->lsp_header
->seq_num
== seq_num
&&
253 lsp
->lsp_header
->checksum
== checksum
&&
254 /*comparing with 0, no need to do ntohl */
255 ((lsp
->lsp_header
->rem_lifetime
== 0 && rem_lifetime
== 0) ||
256 (lsp
->lsp_header
->rem_lifetime
!= 0 && rem_lifetime
!= 0)))
258 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
260 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
263 rawlspid_print (lsp
->lsp_header
->lsp_id
),
264 ntohl (lsp
->lsp_header
->seq_num
),
265 ntohs (lsp
->lsp_header
->checksum
),
266 ntohs (lsp
->lsp_header
->rem_lifetime
));
267 zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
268 " cksum 0x%04x, lifetime %us",
270 ntohl (seq_num
), ntohs (checksum
), ntohs (rem_lifetime
));
276 * LSPs with identical checksums should only be treated as newer if:
277 * a) The current LSP has a remaining lifetime != 0 and the other LSP has a
278 * remaining lifetime == 0. In this case, we should participate in the purge
279 * and should not treat the current LSP with remaining lifetime == 0 as older.
280 * b) The LSP has an incorrect checksum. In this case, we need to react as given
283 if (ntohl (seq_num
) > ntohl (lsp
->lsp_header
->seq_num
)
284 || (ntohl(seq_num
) == ntohl(lsp
->lsp_header
->seq_num
)
285 && ( (lsp
->lsp_header
->rem_lifetime
!= 0
286 && rem_lifetime
== 0)
287 || lsp
->lsp_header
->checksum
!= checksum
)))
289 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
291 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
294 rawlspid_print (lsp
->lsp_header
->lsp_id
),
295 ntohl (seq_num
), ntohs (checksum
), ntohs (rem_lifetime
));
296 zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
297 "cksum 0x%04x, lifetime %us",
299 ntohl (lsp
->lsp_header
->seq_num
),
300 ntohs (lsp
->lsp_header
->checksum
),
301 ntohs (lsp
->lsp_header
->rem_lifetime
));
305 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
308 ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
309 areatag
, rawlspid_print (lsp
->lsp_header
->lsp_id
), ntohl (seq_num
),
310 ntohs (checksum
), ntohs (rem_lifetime
));
311 zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
312 " cksum 0x%04x, lifetime %us", areatag
,
313 ntohl (lsp
->lsp_header
->seq_num
),
314 ntohs (lsp
->lsp_header
->checksum
),
315 ntohs (lsp
->lsp_header
->rem_lifetime
));
322 lsp_auth_add (struct isis_lsp
*lsp
)
324 struct isis_passwd
*passwd
;
325 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
328 * Add the authentication info if its present
330 (lsp
->level
== IS_LEVEL_1
) ? (passwd
= &lsp
->area
->area_passwd
) :
331 (passwd
= &lsp
->area
->domain_passwd
);
332 switch (passwd
->type
)
335 case ISIS_PASSWD_TYPE_CLEARTXT
:
336 memcpy (&lsp
->tlv_data
.auth_info
, passwd
, sizeof (struct isis_passwd
));
337 tlv_add_authinfo (passwd
->type
, passwd
->len
, passwd
->passwd
, lsp
->pdu
);
341 case ISIS_PASSWD_TYPE_HMAC_MD5
:
342 /* Remember where TLV is written so we can later
343 * overwrite the MD5 hash */
344 lsp
->auth_tlv_offset
= stream_get_endp (lsp
->pdu
);
345 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
346 lsp
->tlv_data
.auth_info
.type
= ISIS_PASSWD_TYPE_HMAC_MD5
;
347 lsp
->tlv_data
.auth_info
.len
= ISIS_AUTH_MD5_SIZE
;
348 memcpy (&lsp
->tlv_data
.auth_info
.passwd
, hmac_md5_hash
,
350 tlv_add_authinfo (passwd
->type
, ISIS_AUTH_MD5_SIZE
, hmac_md5_hash
,
360 lsp_auth_update (struct isis_lsp
*lsp
)
362 struct isis_passwd
*passwd
;
363 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
364 uint16_t checksum
, rem_lifetime
;
366 /* For HMAC MD5 we need to recompute the md5 hash and store it */
367 (lsp
->level
== IS_LEVEL_1
) ? (passwd
= &lsp
->area
->area_passwd
) :
368 (passwd
= &lsp
->area
->domain_passwd
);
369 if (passwd
->type
!= ISIS_PASSWD_TYPE_HMAC_MD5
)
373 * In transient conditions (when net is configured where authentication
374 * config and lsp regenerate schedule is not yet run), there could be
375 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
376 * return, when lsp_regenerate is run, lsp will have auth tlv.
378 if (lsp
->auth_tlv_offset
== 0)
382 * RFC 5304 set auth value, checksum and remaining lifetime to zero
383 * before computation and reset to old values after computation.
385 checksum
= lsp
->lsp_header
->checksum
;
386 rem_lifetime
= lsp
->lsp_header
->rem_lifetime
;
387 lsp
->lsp_header
->checksum
= 0;
388 lsp
->lsp_header
->rem_lifetime
= 0;
389 /* Set the authentication value as well to zero */
390 memset (STREAM_DATA (lsp
->pdu
) + lsp
->auth_tlv_offset
+ 3,
391 0, ISIS_AUTH_MD5_SIZE
);
392 /* Compute autentication value */
393 hmac_md5 (STREAM_DATA (lsp
->pdu
), stream_get_endp(lsp
->pdu
),
394 (unsigned char *) &passwd
->passwd
, passwd
->len
,
395 (unsigned char *) &hmac_md5_hash
);
396 /* Copy the hash into the stream */
397 memcpy (STREAM_DATA (lsp
->pdu
) + lsp
->auth_tlv_offset
+ 3,
398 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
399 memcpy (&lsp
->tlv_data
.auth_info
.passwd
, hmac_md5_hash
,
401 /* Copy back the checksum and remaining lifetime */
402 lsp
->lsp_header
->checksum
= checksum
;
403 lsp
->lsp_header
->rem_lifetime
= rem_lifetime
;
407 lsp_inc_seqnum (struct isis_lsp
*lsp
, u_int32_t seq_num
)
411 if (seq_num
== 0 || ntohl (lsp
->lsp_header
->seq_num
) > seq_num
)
412 newseq
= ntohl (lsp
->lsp_header
->seq_num
) + 1;
414 newseq
= seq_num
+ 1;
416 lsp
->lsp_header
->seq_num
= htonl (newseq
);
418 /* Recompute authentication and checksum information */
419 lsp_auth_update (lsp
);
420 /* ISO 10589 - 7.3.11 Generation of the checksum
421 * The checksum shall be computed over all fields in the LSP which appear
422 * after the Remaining Lifetime field. This field (and those appearing
423 * before it) are excluded so that the LSP may be aged by systems without
424 * requiring recomputation.
426 fletcher_checksum(STREAM_DATA (lsp
->pdu
) + 12,
427 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
429 isis_spf_schedule (lsp
->area
, lsp
->level
);
431 isis_spf_schedule6 (lsp
->area
, lsp
->level
);
438 * Genetates checksum for LSP and its frags
441 lsp_seqnum_update (struct isis_lsp
*lsp0
)
443 struct isis_lsp
*lsp
;
444 struct listnode
*node
;
446 lsp_inc_seqnum (lsp0
, 0);
448 if (!lsp0
->lspu
.frags
)
451 for (ALL_LIST_ELEMENTS_RO (lsp0
->lspu
.frags
, node
, lsp
))
452 lsp_inc_seqnum (lsp
, 0);
458 lsp_bits_generate (int level
, int overload_bit
, int attached_bit
)
460 u_int8_t lsp_bits
= 0;
461 if (level
== IS_LEVEL_1
)
462 lsp_bits
= IS_LEVEL_1
;
464 lsp_bits
= IS_LEVEL_1_AND_2
;
466 lsp_bits
|= overload_bit
;
468 lsp_bits
|= attached_bit
;
473 lsp_update_data (struct isis_lsp
*lsp
, struct stream
*stream
,
474 struct isis_area
*area
, int level
)
476 uint32_t expected
= 0, found
;
479 /* free the old lsp data */
480 lsp_clear_data (lsp
);
482 /* copying only the relevant part of our stream */
483 if (lsp
->pdu
!= NULL
)
484 stream_free (lsp
->pdu
);
485 lsp
->pdu
= stream_dup (stream
);
487 /* setting pointers to the correct place */
488 lsp
->isis_header
= (struct isis_fixed_hdr
*) (STREAM_DATA (lsp
->pdu
));
489 lsp
->lsp_header
= (struct isis_link_state_hdr
*) (STREAM_DATA (lsp
->pdu
) +
493 lsp
->age_out
= ZERO_AGE_LIFETIME
;
494 lsp
->installed
= time (NULL
);
496 * Get LSP data i.e. TLVs
498 expected
|= TLVFLAG_AUTH_INFO
;
499 expected
|= TLVFLAG_AREA_ADDRS
;
500 expected
|= TLVFLAG_IS_NEIGHS
;
501 expected
|= TLVFLAG_NLPID
;
502 if (area
->dynhostname
)
503 expected
|= TLVFLAG_DYN_HOSTNAME
;
506 expected
|= TLVFLAG_TE_IS_NEIGHS
;
507 expected
|= TLVFLAG_TE_IPV4_REACHABILITY
;
508 expected
|= TLVFLAG_TE_ROUTER_ID
;
510 expected
|= TLVFLAG_IPV4_ADDR
;
511 expected
|= TLVFLAG_IPV4_INT_REACHABILITY
;
512 expected
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
514 expected
|= TLVFLAG_IPV6_ADDR
;
515 expected
|= TLVFLAG_IPV6_REACHABILITY
;
516 #endif /* HAVE_IPV6 */
518 retval
= parse_tlvs (area
->area_tag
, STREAM_DATA (lsp
->pdu
) +
519 ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
,
520 ntohs (lsp
->lsp_header
->pdu_len
) -
521 ISIS_FIXED_HDR_LEN
- ISIS_LSP_HDR_LEN
,
522 &expected
, &found
, &lsp
->tlv_data
,
524 if (retval
!= ISIS_OK
)
526 zlog_warn ("Could not parse LSP");
530 if ((found
& TLVFLAG_DYN_HOSTNAME
) && (area
->dynhostname
))
532 isis_dynhn_insert (lsp
->lsp_header
->lsp_id
, lsp
->tlv_data
.hostname
,
533 (lsp
->lsp_header
->lsp_bits
& LSPBIT_IST
) ==
534 IS_LEVEL_1_AND_2
? IS_LEVEL_2
: IS_LEVEL_1
);
541 lsp_update (struct isis_lsp
*lsp
, struct stream
*stream
,
542 struct isis_area
*area
, int level
)
544 dnode_t
*dnode
= NULL
;
546 /* Remove old LSP from database. This is required since the
547 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
548 * and will update it with the new data in the stream. */
549 dnode
= dict_lookup (area
->lspdb
[level
- 1], lsp
->lsp_header
->lsp_id
);
551 dnode_destroy (dict_delete (area
->lspdb
[level
- 1], dnode
));
555 zlog_err("ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
556 area
->area_tag
, rawlspid_print(lsp
->lsp_header
->lsp_id
));
561 /* rebuild the lsp data */
562 lsp_update_data (lsp
, stream
, area
, level
);
564 /* insert the lsp back into the database */
565 lsp_insert (lsp
, area
->lspdb
[level
- 1]);
568 /* creation of LSP directly from what we received */
570 lsp_new_from_stream_ptr (struct stream
*stream
,
571 u_int16_t pdu_len
, struct isis_lsp
*lsp0
,
572 struct isis_area
*area
, int level
)
574 struct isis_lsp
*lsp
;
576 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
577 lsp_update_data (lsp
, stream
, area
, level
);
582 * zero lsp -> create the list for fragments
584 lsp
->lspu
.frags
= list_new ();
589 * a fragment -> set the backpointer and add this to zero lsps frag list
591 lsp
->lspu
.zero_lsp
= lsp0
;
592 listnode_add (lsp0
->lspu
.frags
, lsp
);
599 lsp_new(struct isis_area
*area
, u_char
* lsp_id
,
600 u_int16_t rem_lifetime
, u_int32_t seq_num
,
601 u_int8_t lsp_bits
, u_int16_t checksum
, int level
)
603 struct isis_lsp
*lsp
;
605 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
608 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
609 if (LSP_FRAGMENT (lsp_id
) == 0)
610 lsp
->lspu
.frags
= list_new ();
611 lsp
->isis_header
= (struct isis_fixed_hdr
*) (STREAM_DATA (lsp
->pdu
));
612 lsp
->lsp_header
= (struct isis_link_state_hdr
*)
613 (STREAM_DATA (lsp
->pdu
) + ISIS_FIXED_HDR_LEN
);
615 /* at first we fill the FIXED HEADER */
616 (level
== IS_LEVEL_1
) ? fill_fixed_hdr (lsp
->isis_header
, L1_LINK_STATE
) :
617 fill_fixed_hdr (lsp
->isis_header
, L2_LINK_STATE
);
619 /* now for the LSP HEADER */
620 /* Minimal LSP PDU size */
621 lsp
->lsp_header
->pdu_len
= htons (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
622 memcpy (lsp
->lsp_header
->lsp_id
, lsp_id
, ISIS_SYS_ID_LEN
+ 2);
623 lsp
->lsp_header
->checksum
= checksum
; /* Provided in network order */
624 lsp
->lsp_header
->seq_num
= htonl (seq_num
);
625 lsp
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
626 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
628 lsp
->age_out
= ZERO_AGE_LIFETIME
;
630 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
632 if (isis
->debugs
& DEBUG_EVENTS
)
633 zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
634 sysid_print (lsp_id
), LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
),
635 LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
),
636 ntohl (lsp
->lsp_header
->pdu_len
),
637 ntohl (lsp
->lsp_header
->seq_num
));
643 lsp_insert (struct isis_lsp
*lsp
, dict_t
* lspdb
)
645 dict_alloc_insert (lspdb
, lsp
->lsp_header
->lsp_id
, lsp
);
646 if (lsp
->lsp_header
->seq_num
!= 0)
648 isis_spf_schedule (lsp
->area
, lsp
->level
);
650 isis_spf_schedule6 (lsp
->area
, lsp
->level
);
656 * Build a list of LSPs with non-zero ht bounded by start and stop ids
659 lsp_build_list_nonzero_ht (u_char
* start_id
, u_char
* stop_id
,
660 struct list
*list
, dict_t
* lspdb
)
662 dnode_t
*first
, *last
, *curr
;
664 first
= dict_lower_bound (lspdb
, start_id
);
668 last
= dict_upper_bound (lspdb
, stop_id
);
672 if (((struct isis_lsp
*) (curr
->dict_data
))->lsp_header
->rem_lifetime
)
673 listnode_add (list
, first
->dict_data
);
677 curr
= dict_next (lspdb
, curr
);
679 ((struct isis_lsp
*) (curr
->dict_data
))->lsp_header
->rem_lifetime
)
680 listnode_add (list
, curr
->dict_data
);
689 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
692 lsp_build_list (u_char
* start_id
, u_char
* stop_id
, u_char num_lsps
,
693 struct list
*list
, dict_t
* lspdb
)
696 dnode_t
*first
, *last
, *curr
;
698 first
= dict_lower_bound (lspdb
, start_id
);
702 last
= dict_upper_bound (lspdb
, stop_id
);
706 listnode_add (list
, first
->dict_data
);
711 curr
= dict_next (lspdb
, curr
);
714 listnode_add (list
, curr
->dict_data
);
717 if (count
== num_lsps
|| curr
== last
)
725 * Build a list of LSPs with SSN flag set for the given circuit
728 lsp_build_list_ssn (struct isis_circuit
*circuit
, u_char num_lsps
,
729 struct list
*list
, dict_t
* lspdb
)
731 dnode_t
*dnode
, *next
;
732 struct isis_lsp
*lsp
;
735 dnode
= dict_first (lspdb
);
736 while (dnode
!= NULL
)
738 next
= dict_next (lspdb
, dnode
);
739 lsp
= dnode_get (dnode
);
740 if (ISIS_CHECK_FLAG (lsp
->SSNflags
, circuit
))
742 listnode_add (list
, lsp
);
745 if (count
== num_lsps
)
754 lsp_set_time (struct isis_lsp
*lsp
)
758 if (lsp
->lsp_header
->rem_lifetime
== 0)
760 if (lsp
->age_out
> 0)
765 lsp
->lsp_header
->rem_lifetime
=
766 htons (ntohs (lsp
->lsp_header
->rem_lifetime
) - 1);
770 lspid_print (u_char
* lsp_id
, u_char
* trg
, char dynhost
, char frag
)
772 struct isis_dynhn
*dyn
= NULL
;
773 u_char id
[SYSID_STRLEN
];
776 dyn
= dynhn_find_by_id (lsp_id
);
781 sprintf ((char *)id
, "%.14s", dyn
->name
.name
);
782 else if (!memcmp (isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
783 sprintf ((char *)id
, "%.14s", unix_hostname ());
785 memcpy (id
, sysid_print (lsp_id
), 15);
787 sprintf ((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID (lsp_id
),
788 LSP_FRAGMENT (lsp_id
));
790 sprintf ((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID (lsp_id
));
793 /* Convert the lsp attribute bits to attribute string */
795 lsp_bits2string (u_char
* lsp_bits
)
797 char *pos
= lsp_bits_string
;
802 /* we only focus on the default metric */
803 pos
+= sprintf (pos
, "%d/",
804 ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits
) ? 1 : 0);
806 pos
+= sprintf (pos
, "%d/",
807 ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits
) ? 1 : 0);
809 pos
+= sprintf (pos
, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits
) ? 1 : 0);
813 return lsp_bits_string
;
816 /* this function prints the lsp on show isis database */
818 lsp_print (struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
823 lspid_print (lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
824 vty_out (vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
825 vty_out (vty
, "%5u ", ntohs (lsp
->lsp_header
->pdu_len
));
826 vty_out (vty
, "0x%08x ", ntohl (lsp
->lsp_header
->seq_num
));
827 vty_out (vty
, "0x%04x ", ntohs (lsp
->lsp_header
->checksum
));
828 if (ntohs (lsp
->lsp_header
->rem_lifetime
) == 0)
830 snprintf (age_out
, 8, "(%u)", lsp
->age_out
);
832 vty_out (vty
, "%7s ", age_out
);
835 vty_out (vty
, " %5u ", ntohs (lsp
->lsp_header
->rem_lifetime
));
836 vty_out (vty
, "%s%s",
837 lsp_bits2string (&lsp
->lsp_header
->lsp_bits
), VTY_NEWLINE
);
841 lsp_print_detail (struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
843 struct area_addr
*area_addr
;
845 struct listnode
*lnode
;
846 struct is_neigh
*is_neigh
;
847 struct te_is_neigh
*te_is_neigh
;
848 struct ipv4_reachability
*ipv4_reach
;
849 struct in_addr
*ipv4_addr
;
850 struct te_ipv4_reachability
*te_ipv4_reach
;
852 struct ipv6_reachability
*ipv6_reach
;
857 u_char hostname
[255];
858 u_char ipv4_reach_prefix
[20];
859 u_char ipv4_reach_mask
[20];
860 u_char ipv4_address
[20];
862 lspid_print (lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
863 lsp_print (lsp
, vty
, dynhost
);
865 /* for all area address */
866 if (lsp
->tlv_data
.area_addrs
)
867 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.area_addrs
, lnode
, area_addr
))
869 vty_out (vty
, " Area Address: %s%s",
870 isonet_print (area_addr
->area_addr
, area_addr
->addr_len
),
874 /* for the nlpid tlv */
875 if (lsp
->tlv_data
.nlpids
)
877 for (i
= 0; i
< lsp
->tlv_data
.nlpids
->count
; i
++)
879 switch (lsp
->tlv_data
.nlpids
->nlpids
[i
])
883 vty_out (vty
, " NLPID : 0x%X%s",
884 lsp
->tlv_data
.nlpids
->nlpids
[i
], VTY_NEWLINE
);
887 vty_out (vty
, " NLPID : %s%s", "unknown", VTY_NEWLINE
);
893 /* for the hostname tlv */
894 if (lsp
->tlv_data
.hostname
)
896 bzero (hostname
, sizeof (hostname
));
897 memcpy (hostname
, lsp
->tlv_data
.hostname
->name
,
898 lsp
->tlv_data
.hostname
->namelen
);
899 vty_out (vty
, " Hostname : %s%s", hostname
, VTY_NEWLINE
);
902 /* authentication tlv */
903 if (lsp
->tlv_data
.auth_info
.type
!= ISIS_PASSWD_TYPE_UNUSED
)
905 if (lsp
->tlv_data
.auth_info
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
906 vty_out (vty
, " Auth type : md5%s", VTY_NEWLINE
);
907 else if (lsp
->tlv_data
.auth_info
.type
== ISIS_PASSWD_TYPE_CLEARTXT
)
908 vty_out (vty
, " Auth type : clear text%s", VTY_NEWLINE
);
912 if (lsp
->tlv_data
.router_id
)
914 memcpy (ipv4_address
, inet_ntoa (lsp
->tlv_data
.router_id
->id
),
915 sizeof (ipv4_address
));
916 vty_out (vty
, " Router ID : %s%s", ipv4_address
, VTY_NEWLINE
);
919 if (lsp
->tlv_data
.ipv4_addrs
)
920 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_addrs
, lnode
, ipv4_addr
))
922 memcpy (ipv4_address
, inet_ntoa (*ipv4_addr
), sizeof (ipv4_address
));
923 vty_out (vty
, " IPv4 Address: %s%s", ipv4_address
, VTY_NEWLINE
);
926 /* for the IS neighbor tlv */
927 if (lsp
->tlv_data
.is_neighs
)
928 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.is_neighs
, lnode
, is_neigh
))
930 lspid_print (is_neigh
->neigh_id
, LSPid
, dynhost
, 0);
931 vty_out (vty
, " Metric : %-8d IS : %s%s",
932 is_neigh
->metrics
.metric_default
, LSPid
, VTY_NEWLINE
);
935 /* for the internal reachable tlv */
936 if (lsp
->tlv_data
.ipv4_int_reachs
)
937 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_int_reachs
, lnode
,
940 memcpy (ipv4_reach_prefix
, inet_ntoa (ipv4_reach
->prefix
),
941 sizeof (ipv4_reach_prefix
));
942 memcpy (ipv4_reach_mask
, inet_ntoa (ipv4_reach
->mask
),
943 sizeof (ipv4_reach_mask
));
944 vty_out (vty
, " Metric : %-8d IPv4-Internal : %s %s%s",
945 ipv4_reach
->metrics
.metric_default
, ipv4_reach_prefix
,
946 ipv4_reach_mask
, VTY_NEWLINE
);
949 /* for the external reachable tlv */
950 if (lsp
->tlv_data
.ipv4_ext_reachs
)
951 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_ext_reachs
, lnode
,
954 memcpy (ipv4_reach_prefix
, inet_ntoa (ipv4_reach
->prefix
),
955 sizeof (ipv4_reach_prefix
));
956 memcpy (ipv4_reach_mask
, inet_ntoa (ipv4_reach
->mask
),
957 sizeof (ipv4_reach_mask
));
958 vty_out (vty
, " Metric : %-8d IPv4-External : %s %s%s",
959 ipv4_reach
->metrics
.metric_default
, ipv4_reach_prefix
,
960 ipv4_reach_mask
, VTY_NEWLINE
);
965 if (lsp
->tlv_data
.ipv6_reachs
)
966 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv6_reachs
, lnode
, ipv6_reach
))
968 memset (&in6
, 0, sizeof (in6
));
969 memcpy (in6
.s6_addr
, ipv6_reach
->prefix
,
970 PSIZE (ipv6_reach
->prefix_len
));
971 inet_ntop (AF_INET6
, &in6
, (char *)buff
, BUFSIZ
);
972 if ((ipv6_reach
->control_info
&
973 CTRL_INFO_DISTRIBUTION
) == DISTRIBUTION_INTERNAL
)
974 vty_out (vty
, " Metric : %-8d IPv6-Internal : %s/%d%s",
975 ntohl (ipv6_reach
->metric
),
976 buff
, ipv6_reach
->prefix_len
, VTY_NEWLINE
);
978 vty_out (vty
, " Metric : %-8d IPv6-External : %s/%d%s",
979 ntohl (ipv6_reach
->metric
),
980 buff
, ipv6_reach
->prefix_len
, VTY_NEWLINE
);
984 /* TE IS neighbor tlv */
985 if (lsp
->tlv_data
.te_is_neighs
)
986 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_is_neighs
, lnode
, te_is_neigh
))
988 lspid_print (te_is_neigh
->neigh_id
, LSPid
, dynhost
, 0);
989 vty_out (vty
, " Metric : %-8d IS-Extended : %s%s",
990 GET_TE_METRIC(te_is_neigh
), LSPid
, VTY_NEWLINE
);
991 if (IS_MPLS_TE(isisMplsTE
))
992 mpls_te_print_detail(vty
, te_is_neigh
);
996 if (lsp
->tlv_data
.te_ipv4_reachs
)
997 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_ipv4_reachs
, lnode
,
1000 /* FIXME: There should be better way to output this stuff. */
1001 vty_out (vty
, " Metric : %-8d IPv4-Extended : %s/%d%s",
1002 ntohl (te_ipv4_reach
->te_metric
),
1003 inet_ntoa (newprefix2inaddr (&te_ipv4_reach
->prefix_start
,
1004 te_ipv4_reach
->control
)),
1005 te_ipv4_reach
->control
& 0x3F, VTY_NEWLINE
);
1007 vty_out (vty
, "%s", VTY_NEWLINE
);
1012 /* print all the lsps info in the local lspdb */
1014 lsp_print_all (struct vty
*vty
, dict_t
* lspdb
, char detail
, char dynhost
)
1017 dnode_t
*node
= dict_first (lspdb
), *next
;
1020 if (detail
== ISIS_UI_LEVEL_BRIEF
)
1022 while (node
!= NULL
)
1024 /* I think it is unnecessary, so I comment it out */
1025 /* dict_contains (lspdb, node); */
1026 next
= dict_next (lspdb
, node
);
1027 lsp_print (dnode_get (node
), vty
, dynhost
);
1032 else if (detail
== ISIS_UI_LEVEL_DETAIL
)
1034 while (node
!= NULL
)
1036 next
= dict_next (lspdb
, node
);
1037 lsp_print_detail (dnode_get (node
), vty
, dynhost
);
1046 #define FRAG_THOLD(S,T) \
1047 ((STREAM_SIZE(S)*T)/100)
1049 /* stream*, area->lsp_frag_threshold, increment */
1050 #define FRAG_NEEDED(S,T,I) \
1051 (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
1053 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1054 * variable length (TE TLVs, sub TLVs). */
1056 lsp_tlv_fit (struct isis_lsp
*lsp
, struct list
**from
, struct list
**to
,
1057 int tlvsize
, int frag_thold
,
1058 int tlv_build_func (struct list
*, struct stream
*))
1062 /* can we fit all ? */
1063 if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, listcount (*from
) * tlvsize
+ 2))
1065 tlv_build_func (*from
, lsp
->pdu
);
1066 if (listcount (*to
) != 0)
1068 struct listnode
*node
, *nextnode
;
1071 for (ALL_LIST_ELEMENTS (*from
, node
, nextnode
, elem
))
1073 listnode_add (*to
, elem
);
1074 list_delete_node (*from
, node
);
1084 else if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, tlvsize
+ 2))
1086 /* fit all we can */
1087 count
= FRAG_THOLD (lsp
->pdu
, frag_thold
) - 2 -
1088 (STREAM_SIZE (lsp
->pdu
) - STREAM_REMAIN (lsp
->pdu
));
1089 count
= count
/ tlvsize
;
1090 if (count
> (int)listcount (*from
))
1091 count
= listcount (*from
);
1092 for (i
= 0; i
< count
; i
++)
1094 listnode_add (*to
, listgetdata (listhead (*from
)));
1095 listnode_delete (*from
, listgetdata (listhead (*from
)));
1097 tlv_build_func (*to
, lsp
->pdu
);
1099 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1103 /* Process IS_NEIGHBOURS TLV with TE subTLVs */
1105 lsp_te_tlv_fit (struct isis_lsp
*lsp
, struct list
**from
, struct list
**to
, int frag_thold
)
1107 int count
, size
= 0;
1108 struct listnode
*node
, *nextnode
;
1109 struct te_is_neigh
*elem
;
1111 /* Start computing real size of TLVs */
1112 for (ALL_LIST_ELEMENTS (*from
, node
, nextnode
, elem
))
1113 size
= size
+ elem
->sub_tlvs_length
+ IS_NEIGHBOURS_LEN
;
1115 /* can we fit all ? */
1116 if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, size
))
1118 tlv_add_te_is_neighs (*from
, lsp
->pdu
);
1119 if (listcount (*to
) != 0)
1121 for (ALL_LIST_ELEMENTS (*from
, node
, nextnode
, elem
))
1123 listnode_add (*to
, elem
);
1124 list_delete_node (*from
, node
);
1136 /* fit all we can */
1137 /* Compute remaining place in LSP PDU */
1138 count
= FRAG_THOLD (lsp
->pdu
, frag_thold
) - 2 -
1139 (STREAM_SIZE (lsp
->pdu
) - STREAM_REMAIN (lsp
->pdu
));
1140 /* Determine size of TE SubTLVs */
1141 elem
= (struct te_is_neigh
*)listgetdata ((struct listnode
*)listhead (*from
));
1142 count
= count
- elem
->sub_tlvs_length
- IS_NEIGHBOURS_LEN
;
1147 listnode_add (*to
, listgetdata ((struct listnode
*)listhead (*from
)));
1148 listnode_delete (*from
, listgetdata ((struct listnode
*)listhead (*from
)));
1150 elem
= (struct te_is_neigh
*)listgetdata ((struct listnode
*)listhead (*from
));
1151 count
= count
- elem
->sub_tlvs_length
- IS_NEIGHBOURS_LEN
;
1154 tlv_add_te_is_neighs (*to
, lsp
->pdu
);
1157 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1162 lsp_rem_lifetime (struct isis_area
*area
, int level
)
1164 u_int16_t rem_lifetime
;
1166 /* Add jitter to configured LSP lifetime */
1167 rem_lifetime
= isis_jitter (area
->max_lsp_lifetime
[level
- 1],
1170 /* No jitter if the max refresh will be less than configure gen interval */
1171 /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at
1173 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
1174 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
1176 return rem_lifetime
;
1180 lsp_refresh_time (struct isis_lsp
*lsp
, u_int16_t rem_lifetime
)
1182 struct isis_area
*area
= lsp
->area
;
1183 int level
= lsp
->level
;
1184 u_int16_t refresh_time
;
1186 /* Add jitter to LSP refresh time */
1187 refresh_time
= isis_jitter (area
->lsp_refresh
[level
- 1],
1188 MAX_LSP_GEN_JITTER
);
1190 /* RFC 4444 : make sure the refresh time is at least less than 300
1191 * of the remaining lifetime and more than gen interval */
1192 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1] ||
1193 refresh_time
> (rem_lifetime
- 300))
1194 refresh_time
= rem_lifetime
- 300;
1196 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1197 * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
1199 return refresh_time
;
1202 static struct isis_lsp
*
1203 lsp_next_frag (u_char frag_num
, struct isis_lsp
*lsp0
, struct isis_area
*area
,
1206 struct isis_lsp
*lsp
;
1207 u_char frag_id
[ISIS_SYS_ID_LEN
+ 2];
1209 memcpy (frag_id
, lsp0
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1210 LSP_FRAGMENT (frag_id
) = frag_num
;
1211 /* FIXME add authentication TLV for fragment LSPs */
1212 lsp
= lsp_search (frag_id
, area
->lspdb
[level
- 1]);
1215 /* Clear the TLVs */
1216 lsp_clear_data (lsp
);
1219 lsp
= lsp_new (area
, frag_id
, ntohs(lsp0
->lsp_header
->rem_lifetime
), 0,
1220 lsp_bits_generate (level
, area
->overload_bit
,
1221 area
->attached_bit
), 0, level
);
1224 lsp_insert (lsp
, area
->lspdb
[level
- 1]);
1225 listnode_add (lsp0
->lspu
.frags
, lsp
);
1226 lsp
->lspu
.zero_lsp
= lsp0
;
1231 lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
, struct isis_area
*area
,
1232 struct tlvs
*tlv_data
)
1234 struct route_table
*er_table
;
1235 struct route_node
*rn
;
1236 struct prefix_ipv4
*ipv4
;
1237 struct isis_ext_info
*info
;
1238 struct ipv4_reachability
*ipreach
;
1239 struct te_ipv4_reachability
*te_ipreach
;
1241 er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
1245 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
1250 ipv4
= (struct prefix_ipv4
*)&rn
->p
;
1252 if (area
->oldmetric
)
1254 if (tlv_data
->ipv4_ext_reachs
== NULL
)
1256 tlv_data
->ipv4_ext_reachs
= list_new();
1257 tlv_data
->ipv4_ext_reachs
->del
= free_tlv
;
1259 ipreach
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*ipreach
));
1261 ipreach
->prefix
.s_addr
= ipv4
->prefix
.s_addr
;
1262 masklen2ip(ipv4
->prefixlen
, &ipreach
->mask
);
1263 ipreach
->prefix
.s_addr
&= ipreach
->mask
.s_addr
;
1265 if ((info
->metric
& 0x3f) != info
->metric
)
1266 ipreach
->metrics
.metric_default
= 0x3f;
1268 ipreach
->metrics
.metric_default
= info
->metric
;
1269 ipreach
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1270 ipreach
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1271 ipreach
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1272 listnode_add(tlv_data
->ipv4_ext_reachs
, ipreach
);
1274 if (area
->newmetric
)
1276 if (tlv_data
->te_ipv4_reachs
== NULL
)
1278 tlv_data
->te_ipv4_reachs
= list_new();
1279 tlv_data
->te_ipv4_reachs
->del
= free_tlv
;
1282 XCALLOC(MTYPE_ISIS_TLV
,
1283 sizeof(*te_ipreach
) - 1 + PSIZE(ipv4
->prefixlen
));
1284 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1285 te_ipreach
->te_metric
= htonl(MAX_WIDE_PATH_METRIC
);
1287 te_ipreach
->te_metric
= htonl(info
->metric
);
1288 te_ipreach
->control
= ipv4
->prefixlen
& 0x3f;
1289 memcpy(&te_ipreach
->prefix_start
, &ipv4
->prefix
.s_addr
,
1290 PSIZE(ipv4
->prefixlen
));
1291 listnode_add(tlv_data
->te_ipv4_reachs
, te_ipreach
);
1297 lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
, struct isis_area
*area
,
1298 struct tlvs
*tlv_data
)
1300 struct route_table
*er_table
;
1301 struct route_node
*rn
;
1302 struct prefix_ipv6
*ipv6
;
1303 struct isis_ext_info
*info
;
1304 struct ipv6_reachability
*ip6reach
;
1306 er_table
= get_ext_reach(area
, AF_INET6
, lsp
->level
);
1310 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
1315 ipv6
= (struct prefix_ipv6
*)&rn
->p
;
1318 if (tlv_data
->ipv6_reachs
== NULL
)
1320 tlv_data
->ipv6_reachs
= list_new();
1321 tlv_data
->ipv6_reachs
->del
= free_tlv
;
1323 ip6reach
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ip6reach
));
1324 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1325 ip6reach
->metric
= htonl(MAX_WIDE_PATH_METRIC
);
1327 ip6reach
->metric
= htonl(info
->metric
);
1328 ip6reach
->control_info
= DISTRIBUTION_EXTERNAL
;
1329 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1330 memcpy(ip6reach
->prefix
, ipv6
->prefix
.s6_addr
, sizeof(ip6reach
->prefix
));
1331 listnode_add(tlv_data
->ipv6_reachs
, ip6reach
);
1336 lsp_build_ext_reach (struct isis_lsp
*lsp
, struct isis_area
*area
,
1337 struct tlvs
*tlv_data
)
1339 lsp_build_ext_reach_ipv4(lsp
, area
, tlv_data
);
1340 lsp_build_ext_reach_ipv6(lsp
, area
, tlv_data
);
1344 * Builds the LSP data part. This func creates a new frag whenever
1345 * area->lsp_frag_threshold is exceeded.
1348 lsp_build (struct isis_lsp
*lsp
, struct isis_area
*area
)
1350 struct is_neigh
*is_neigh
;
1351 struct te_is_neigh
*te_is_neigh
;
1352 struct listnode
*node
, *ipnode
;
1353 int level
= lsp
->level
;
1354 struct isis_circuit
*circuit
;
1355 struct prefix_ipv4
*ipv4
;
1356 struct ipv4_reachability
*ipreach
;
1357 struct te_ipv4_reachability
*te_ipreach
;
1358 struct isis_adjacency
*nei
;
1360 struct prefix_ipv6
*ipv6
, ip6prefix
;
1361 struct ipv6_reachability
*ip6reach
;
1362 #endif /* HAVE_IPV6 */
1363 struct tlvs tlv_data
;
1364 struct isis_lsp
*lsp0
= lsp
;
1365 struct in_addr
*routerid
;
1366 uint32_t expected
= 0, found
= 0;
1368 u_char zero_id
[ISIS_SYS_ID_LEN
+ 1];
1369 int retval
= ISIS_OK
;
1372 lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area
->area_tag
, level
);
1375 * Building the zero lsp
1377 memset (zero_id
, 0, ISIS_SYS_ID_LEN
+ 1);
1379 /* Reset stream endp. Stream is always there and on every LSP refresh only
1380 * TLV part of it is overwritten. So we must seek past header we will not
1382 stream_reset (lsp
->pdu
);
1383 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
1386 * Add the authentication info if its present
1391 * First add the tlvs related to area
1394 /* Area addresses */
1395 if (lsp
->tlv_data
.area_addrs
== NULL
)
1396 lsp
->tlv_data
.area_addrs
= list_new ();
1397 list_add_list (lsp
->tlv_data
.area_addrs
, area
->area_addrs
);
1398 if (listcount (lsp
->tlv_data
.area_addrs
) > 0)
1399 tlv_add_area_addrs (lsp
->tlv_data
.area_addrs
, lsp
->pdu
);
1401 /* Protocols Supported */
1402 if (area
->ip_circuits
> 0
1404 || area
->ipv6_circuits
> 0
1405 #endif /* HAVE_IPV6 */
1408 lsp
->tlv_data
.nlpids
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct nlpids
));
1409 lsp
->tlv_data
.nlpids
->count
= 0;
1410 if (area
->ip_circuits
> 0)
1412 lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area
->area_tag
);
1413 lsp
->tlv_data
.nlpids
->count
++;
1414 lsp
->tlv_data
.nlpids
->nlpids
[0] = NLPID_IP
;
1417 if (area
->ipv6_circuits
> 0)
1419 lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area
->area_tag
);
1420 lsp
->tlv_data
.nlpids
->count
++;
1421 lsp
->tlv_data
.nlpids
->nlpids
[lsp
->tlv_data
.nlpids
->count
- 1] =
1424 #endif /* HAVE_IPV6 */
1425 tlv_add_nlpid (lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1428 /* Dynamic Hostname */
1429 if (area
->dynhostname
)
1431 const char *hostname
= unix_hostname();
1432 size_t hostname_len
= strlen(hostname
);
1434 lsp
->tlv_data
.hostname
= XMALLOC (MTYPE_ISIS_TLV
,
1435 sizeof (struct hostname
));
1437 strncpy((char *)lsp
->tlv_data
.hostname
->name
, hostname
,
1438 sizeof(lsp
->tlv_data
.hostname
->name
));
1439 if (hostname_len
<= MAX_TLV_LEN
)
1440 lsp
->tlv_data
.hostname
->namelen
= hostname_len
;
1442 lsp
->tlv_data
.hostname
->namelen
= MAX_TLV_LEN
;
1444 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area
->area_tag
,
1445 lsp
->tlv_data
.hostname
->namelen
, lsp
->tlv_data
.hostname
->name
);
1446 tlv_add_dynamic_hostname (lsp
->tlv_data
.hostname
, lsp
->pdu
);
1450 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area
->area_tag
);
1453 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1454 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
1455 * LSP and this address is same as router id. */
1456 if (isis
->router_id
!= 0)
1458 inet_ntop(AF_INET
, &isis
->router_id
, buf
, sizeof(buf
));
1459 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area
->area_tag
, buf
);
1460 if (lsp
->tlv_data
.ipv4_addrs
== NULL
)
1462 lsp
->tlv_data
.ipv4_addrs
= list_new ();
1463 lsp
->tlv_data
.ipv4_addrs
->del
= free_tlv
;
1466 routerid
= XMALLOC (MTYPE_ISIS_TLV
, sizeof (struct in_addr
));
1467 routerid
->s_addr
= isis
->router_id
;
1468 listnode_add (lsp
->tlv_data
.ipv4_addrs
, routerid
);
1469 tlv_add_in_addr (routerid
, lsp
->pdu
, IPV4_ADDR
);
1471 /* Exactly same data is put into TE router ID TLV, but only if new style
1472 * TLV's are in use. */
1473 if (area
->newmetric
)
1475 lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area
->area_tag
);
1476 lsp
->tlv_data
.router_id
= XMALLOC (MTYPE_ISIS_TLV
,
1477 sizeof (struct in_addr
));
1478 lsp
->tlv_data
.router_id
->id
.s_addr
= isis
->router_id
;
1479 tlv_add_in_addr (&lsp
->tlv_data
.router_id
->id
, lsp
->pdu
,
1485 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area
->area_tag
);
1488 memset (&tlv_data
, 0, sizeof (struct tlvs
));
1490 lsp_debug("ISIS (%s): Adding circuit specific information.", area
->area_tag
);
1493 * Then build lists of tlvs related to circuits
1495 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, node
, circuit
))
1497 if (!circuit
->interface
)
1498 lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface",
1499 area
->area_tag
, circuit_type2string(circuit
->circ_type
), circuit
);
1501 lsp_debug("ISIS (%s): Processing %s circuit %s",
1502 area
->area_tag
, circuit_type2string(circuit
->circ_type
), circuit
->interface
->name
);
1504 if (circuit
->state
!= C_STATE_UP
)
1506 lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area
->area_tag
);
1511 * Add IPv4 internal reachability of this circuit
1513 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
1514 circuit
->ip_addrs
->count
> 0)
1516 lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area
->area_tag
);
1517 if (area
->oldmetric
)
1519 if (tlv_data
.ipv4_int_reachs
== NULL
)
1521 tlv_data
.ipv4_int_reachs
= list_new ();
1522 tlv_data
.ipv4_int_reachs
->del
= free_tlv
;
1524 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
1527 XMALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv4_reachability
));
1528 ipreach
->metrics
.metric_default
= circuit
->metric
[level
- 1];
1529 ipreach
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1530 ipreach
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1531 ipreach
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1532 masklen2ip (ipv4
->prefixlen
, &ipreach
->mask
);
1533 ipreach
->prefix
.s_addr
= ((ipreach
->mask
.s_addr
) &
1534 (ipv4
->prefix
.s_addr
));
1535 inet_ntop(AF_INET
, &ipreach
->prefix
.s_addr
, buf
, sizeof(buf
));
1536 lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d",
1537 area
->area_tag
, buf
, ipv4
->prefixlen
);
1538 listnode_add (tlv_data
.ipv4_int_reachs
, ipreach
);
1541 if (area
->newmetric
)
1543 if (tlv_data
.te_ipv4_reachs
== NULL
)
1545 tlv_data
.te_ipv4_reachs
= list_new ();
1546 tlv_data
.te_ipv4_reachs
->del
= free_tlv
;
1548 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
1550 /* FIXME All this assumes that we have no sub TLVs. */
1551 te_ipreach
= XCALLOC (MTYPE_ISIS_TLV
,
1552 sizeof (struct te_ipv4_reachability
) +
1553 ((ipv4
->prefixlen
+ 7)/8) - 1);
1555 if (area
->oldmetric
)
1556 te_ipreach
->te_metric
= htonl (circuit
->metric
[level
- 1]);
1558 te_ipreach
->te_metric
= htonl (circuit
->te_metric
[level
- 1]);
1560 te_ipreach
->control
= (ipv4
->prefixlen
& 0x3F);
1561 memcpy (&te_ipreach
->prefix_start
, &ipv4
->prefix
.s_addr
,
1562 (ipv4
->prefixlen
+ 7)/8);
1563 inet_ntop(AF_INET
, &ipv4
->prefix
.s_addr
, buf
, sizeof(buf
));
1564 lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d",
1565 area
->area_tag
, buf
, ipv4
->prefixlen
);
1566 listnode_add (tlv_data
.te_ipv4_reachs
, te_ipreach
);
1573 * Add IPv6 reachability of this circuit
1575 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
&&
1576 circuit
->ipv6_non_link
->count
> 0)
1579 if (tlv_data
.ipv6_reachs
== NULL
)
1581 tlv_data
.ipv6_reachs
= list_new ();
1582 tlv_data
.ipv6_reachs
->del
= free_tlv
;
1584 for (ALL_LIST_ELEMENTS_RO (circuit
->ipv6_non_link
, ipnode
, ipv6
))
1587 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv6_reachability
));
1589 if (area
->oldmetric
)
1591 htonl (circuit
->metric
[level
- 1]);
1593 ip6reach
->metric
= htonl (circuit
->te_metric
[level
- 1]);
1595 ip6reach
->control_info
= 0;
1596 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1597 memcpy(&ip6prefix
, ipv6
, sizeof(ip6prefix
));
1598 apply_mask_ipv6(&ip6prefix
);
1600 inet_ntop(AF_INET6
, &ip6prefix
.prefix
.s6_addr
, buf
, sizeof(buf
));
1601 lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
1602 area
->area_tag
, buf
, ipv6
->prefixlen
);
1604 memcpy (ip6reach
->prefix
, ip6prefix
.prefix
.s6_addr
,
1605 sizeof (ip6reach
->prefix
));
1606 listnode_add (tlv_data
.ipv6_reachs
, ip6reach
);
1609 #endif /* HAVE_IPV6 */
1611 switch (circuit
->circ_type
)
1613 case CIRCUIT_T_BROADCAST
:
1614 if (level
& circuit
->is_type
)
1616 if (area
->oldmetric
)
1618 if (tlv_data
.is_neighs
== NULL
)
1620 tlv_data
.is_neighs
= list_new ();
1621 tlv_data
.is_neighs
->del
= free_tlv
;
1623 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1624 if (level
== IS_LEVEL_1
)
1625 memcpy (is_neigh
->neigh_id
,
1626 circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1628 memcpy (is_neigh
->neigh_id
,
1629 circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1630 is_neigh
->metrics
.metric_default
= circuit
->metric
[level
- 1];
1631 is_neigh
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1632 is_neigh
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1633 is_neigh
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1634 if (!memcmp (is_neigh
->neigh_id
, zero_id
,
1635 ISIS_SYS_ID_LEN
+ 1))
1637 XFREE (MTYPE_ISIS_TLV
, is_neigh
);
1638 lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1643 listnode_add (tlv_data
.is_neighs
, is_neigh
);
1644 lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1645 area
->area_tag
, sysid_print(is_neigh
->neigh_id
),
1646 LSP_PSEUDO_ID(is_neigh
->neigh_id
));
1649 if (area
->newmetric
)
1651 if (tlv_data
.te_is_neighs
== NULL
)
1653 tlv_data
.te_is_neighs
= list_new ();
1654 tlv_data
.te_is_neighs
->del
= free_tlv
;
1656 te_is_neigh
= XCALLOC (MTYPE_ISIS_TLV
,
1657 sizeof (struct te_is_neigh
));
1658 if (level
== IS_LEVEL_1
)
1659 memcpy (te_is_neigh
->neigh_id
,
1660 circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1662 memcpy (te_is_neigh
->neigh_id
,
1663 circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1664 if (area
->oldmetric
)
1665 metric
= circuit
->metric
[level
- 1];
1667 metric
= circuit
->te_metric
[level
- 1];
1668 SET_TE_METRIC(te_is_neigh
, metric
);
1669 if (!memcmp (te_is_neigh
->neigh_id
, zero_id
,
1670 ISIS_SYS_ID_LEN
+ 1))
1672 XFREE (MTYPE_ISIS_TLV
, te_is_neigh
);
1673 lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1678 /* Check if MPLS_TE is activate */
1679 if (IS_MPLS_TE(isisMplsTE
) && HAS_LINK_PARAMS(circuit
->interface
))
1680 /* Add SubTLVs & Adjust real size of SubTLVs */
1681 te_is_neigh
->sub_tlvs_length
= add_te_subtlvs(te_is_neigh
->sub_tlvs
, circuit
->mtc
);
1683 /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1684 te_is_neigh
->sub_tlvs_length
= 0;
1686 listnode_add (tlv_data
.te_is_neighs
, te_is_neigh
);
1687 lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
1688 area
->area_tag
, sysid_print(te_is_neigh
->neigh_id
),
1689 LSP_PSEUDO_ID(te_is_neigh
->neigh_id
));
1695 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1700 nei
= circuit
->u
.p2p
.neighbor
;
1701 if (nei
&& (level
& nei
->circuit_t
))
1703 if (area
->oldmetric
)
1705 if (tlv_data
.is_neighs
== NULL
)
1707 tlv_data
.is_neighs
= list_new ();
1708 tlv_data
.is_neighs
->del
= free_tlv
;
1710 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1711 memcpy (is_neigh
->neigh_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1712 is_neigh
->metrics
.metric_default
= circuit
->metric
[level
- 1];
1713 is_neigh
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1714 is_neigh
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1715 is_neigh
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1716 listnode_add (tlv_data
.is_neighs
, is_neigh
);
1717 lsp_debug("ISIS (%s): Adding old-style is reach for %s", area
->area_tag
,
1718 sysid_print(is_neigh
->neigh_id
));
1720 if (area
->newmetric
)
1724 if (tlv_data
.te_is_neighs
== NULL
)
1726 tlv_data
.te_is_neighs
= list_new ();
1727 tlv_data
.te_is_neighs
->del
= free_tlv
;
1729 te_is_neigh
= XCALLOC (MTYPE_ISIS_TLV
,
1730 sizeof (struct te_is_neigh
));
1731 memcpy (te_is_neigh
->neigh_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1732 metric
= circuit
->te_metric
[level
- 1];
1733 SET_TE_METRIC(te_is_neigh
, metric
);
1734 /* Check if MPLS_TE is activate */
1735 if (IS_MPLS_TE(isisMplsTE
) && HAS_LINK_PARAMS(circuit
->interface
))
1736 /* Update Local and Remote IP address for MPLS TE circuit parameters */
1737 /* NOTE sure that it is the pertinent place for that updates */
1738 /* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */
1739 /* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */
1741 /* Add SubTLVs & Adjust real size of SubTLVs */
1742 te_is_neigh
->sub_tlvs_length
= add_te_subtlvs(te_is_neigh
->sub_tlvs
, circuit
->mtc
);
1744 /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1745 te_is_neigh
->sub_tlvs_length
= 0;
1746 listnode_add (tlv_data
.te_is_neighs
, te_is_neigh
);
1747 lsp_debug("ISIS (%s): Adding te-style is reach for %s", area
->area_tag
,
1748 sysid_print(te_is_neigh
->neigh_id
));
1753 lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1757 case CIRCUIT_T_LOOPBACK
:
1760 zlog_warn ("lsp_area_create: unknown circuit type");
1764 lsp_build_ext_reach(lsp
, area
, &tlv_data
);
1766 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area
->area_tag
);
1768 while (tlv_data
.ipv4_int_reachs
&& listcount (tlv_data
.ipv4_int_reachs
))
1770 if (lsp
->tlv_data
.ipv4_int_reachs
== NULL
)
1771 lsp
->tlv_data
.ipv4_int_reachs
= list_new ();
1772 lsp_tlv_fit (lsp
, &tlv_data
.ipv4_int_reachs
,
1773 &lsp
->tlv_data
.ipv4_int_reachs
,
1774 IPV4_REACH_LEN
, area
->lsp_frag_threshold
,
1775 tlv_add_ipv4_int_reachs
);
1776 if (tlv_data
.ipv4_int_reachs
&& listcount (tlv_data
.ipv4_int_reachs
))
1777 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1781 while (tlv_data
.ipv4_ext_reachs
&& listcount (tlv_data
.ipv4_ext_reachs
))
1783 if (lsp
->tlv_data
.ipv4_ext_reachs
== NULL
)
1784 lsp
->tlv_data
.ipv4_ext_reachs
= list_new ();
1785 lsp_tlv_fit (lsp
, &tlv_data
.ipv4_ext_reachs
,
1786 &lsp
->tlv_data
.ipv4_ext_reachs
,
1787 IPV4_REACH_LEN
, area
->lsp_frag_threshold
,
1788 tlv_add_ipv4_ext_reachs
);
1789 if (tlv_data
.ipv4_ext_reachs
&& listcount (tlv_data
.ipv4_ext_reachs
))
1790 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1794 /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
1795 * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
1796 * TLVs (sub TLVs!). */
1797 while (tlv_data
.te_ipv4_reachs
&& listcount (tlv_data
.te_ipv4_reachs
))
1799 if (lsp
->tlv_data
.te_ipv4_reachs
== NULL
)
1800 lsp
->tlv_data
.te_ipv4_reachs
= list_new ();
1801 lsp_tlv_fit (lsp
, &tlv_data
.te_ipv4_reachs
,
1802 &lsp
->tlv_data
.te_ipv4_reachs
,
1803 TE_IPV4_REACH_LEN
, area
->lsp_frag_threshold
,
1804 tlv_add_te_ipv4_reachs
);
1805 if (tlv_data
.te_ipv4_reachs
&& listcount (tlv_data
.te_ipv4_reachs
))
1806 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1811 while (tlv_data
.ipv6_reachs
&& listcount (tlv_data
.ipv6_reachs
))
1813 if (lsp
->tlv_data
.ipv6_reachs
== NULL
)
1814 lsp
->tlv_data
.ipv6_reachs
= list_new ();
1815 lsp_tlv_fit (lsp
, &tlv_data
.ipv6_reachs
,
1816 &lsp
->tlv_data
.ipv6_reachs
,
1817 IPV6_REACH_LEN
, area
->lsp_frag_threshold
,
1818 tlv_add_ipv6_reachs
);
1819 if (tlv_data
.ipv6_reachs
&& listcount (tlv_data
.ipv6_reachs
))
1820 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1823 #endif /* HAVE_IPV6 */
1825 while (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
1827 if (lsp
->tlv_data
.is_neighs
== NULL
)
1828 lsp
->tlv_data
.is_neighs
= list_new ();
1829 lsp_tlv_fit (lsp
, &tlv_data
.is_neighs
,
1830 &lsp
->tlv_data
.is_neighs
,
1831 IS_NEIGHBOURS_LEN
, area
->lsp_frag_threshold
,
1833 if (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
1834 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1838 while (tlv_data
.te_is_neighs
&& listcount (tlv_data
.te_is_neighs
))
1840 if (lsp
->tlv_data
.te_is_neighs
== NULL
)
1841 lsp
->tlv_data
.te_is_neighs
= list_new ();
1842 lsp_tlv_fit (lsp
, &tlv_data
.te_is_neighs
, &lsp
->tlv_data
.te_is_neighs
,
1843 IS_NEIGHBOURS_LEN
, area
->lsp_frag_threshold
,
1844 tlv_add_te_is_neighs
);
1845 if (tlv_data
.te_is_neighs
&& listcount (tlv_data
.te_is_neighs
))
1846 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1849 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1851 free_tlvs (&tlv_data
);
1853 /* Validate the LSP */
1854 retval
= parse_tlvs (area
->area_tag
, STREAM_DATA (lsp
->pdu
) +
1855 ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
,
1856 stream_get_endp (lsp
->pdu
) -
1857 ISIS_FIXED_HDR_LEN
- ISIS_LSP_HDR_LEN
,
1858 &expected
, &found
, &tlv_data
, NULL
);
1859 assert (retval
== ISIS_OK
);
1865 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1868 lsp_generate (struct isis_area
*area
, int level
)
1870 struct isis_lsp
*oldlsp
, *newlsp
;
1871 u_int32_t seq_num
= 0;
1872 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1873 u_int16_t rem_lifetime
, refresh_time
;
1875 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1878 memset (&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1879 memcpy (&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1881 /* only builds the lsp if the area shares the level */
1882 oldlsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
1885 /* FIXME: we should actually initiate a purge */
1886 seq_num
= ntohl (oldlsp
->lsp_header
->seq_num
);
1887 lsp_search_and_destroy (oldlsp
->lsp_header
->lsp_id
,
1888 area
->lspdb
[level
- 1]);
1890 rem_lifetime
= lsp_rem_lifetime (area
, level
);
1891 newlsp
= lsp_new (area
, lspid
, rem_lifetime
, seq_num
,
1892 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1894 newlsp
->area
= area
;
1895 newlsp
->own_lsp
= 1;
1897 lsp_insert (newlsp
, area
->lspdb
[level
- 1]);
1898 /* build_lsp_data (newlsp, area); */
1899 lsp_build (newlsp
, area
);
1900 /* time to calculate our checksum */
1901 lsp_seqnum_update (newlsp
);
1902 newlsp
->last_generated
= time(NULL
);
1903 lsp_set_all_srmflags (newlsp
);
1905 refresh_time
= lsp_refresh_time (newlsp
, rem_lifetime
);
1907 THREAD_TIMER_OFF (area
->t_lsp_refresh
[level
- 1]);
1908 area
->lsp_regenerate_pending
[level
- 1] = 0;
1909 if (level
== IS_LEVEL_1
)
1910 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[level
- 1],
1911 lsp_l1_refresh
, area
, refresh_time
);
1912 else if (level
== IS_LEVEL_2
)
1913 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[level
- 1],
1914 lsp_l2_refresh
, area
, refresh_time
);
1916 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1918 zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
1919 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1920 area
->area_tag
, level
,
1921 rawlspid_print (newlsp
->lsp_header
->lsp_id
),
1922 ntohl (newlsp
->lsp_header
->pdu_len
),
1923 ntohl (newlsp
->lsp_header
->seq_num
),
1924 ntohs (newlsp
->lsp_header
->checksum
),
1925 ntohs (newlsp
->lsp_header
->rem_lifetime
),
1928 sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1929 area
->area_tag
, level
);
1935 * Search own LSPs, update holding time and set SRM
1938 lsp_regenerate (struct isis_area
*area
, int level
)
1941 struct isis_lsp
*lsp
, *frag
;
1942 struct listnode
*node
;
1943 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1944 u_int16_t rem_lifetime
, refresh_time
;
1946 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1949 lspdb
= area
->lspdb
[level
- 1];
1951 memset (lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1952 memcpy (lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1954 lsp
= lsp_search (lspid
, lspdb
);
1958 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1959 area
->area_tag
, level
);
1963 lsp_clear_data (lsp
);
1964 lsp_build (lsp
, area
);
1965 lsp
->lsp_header
->lsp_bits
= lsp_bits_generate (level
, area
->overload_bit
,
1966 area
->attached_bit
);
1967 rem_lifetime
= lsp_rem_lifetime (area
, level
);
1968 lsp
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
1969 lsp_seqnum_update (lsp
);
1971 lsp
->last_generated
= time (NULL
);
1972 lsp_set_all_srmflags (lsp
);
1973 for (ALL_LIST_ELEMENTS_RO (lsp
->lspu
.frags
, node
, frag
))
1975 frag
->lsp_header
->lsp_bits
= lsp_bits_generate (level
,
1977 area
->attached_bit
);
1978 /* Set the lifetime values of all the fragments to the same value,
1979 * so that no fragment expires before the lsp is refreshed.
1981 frag
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
1982 lsp_set_all_srmflags (frag
);
1985 refresh_time
= lsp_refresh_time (lsp
, rem_lifetime
);
1986 if (level
== IS_LEVEL_1
)
1987 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[level
- 1],
1988 lsp_l1_refresh
, area
, refresh_time
);
1989 else if (level
== IS_LEVEL_2
)
1990 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[level
- 1],
1991 lsp_l2_refresh
, area
, refresh_time
);
1992 area
->lsp_regenerate_pending
[level
- 1] = 0;
1994 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1996 zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
1997 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1998 area
->area_tag
, level
,
1999 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2000 ntohl (lsp
->lsp_header
->pdu_len
),
2001 ntohl (lsp
->lsp_header
->seq_num
),
2002 ntohs (lsp
->lsp_header
->checksum
),
2003 ntohs (lsp
->lsp_header
->rem_lifetime
),
2006 sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2007 area
->area_tag
, level
);
2013 * Something has changed or periodic refresh -> regenerate LSP
2016 lsp_l1_refresh (struct thread
*thread
)
2018 struct isis_area
*area
;
2020 area
= THREAD_ARG (thread
);
2023 area
->t_lsp_refresh
[0] = NULL
;
2024 area
->lsp_regenerate_pending
[0] = 0;
2026 if ((area
->is_type
& IS_LEVEL_1
) == 0)
2029 sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area
->area_tag
);
2030 return lsp_regenerate (area
, IS_LEVEL_1
);
2034 lsp_l2_refresh (struct thread
*thread
)
2036 struct isis_area
*area
;
2038 area
= THREAD_ARG (thread
);
2041 area
->t_lsp_refresh
[1] = NULL
;
2042 area
->lsp_regenerate_pending
[1] = 0;
2044 if ((area
->is_type
& IS_LEVEL_2
) == 0)
2047 sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area
->area_tag
);
2048 return lsp_regenerate (area
, IS_LEVEL_2
);
2052 lsp_regenerate_schedule (struct isis_area
*area
, int level
, int all_pseudo
)
2054 struct isis_lsp
*lsp
;
2055 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2058 struct listnode
*cnode
;
2059 struct isis_circuit
*circuit
;
2065 sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2066 area
->area_tag
, circuit_t2string(level
), all_pseudo
? "" : "not ");
2068 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2069 LSP_PSEUDO_ID (id
) = LSP_FRAGMENT (id
) = 0;
2072 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++)
2074 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
2077 sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2078 area
->area_tag
, lvl
);
2080 if (area
->lsp_regenerate_pending
[lvl
- 1])
2082 struct timeval remain
= thread_timer_remain(area
->t_lsp_refresh
[lvl
- 1]);
2083 sched_debug("ISIS (%s): Regeneration is already pending, nothing todo."
2084 " (Due in %lld.%03lld seconds)", area
->area_tag
,
2085 (long long)remain
.tv_sec
, (long long)remain
.tv_usec
/ 1000);
2089 lsp
= lsp_search (id
, area
->lspdb
[lvl
- 1]);
2092 sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2098 * Throttle avoidance
2100 sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2101 area
->area_tag
, (long long)lsp
->last_generated
, (long long)now
);
2102 THREAD_TIMER_OFF (area
->t_lsp_refresh
[lvl
- 1]);
2103 diff
= now
- lsp
->last_generated
;
2104 if (diff
< area
->lsp_gen_interval
[lvl
- 1])
2106 timeout
= 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
2107 sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2108 area
->area_tag
, timeout
);
2113 * lsps are not regenerated if lsp_regenerate function is called
2114 * directly. However if the lsp_regenerate call is queued for
2115 * later execution it works.
2118 sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2119 " Scheduling for execution in %ld ms.", area
->area_tag
, timeout
);
2122 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
2123 if (lvl
== IS_LEVEL_1
)
2125 THREAD_TIMER_MSEC_ON(master
, area
->t_lsp_refresh
[lvl
- 1],
2126 lsp_l1_refresh
, area
, timeout
);
2128 else if (lvl
== IS_LEVEL_2
)
2130 THREAD_TIMER_MSEC_ON(master
, area
->t_lsp_refresh
[lvl
- 1],
2131 lsp_l2_refresh
, area
, timeout
);
2137 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2138 lsp_regenerate_schedule_pseudo (circuit
, level
);
2145 * Funcs for pseudonode LSPs
2149 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2152 lsp_build_pseudo (struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2155 struct isis_adjacency
*adj
;
2156 struct is_neigh
*is_neigh
;
2157 struct te_is_neigh
*te_is_neigh
;
2158 struct es_neigh
*es_neigh
;
2159 struct list
*adj_list
;
2160 struct listnode
*node
;
2161 struct isis_area
*area
= circuit
->area
;
2163 lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2164 area
->area_tag
, rawlspid_print(lsp
->lsp_header
->lsp_id
),
2165 circuit
->interface
->name
, level
);
2168 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2169 lsp
->lsp_header
->lsp_bits
= lsp_bits_generate (level
, 0,
2170 circuit
->area
->attached_bit
);
2173 * add self to IS neighbours
2175 if (circuit
->area
->oldmetric
)
2177 if (lsp
->tlv_data
.is_neighs
== NULL
)
2179 lsp
->tlv_data
.is_neighs
= list_new ();
2180 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
2182 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
2184 memcpy (&is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2185 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
2186 lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2187 area
->area_tag
, sysid_print(is_neigh
->neigh_id
),
2188 LSP_PSEUDO_ID(is_neigh
->neigh_id
));
2190 if (circuit
->area
->newmetric
)
2192 if (lsp
->tlv_data
.te_is_neighs
== NULL
)
2194 lsp
->tlv_data
.te_is_neighs
= list_new ();
2195 lsp
->tlv_data
.te_is_neighs
->del
= free_tlv
;
2197 te_is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct te_is_neigh
));
2199 memcpy (&te_is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2200 listnode_add (lsp
->tlv_data
.te_is_neighs
, te_is_neigh
);
2201 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2202 area
->area_tag
, sysid_print(te_is_neigh
->neigh_id
),
2203 LSP_PSEUDO_ID(te_is_neigh
->neigh_id
));
2206 adj_list
= list_new ();
2207 isis_adj_build_up_list (circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
2209 for (ALL_LIST_ELEMENTS_RO (adj_list
, node
, adj
))
2211 if (adj
->level
& level
)
2213 if ((level
== IS_LEVEL_1
&& adj
->sys_type
== ISIS_SYSTYPE_L1_IS
) ||
2214 (level
== IS_LEVEL_1
&& adj
->sys_type
== ISIS_SYSTYPE_L2_IS
&&
2215 adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
2216 (level
== IS_LEVEL_2
&& adj
->sys_type
== ISIS_SYSTYPE_L2_IS
))
2218 /* an IS neighbour -> add it */
2219 if (circuit
->area
->oldmetric
)
2221 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
2223 memcpy (&is_neigh
->neigh_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
2224 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
2225 lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2226 area
->area_tag
, sysid_print(is_neigh
->neigh_id
),
2227 LSP_PSEUDO_ID(is_neigh
->neigh_id
));
2229 if (circuit
->area
->newmetric
)
2231 te_is_neigh
= XCALLOC (MTYPE_ISIS_TLV
,
2232 sizeof (struct te_is_neigh
));
2233 memcpy (&te_is_neigh
->neigh_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
2234 listnode_add (lsp
->tlv_data
.te_is_neighs
, te_is_neigh
);
2235 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2236 area
->area_tag
, sysid_print(te_is_neigh
->neigh_id
),
2237 LSP_PSEUDO_ID(te_is_neigh
->neigh_id
));
2240 else if (level
== IS_LEVEL_1
&& adj
->sys_type
== ISIS_SYSTYPE_ES
)
2242 /* an ES neigbour add it, if we are building level 1 LSP */
2243 /* FIXME: the tlv-format is hard to use here */
2244 if (lsp
->tlv_data
.es_neighs
== NULL
)
2246 lsp
->tlv_data
.es_neighs
= list_new ();
2247 lsp
->tlv_data
.es_neighs
->del
= free_tlv
;
2249 es_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct es_neigh
));
2251 memcpy (&es_neigh
->first_es_neigh
, adj
->sysid
, ISIS_SYS_ID_LEN
);
2252 listnode_add (lsp
->tlv_data
.es_neighs
, es_neigh
);
2253 lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
2254 area
->area_tag
, sysid_print(es_neigh
->first_es_neigh
));
2258 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
2259 area
->area_tag
, sysid_print(adj
->sysid
));
2264 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
2265 area
->area_tag
, sysid_print(adj
->sysid
));
2268 list_delete (adj_list
);
2270 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area
->area_tag
);
2272 /* Reset endp of stream to overwrite only TLV part of it. */
2273 stream_reset (lsp
->pdu
);
2274 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2277 * Add the authentication info if it's present
2281 if (lsp
->tlv_data
.is_neighs
&& listcount (lsp
->tlv_data
.is_neighs
) > 0)
2282 tlv_add_is_neighs (lsp
->tlv_data
.is_neighs
, lsp
->pdu
);
2284 if (lsp
->tlv_data
.te_is_neighs
&& listcount (lsp
->tlv_data
.te_is_neighs
) > 0)
2285 tlv_add_te_is_neighs (lsp
->tlv_data
.te_is_neighs
, lsp
->pdu
);
2287 if (lsp
->tlv_data
.es_neighs
&& listcount (lsp
->tlv_data
.es_neighs
) > 0)
2288 tlv_add_is_neighs (lsp
->tlv_data
.es_neighs
, lsp
->pdu
);
2290 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
2292 /* Recompute authentication and checksum information */
2293 lsp_auth_update (lsp
);
2294 fletcher_checksum(STREAM_DATA (lsp
->pdu
) + 12,
2295 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
2301 lsp_generate_pseudo (struct isis_circuit
*circuit
, int level
)
2303 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
2304 struct isis_lsp
*lsp
;
2305 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2306 u_int16_t rem_lifetime
, refresh_time
;
2308 if ((circuit
->is_type
& level
) != level
||
2309 (circuit
->state
!= C_STATE_UP
) ||
2310 (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
) ||
2311 (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
2314 memcpy (lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2315 LSP_FRAGMENT (lsp_id
) = 0;
2316 LSP_PSEUDO_ID (lsp_id
) = circuit
->circuit_id
;
2319 * If for some reason have a pseudo LSP in the db already -> regenerate
2321 if (lsp_search (lsp_id
, lspdb
))
2322 return lsp_regenerate_schedule_pseudo (circuit
, level
);
2324 rem_lifetime
= lsp_rem_lifetime (circuit
->area
, level
);
2325 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2326 lsp
= lsp_new (circuit
->area
, lsp_id
, rem_lifetime
, 1,
2327 circuit
->area
->is_type
| circuit
->area
->attached_bit
,
2329 lsp
->area
= circuit
->area
;
2331 lsp_build_pseudo (lsp
, circuit
, level
);
2334 lsp_insert (lsp
, lspdb
);
2335 lsp_set_all_srmflags (lsp
);
2337 refresh_time
= lsp_refresh_time (lsp
, rem_lifetime
);
2338 THREAD_TIMER_OFF (circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2339 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
2340 if (level
== IS_LEVEL_1
)
2341 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1],
2342 lsp_l1_refresh_pseudo
, circuit
, refresh_time
);
2343 else if (level
== IS_LEVEL_2
)
2344 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1],
2345 lsp_l2_refresh_pseudo
, circuit
, refresh_time
);
2347 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2349 zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2350 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2351 circuit
->area
->area_tag
, level
,
2352 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2353 ntohl (lsp
->lsp_header
->pdu_len
),
2354 ntohl (lsp
->lsp_header
->seq_num
),
2355 ntohs (lsp
->lsp_header
->checksum
),
2356 ntohs (lsp
->lsp_header
->rem_lifetime
),
2364 lsp_regenerate_pseudo (struct isis_circuit
*circuit
, int level
)
2366 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
2367 struct isis_lsp
*lsp
;
2368 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2369 u_int16_t rem_lifetime
, refresh_time
;
2371 if ((circuit
->is_type
& level
) != level
||
2372 (circuit
->state
!= C_STATE_UP
) ||
2373 (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
) ||
2374 (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
2377 memcpy (lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2378 LSP_PSEUDO_ID (lsp_id
) = circuit
->circuit_id
;
2379 LSP_FRAGMENT (lsp_id
) = 0;
2381 lsp
= lsp_search (lsp_id
, lspdb
);
2385 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2386 level
, rawlspid_print (lsp_id
));
2389 lsp_clear_data (lsp
);
2391 lsp_build_pseudo (lsp
, circuit
, level
);
2393 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2394 lsp
->lsp_header
->lsp_bits
= lsp_bits_generate (level
, 0,
2395 circuit
->area
->attached_bit
);
2396 rem_lifetime
= lsp_rem_lifetime (circuit
->area
, level
);
2397 lsp
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
2398 lsp_inc_seqnum (lsp
, 0);
2399 lsp
->last_generated
= time (NULL
);
2400 lsp_set_all_srmflags (lsp
);
2402 refresh_time
= lsp_refresh_time (lsp
, rem_lifetime
);
2403 if (level
== IS_LEVEL_1
)
2404 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1],
2405 lsp_l1_refresh_pseudo
, circuit
, refresh_time
);
2406 else if (level
== IS_LEVEL_2
)
2407 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1],
2408 lsp_l2_refresh_pseudo
, circuit
, refresh_time
);
2410 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2412 zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2413 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2414 circuit
->area
->area_tag
, level
,
2415 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2416 ntohl (lsp
->lsp_header
->pdu_len
),
2417 ntohl (lsp
->lsp_header
->seq_num
),
2418 ntohs (lsp
->lsp_header
->checksum
),
2419 ntohs (lsp
->lsp_header
->rem_lifetime
),
2427 * Something has changed or periodic refresh -> regenerate pseudo LSP
2430 lsp_l1_refresh_pseudo (struct thread
*thread
)
2432 struct isis_circuit
*circuit
;
2433 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2435 circuit
= THREAD_ARG (thread
);
2437 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
2438 circuit
->lsp_regenerate_pending
[0] = 0;
2440 if ((circuit
->u
.bc
.is_dr
[0] == 0) ||
2441 (circuit
->is_type
& IS_LEVEL_1
) == 0)
2443 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2444 LSP_PSEUDO_ID (id
) = circuit
->circuit_id
;
2445 LSP_FRAGMENT (id
) = 0;
2446 lsp_purge_pseudo (id
, circuit
, IS_LEVEL_1
);
2450 return lsp_regenerate_pseudo (circuit
, IS_LEVEL_1
);
2454 lsp_l2_refresh_pseudo (struct thread
*thread
)
2456 struct isis_circuit
*circuit
;
2457 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2459 circuit
= THREAD_ARG (thread
);
2461 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
2462 circuit
->lsp_regenerate_pending
[1] = 0;
2464 if ((circuit
->u
.bc
.is_dr
[1] == 0) ||
2465 (circuit
->is_type
& IS_LEVEL_2
) == 0)
2467 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2468 LSP_PSEUDO_ID (id
) = circuit
->circuit_id
;
2469 LSP_FRAGMENT (id
) = 0;
2470 lsp_purge_pseudo (id
, circuit
, IS_LEVEL_2
);
2474 return lsp_regenerate_pseudo (circuit
, IS_LEVEL_2
);
2478 lsp_regenerate_schedule_pseudo (struct isis_circuit
*circuit
, int level
)
2480 struct isis_lsp
*lsp
;
2481 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2485 struct isis_area
*area
= circuit
->area
;
2487 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
||
2488 circuit
->state
!= C_STATE_UP
)
2491 sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2492 area
->area_tag
, circuit_t2string(level
), circuit
->interface
->name
);
2494 memcpy (lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2495 LSP_PSEUDO_ID (lsp_id
) = circuit
->circuit_id
;
2496 LSP_FRAGMENT (lsp_id
) = 0;
2499 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++)
2501 sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2502 area
->area_tag
, lvl
);
2504 if (!((level
& lvl
) && (circuit
->is_type
& lvl
)))
2506 sched_debug("ISIS (%s): Level is not active on circuit",
2511 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0)
2513 sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
2518 if (circuit
->lsp_regenerate_pending
[lvl
- 1])
2520 struct timeval remain
=
2521 thread_timer_remain(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2522 sched_debug("ISIS (%s): Regenerate is already pending, nothing todo."
2523 " (Due in %lld.%03lld seconds)", area
->area_tag
,
2524 (long long)remain
.tv_sec
, (long long)remain
.tv_usec
/1000);
2528 lsp
= lsp_search (lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
2531 sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2537 * Throttle avoidance
2539 sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2540 area
->area_tag
, (long long)lsp
->last_generated
, (long long) now
);
2541 THREAD_TIMER_OFF (circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2542 diff
= now
- lsp
->last_generated
;
2543 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1])
2545 timeout
= 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1] - diff
);
2546 sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2547 area
->area_tag
, timeout
);
2552 sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2553 " Scheduling for execution in %ld ms.", area
->area_tag
, timeout
);
2556 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
2558 if (lvl
== IS_LEVEL_1
)
2560 THREAD_TIMER_MSEC_ON(master
,
2561 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1],
2562 lsp_l1_refresh_pseudo
, circuit
, timeout
);
2564 else if (lvl
== IS_LEVEL_2
)
2566 THREAD_TIMER_MSEC_ON(master
,
2567 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1],
2568 lsp_l2_refresh_pseudo
, circuit
, timeout
);
2576 * Walk through LSPs for an area
2577 * - set remaining lifetime
2578 * - set LSPs with SRMflag set for sending
2581 lsp_tick (struct thread
*thread
)
2583 struct isis_area
*area
;
2584 struct isis_circuit
*circuit
;
2585 struct isis_lsp
*lsp
;
2586 struct list
*lsp_list
;
2587 struct listnode
*lspnode
, *cnode
;
2588 dnode_t
*dnode
, *dnode_next
;
2590 u_int16_t rem_lifetime
;
2592 lsp_list
= list_new ();
2594 area
= THREAD_ARG (thread
);
2596 area
->t_tick
= NULL
;
2597 THREAD_TIMER_ON (master
, area
->t_tick
, lsp_tick
, area
, 1);
2600 * Build a list of LSPs with (any) SRMflag set
2601 * and removed the ones that have aged out
2603 for (level
= 0; level
< ISIS_LEVELS
; level
++)
2605 if (area
->lspdb
[level
] && dict_count (area
->lspdb
[level
]) > 0)
2607 for (dnode
= dict_first (area
->lspdb
[level
]);
2608 dnode
!= NULL
; dnode
= dnode_next
)
2610 dnode_next
= dict_next (area
->lspdb
[level
], dnode
);
2611 lsp
= dnode_get (dnode
);
2614 * The lsp rem_lifetime is kept at 0 for MaxAge or
2615 * ZeroAgeLifetime depending on explicit purge or
2616 * natural age out. So schedule spf only once when
2617 * the first time rem_lifetime becomes 0.
2619 rem_lifetime
= ntohs(lsp
->lsp_header
->rem_lifetime
);
2623 * Schedule may run spf which should be done only after
2624 * the lsp rem_lifetime becomes 0 for the first time.
2625 * ISO 10589 - 7.3.16.4 first paragraph.
2627 if (rem_lifetime
== 1 && lsp
->lsp_header
->seq_num
!= 0)
2629 /* 7.3.16.4 a) set SRM flags on all */
2630 lsp_set_all_srmflags (lsp
);
2631 /* 7.3.16.4 b) retain only the header FIXME */
2632 /* 7.3.16.4 c) record the time to purge FIXME */
2633 /* run/schedule spf */
2634 /* isis_spf_schedule is called inside lsp_destroy() below;
2635 * so it is not needed here. */
2636 /* isis_spf_schedule (lsp->area, lsp->level); */
2639 if (lsp
->age_out
== 0)
2641 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2644 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2645 ntohl (lsp
->lsp_header
->seq_num
));
2648 dict_delete_free (area
->lspdb
[level
], dnode
);
2650 else if (flags_any_set (lsp
->SRMflags
))
2651 listnode_add (lsp_list
, lsp
);
2655 * Send LSPs on circuits indicated by the SRMflags
2657 if (listcount (lsp_list
) > 0)
2659 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2661 int diff
= time (NULL
) - circuit
->lsp_queue_last_cleared
;
2662 if (circuit
->lsp_queue
== NULL
||
2663 diff
< MIN_LSP_TRANS_INTERVAL
)
2665 for (ALL_LIST_ELEMENTS_RO (lsp_list
, lspnode
, lsp
))
2667 if (circuit
->upadjcount
[lsp
->level
- 1] &&
2668 ISIS_CHECK_FLAG (lsp
->SRMflags
, circuit
))
2670 /* Add the lsp only if it is not already in lsp
2672 if (! listnode_lookup (circuit
->lsp_queue
, lsp
))
2674 listnode_add (circuit
->lsp_queue
, lsp
);
2675 thread_add_event (master
, send_lsp
, circuit
, 0);
2680 list_delete_all_node (lsp_list
);
2685 list_delete (lsp_list
);
2691 lsp_purge_pseudo (u_char
* id
, struct isis_circuit
*circuit
, int level
)
2693 struct isis_lsp
*lsp
;
2697 lsp
= lsp_search (id
, circuit
->area
->lspdb
[level
- 1]);
2701 /* store old values */
2702 seq_num
= lsp
->lsp_header
->seq_num
;
2703 lsp_bits
= lsp
->lsp_header
->lsp_bits
;
2706 lsp_clear_data (lsp
);
2707 stream_reset (lsp
->pdu
);
2710 lsp
->lsp_header
->pdu_len
= htons (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2711 memcpy (lsp
->lsp_header
->lsp_id
, id
, ISIS_SYS_ID_LEN
+ 2);
2712 lsp
->lsp_header
->checksum
= 0;
2713 lsp
->lsp_header
->seq_num
= seq_num
;
2714 lsp
->lsp_header
->rem_lifetime
= 0;
2715 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
2717 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
-1];
2718 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2721 * Add and update the authentication info if its present
2724 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
2725 lsp_auth_update (lsp
);
2726 fletcher_checksum(STREAM_DATA (lsp
->pdu
) + 12,
2727 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
2729 lsp_set_all_srmflags (lsp
);
2735 * Purge own LSP that is received and we don't have.
2736 * -> Do as in 7.3.16.4
2739 lsp_purge_non_exist (int level
,
2740 struct isis_link_state_hdr
*lsp_hdr
,
2741 struct isis_area
*area
)
2743 struct isis_lsp
*lsp
;
2746 * We need to create the LSP to be purged
2748 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
2751 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
2752 lsp
->isis_header
= (struct isis_fixed_hdr
*) STREAM_DATA (lsp
->pdu
);
2753 fill_fixed_hdr (lsp
->isis_header
, (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
2755 lsp
->lsp_header
= (struct isis_link_state_hdr
*) (STREAM_DATA (lsp
->pdu
) +
2756 ISIS_FIXED_HDR_LEN
);
2757 memcpy (lsp
->lsp_header
, lsp_hdr
, ISIS_LSP_HDR_LEN
);
2758 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2761 * Set the remaining lifetime to 0
2763 lsp
->lsp_header
->rem_lifetime
= 0;
2766 * Add and update the authentication info if its present
2769 lsp_auth_update (lsp
);
2772 * Update the PDU length to header plus any authentication TLV.
2774 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
2777 * Put the lsp into LSPdb
2779 lsp_insert (lsp
, area
->lspdb
[lsp
->level
- 1]);
2782 * Send in to whole area
2784 lsp_set_all_srmflags (lsp
);
2789 void lsp_set_all_srmflags (struct isis_lsp
*lsp
)
2791 struct listnode
*node
;
2792 struct isis_circuit
*circuit
;
2796 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
2800 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2801 for (ALL_LIST_ELEMENTS_RO (circuit_list
, node
, circuit
))
2803 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);