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; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40 #include "srcdest_table.h"
41 #include "lib_errors.h"
43 #include "isisd/dict.h"
44 #include "isisd/isis_constants.h"
45 #include "isisd/isis_common.h"
46 #include "isisd/isis_flags.h"
47 #include "isisd/isis_circuit.h"
48 #include "isisd/isisd.h"
49 #include "isisd/isis_lsp.h"
50 #include "isisd/isis_pdu.h"
51 #include "isisd/isis_dynhn.h"
52 #include "isisd/isis_misc.h"
53 #include "isisd/isis_csm.h"
54 #include "isisd/isis_adjacency.h"
55 #include "isisd/isis_spf.h"
56 #include "isisd/isis_te.h"
57 #include "isisd/isis_mt.h"
58 #include "isisd/isis_tlvs.h"
59 #include "isisd/fabricd.h"
60 #include "isisd/isis_tx_queue.h"
62 static int lsp_l1_refresh(struct thread
*thread
);
63 static int lsp_l2_refresh(struct thread
*thread
);
64 static int lsp_l1_refresh_pseudo(struct thread
*thread
);
65 static int lsp_l2_refresh_pseudo(struct thread
*thread
);
67 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
69 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
72 dict_t
*lsp_db_init(void)
76 dict
= dict_create(DICTCOUNT_T_MAX
, (dict_comp_t
)lsp_id_cmp
);
81 struct isis_lsp
*lsp_search(uint8_t *id
, dict_t
*lspdb
)
88 zlog_debug("searching db");
89 for (dn
= dict_first(lspdb
); dn
; dn
= dict_next(lspdb
, dn
)) {
91 rawlspid_print((uint8_t *)dnode_getkey(dn
)),
94 #endif /* EXTREME DEBUG */
96 node
= dict_lookup(lspdb
, id
);
99 return (struct isis_lsp
*)dnode_get(node
);
104 static void lsp_clear_data(struct isis_lsp
*lsp
)
109 isis_free_tlvs(lsp
->tlvs
);
113 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
);
115 static void lsp_destroy(struct isis_lsp
*lsp
)
117 struct listnode
*cnode
;
118 struct isis_circuit
*circuit
;
123 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
, circuit
))
124 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
126 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
130 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
131 if (lsp
->lspu
.frags
) {
132 lsp_remove_frags(lsp
->lspu
.frags
,
133 lsp
->area
->lspdb
[lsp
->level
- 1]);
134 list_delete(&lsp
->lspu
.frags
);
137 if (lsp
->lspu
.zero_lsp
138 && lsp
->lspu
.zero_lsp
->lspu
.frags
) {
139 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
143 isis_spf_schedule(lsp
->area
, lsp
->level
);
146 stream_free(lsp
->pdu
);
147 XFREE(MTYPE_ISIS_LSP
, lsp
);
150 void lsp_db_destroy(dict_t
*lspdb
)
152 dnode_t
*dnode
, *next
;
153 struct isis_lsp
*lsp
;
155 dnode
= dict_first(lspdb
);
157 next
= dict_next(lspdb
, dnode
);
158 lsp
= dnode_get(dnode
);
160 dict_delete_free(lspdb
, dnode
);
170 * Remove all the frags belonging to the given lsp
172 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
)
175 struct listnode
*lnode
, *lnnode
;
176 struct isis_lsp
*lsp
;
178 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
179 dnode
= dict_lookup(lspdb
, lsp
->hdr
.lsp_id
);
181 dnode_destroy(dict_delete(lspdb
, dnode
));
185 void lsp_search_and_destroy(uint8_t *id
, dict_t
*lspdb
)
188 struct isis_lsp
*lsp
;
190 node
= dict_lookup(lspdb
, id
);
192 node
= dict_delete(lspdb
, node
);
193 lsp
= dnode_get(node
);
195 * If this is a zero lsp, remove all the frags now
197 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
199 lsp_remove_frags(lsp
->lspu
.frags
, lspdb
);
202 * else just remove this frag, from the zero lsps' frag
205 if (lsp
->lspu
.zero_lsp
206 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
207 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
216 * Compares a LSP to given values
217 * Params are given in net order
219 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
220 uint16_t checksum
, uint16_t rem_lifetime
)
222 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
223 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
224 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
225 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
227 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
228 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
230 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
231 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
232 lsp
->hdr
.rem_lifetime
);
234 "ISIS-Snp (%s): is equal to ours seq 0x%08" PRIx32
235 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
237 areatag
, seqno
, checksum
, rem_lifetime
);
243 * LSPs with identical checksums should only be treated as newer if:
244 * a) The current LSP has a remaining lifetime != 0 and the other LSP
246 * remaining lifetime == 0. In this case, we should participate in
248 * and should not treat the current LSP with remaining lifetime == 0
250 * b) The LSP has an incorrect checksum. In this case, we need to react
254 if (seqno
> lsp
->hdr
.seqno
255 || (seqno
== lsp
->hdr
.seqno
256 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
257 || lsp
->hdr
.checksum
!= checksum
))) {
258 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
260 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
261 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
263 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
264 checksum
, rem_lifetime
);
266 "ISIS-Snp (%s): is newer than ours seq 0x%08" PRIx32
267 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
269 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
270 lsp
->hdr
.rem_lifetime
);
274 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
275 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
276 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
277 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
278 checksum
, rem_lifetime
);
280 "ISIS-Snp (%s): is older than ours seq 0x%08" PRIx32
281 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
282 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
283 lsp
->hdr
.rem_lifetime
);
289 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
292 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
293 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
294 struct stream
*stream
= lsp
->pdu
;
295 size_t orig_getp
= 0, orig_endp
= 0;
298 orig_getp
= stream_get_getp(lsp
->pdu
);
299 orig_endp
= stream_get_endp(lsp
->pdu
);
302 stream_set_getp(lsp
->pdu
, 0);
303 stream_set_endp(lsp
->pdu
, 0);
305 fill_fixed_hdr(pdu_type
, stream
);
308 *len_pointer
= stream_get_endp(stream
);
309 stream_putw(stream
, hdr
->pdu_len
);
310 stream_putw(stream
, hdr
->rem_lifetime
);
311 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
312 stream_putl(stream
, hdr
->seqno
);
313 stream_putw(stream
, hdr
->checksum
);
314 stream_putc(stream
, hdr
->lsp_bits
);
317 stream_set_endp(lsp
->pdu
, orig_endp
);
318 stream_set_getp(lsp
->pdu
, orig_getp
);
322 static void lsp_add_auth(struct isis_lsp
*lsp
)
324 struct isis_passwd
*passwd
;
325 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
326 : &lsp
->area
->domain_passwd
;
327 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
330 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
333 lsp
->tlvs
= isis_alloc_tlvs();
338 put_lsp_hdr(lsp
, &len_pointer
, false);
339 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
341 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
343 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
344 stream_get_endp(lsp
->pdu
) - 12, 12));
347 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
351 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
352 newseq
= lsp
->hdr
.seqno
+ 1;
356 lsp
->hdr
.seqno
= newseq
;
359 isis_spf_schedule(lsp
->area
, lsp
->level
);
362 static void lsp_purge_add_poi(struct isis_lsp
*lsp
,
363 const uint8_t *sender
)
365 if (!lsp
->area
->purge_originator
)
368 /* add purge originator identification */
370 lsp
->tlvs
= isis_alloc_tlvs();
371 isis_tlvs_set_purge_originator(lsp
->tlvs
, isis
->sysid
, sender
);
372 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
375 static void lsp_purge(struct isis_lsp
*lsp
, int level
,
376 const uint8_t *sender
)
380 stream_reset(lsp
->pdu
);
383 lsp
->hdr
.checksum
= 0;
384 lsp
->hdr
.rem_lifetime
= 0;
386 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
388 lsp_purge_add_poi(lsp
, sender
);
391 lsp_flood(lsp
, NULL
);
395 * Generates checksum for LSP and its frags
397 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
399 struct isis_lsp
*lsp
;
400 struct listnode
*node
;
402 lsp_inc_seqno(lsp0
, 0);
404 if (!lsp0
->lspu
.frags
)
407 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
409 lsp_inc_seqno(lsp
, 0);
411 lsp_purge(lsp
, lsp0
->level
, NULL
);
417 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
419 uint8_t lsp_bits
= 0;
420 if (level
== IS_LEVEL_1
)
421 lsp_bits
= IS_LEVEL_1
;
423 lsp_bits
= IS_LEVEL_1_AND_2
;
425 lsp_bits
|= overload_bit
;
427 lsp_bits
|= attached_bit
;
431 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
432 struct isis_tlvs
*tlvs
, struct stream
*stream
,
433 struct isis_area
*area
, int level
)
435 /* free the old lsp data */
438 /* copying only the relevant part of our stream */
439 if (lsp
->pdu
!= NULL
)
440 stream_free(lsp
->pdu
);
441 lsp
->pdu
= stream_dup(stream
);
443 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
446 lsp
->age_out
= ZERO_AGE_LIFETIME
;
447 lsp
->installed
= time(NULL
);
451 if (area
->dynhostname
&& lsp
->tlvs
->hostname
452 && lsp
->hdr
.rem_lifetime
) {
453 isis_dynhn_insert(lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
454 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
)
463 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
465 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
466 /* zero lsp -> create list to store fragments */
467 lsp
->lspu
.frags
= list_new();
469 /* fragment -> set backpointer and add to zero lsps list */
471 lsp
->lspu
.zero_lsp
= lsp0
;
472 listnode_add(lsp0
->lspu
.frags
, lsp
);
476 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
477 struct isis_tlvs
*tlvs
, struct stream
*stream
,
478 struct isis_area
*area
, int level
, bool confusion
)
483 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
484 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
490 lsp_purge(lsp
, level
, NULL
);
492 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
495 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
496 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
497 struct isis_lsp
*lsp0
;
499 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
500 LSP_FRAGMENT(lspid
) = 0;
501 lsp0
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
503 lsp_link_fragment(lsp
, lsp0
);
507 isis_spf_schedule(lsp
->area
, lsp
->level
);
510 /* creation of LSP directly from what we received */
511 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
512 struct isis_tlvs
*tlvs
,
513 struct stream
*stream
, struct isis_lsp
*lsp0
,
514 struct isis_area
*area
, int level
)
516 struct isis_lsp
*lsp
;
518 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
519 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
520 lsp_link_fragment(lsp
, lsp0
);
525 static void lsp_adjust_stream(struct isis_lsp
*lsp
)
528 if (STREAM_SIZE(lsp
->pdu
) == LLC_LEN
+ lsp
->area
->lsp_mtu
)
530 stream_free(lsp
->pdu
);
533 lsp
->pdu
= stream_new(LLC_LEN
+ lsp
->area
->lsp_mtu
);
536 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
537 uint16_t rem_lifetime
, uint32_t seqno
,
538 uint8_t lsp_bits
, uint16_t checksum
,
539 struct isis_lsp
*lsp0
, int level
)
541 struct isis_lsp
*lsp
;
543 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
546 lsp_adjust_stream(lsp
);
548 /* Minimal LSP PDU size */
549 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
550 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
551 lsp
->hdr
.checksum
= checksum
;
552 lsp
->hdr
.seqno
= seqno
;
553 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
554 lsp
->hdr
.lsp_bits
= lsp_bits
;
556 lsp
->age_out
= ZERO_AGE_LIFETIME
;
557 lsp_link_fragment(lsp
, lsp0
);
558 put_lsp_hdr(lsp
, NULL
, false);
560 if (isis
->debugs
& DEBUG_EVENTS
)
561 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
562 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
563 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
569 void lsp_insert(struct isis_lsp
*lsp
, dict_t
*lspdb
)
571 dict_alloc_insert(lspdb
, lsp
->hdr
.lsp_id
, lsp
);
573 isis_spf_schedule(lsp
->area
, lsp
->level
);
577 * Build a list of LSPs with non-zero ht bounded by start and stop ids
579 void lsp_build_list_nonzero_ht(uint8_t *start_id
, uint8_t *stop_id
,
580 struct list
*list
, dict_t
*lspdb
)
582 dnode_t
*first
, *last
, *curr
;
584 first
= dict_lower_bound(lspdb
, start_id
);
588 last
= dict_upper_bound(lspdb
, stop_id
);
592 if (((struct isis_lsp
*)(curr
->dict_data
))->hdr
.rem_lifetime
)
593 listnode_add(list
, first
->dict_data
);
596 curr
= dict_next(lspdb
, curr
);
598 && ((struct isis_lsp
*)(curr
->dict_data
))->hdr
.rem_lifetime
)
599 listnode_add(list
, curr
->dict_data
);
607 static void lsp_set_time(struct isis_lsp
*lsp
)
611 if (lsp
->hdr
.rem_lifetime
== 0) {
612 if (lsp
->age_out
> 0)
617 lsp
->hdr
.rem_lifetime
--;
618 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
619 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
622 static void lspid_print(uint8_t *lsp_id
, uint8_t *trg
, char dynhost
, char frag
)
624 struct isis_dynhn
*dyn
= NULL
;
625 uint8_t id
[SYSID_STRLEN
];
628 dyn
= dynhn_find_by_id(lsp_id
);
633 sprintf((char *)id
, "%.14s", dyn
->hostname
);
634 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
635 sprintf((char *)id
, "%.14s", cmd_hostname_get());
637 memcpy(id
, sysid_print(lsp_id
), 15);
639 sprintf((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
640 LSP_FRAGMENT(lsp_id
));
642 sprintf((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
645 /* Convert the lsp attribute bits to attribute string */
646 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
653 if (buf_size
< 2 * 3)
656 /* we only focus on the default metric */
657 pos
+= sprintf(pos
, "%d/",
658 ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits
) ? 1 : 0);
660 pos
+= sprintf(pos
, "%d/",
661 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
663 sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
668 /* this function prints the lsp on show isis database */
669 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
675 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, dynhost
, 1);
676 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
677 vty_out(vty
, "%5" PRIu16
" ", lsp
->hdr
.pdu_len
);
678 vty_out(vty
, "0x%08" PRIx32
" ", lsp
->hdr
.seqno
);
679 vty_out(vty
, "0x%04" PRIx16
" ", lsp
->hdr
.checksum
);
680 if (lsp
->hdr
.rem_lifetime
== 0) {
681 snprintf(age_out
, 8, "(%d)", lsp
->age_out
);
683 vty_out(vty
, "%7s ", age_out
);
685 vty_out(vty
, " %5" PRIu16
" ", lsp
->hdr
.rem_lifetime
);
686 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
689 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
691 lsp_print(lsp
, vty
, dynhost
);
693 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
697 /* print all the lsps info in the local lspdb */
698 int lsp_print_all(struct vty
*vty
, dict_t
*lspdb
, char detail
, char dynhost
)
701 dnode_t
*node
= dict_first(lspdb
), *next
;
704 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
705 while (node
!= NULL
) {
706 /* I think it is unnecessary, so I comment it out */
707 /* dict_contains (lspdb, node); */
708 next
= dict_next(lspdb
, node
);
709 lsp_print(dnode_get(node
), vty
, dynhost
);
713 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
714 while (node
!= NULL
) {
715 next
= dict_next(lspdb
, node
);
716 lsp_print_detail(dnode_get(node
), vty
, dynhost
);
725 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
727 uint16_t rem_lifetime
;
729 /* Add jitter to configured LSP lifetime */
731 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
733 /* No jitter if the max refresh will be less than configure gen interval
735 /* N.B. this calucation is acceptable since rem_lifetime is in
738 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
739 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
744 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
746 struct isis_area
*area
= lsp
->area
;
747 int level
= lsp
->level
;
748 uint16_t refresh_time
;
750 /* Add jitter to LSP refresh time */
752 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
754 /* RFC 4444 : make sure the refresh time is at least less than 300
755 * of the remaining lifetime and more than gen interval */
756 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
757 || refresh_time
> (rem_lifetime
- 300))
758 refresh_time
= rem_lifetime
- 300;
760 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
761 * we accept this violation to satisfy refresh_time <= rem_lifetime -
767 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
768 struct isis_area
*area
)
770 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
774 for (struct route_node
*rn
= route_top(er_table
); rn
;
775 rn
= route_next(rn
)) {
779 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
780 struct isis_ext_info
*info
= rn
->info
;
782 uint32_t metric
= info
->metric
;
783 if (metric
> MAX_WIDE_PATH_METRIC
)
784 metric
= MAX_WIDE_PATH_METRIC
;
785 if (area
->oldmetric
&& metric
> 0x3f)
789 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
792 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
,
797 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
798 struct isis_area
*area
)
800 struct route_table
*er_table
=
801 get_ext_reach(area
, AF_INET6
, lsp
->level
);
805 for (struct route_node
*rn
= route_top(er_table
); rn
;
806 rn
= srcdest_route_next(rn
)) {
809 struct isis_ext_info
*info
= rn
->info
;
811 struct prefix_ipv6
*p
, *src_p
;
812 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
813 (const struct prefix
**)&src_p
);
815 uint32_t metric
= info
->metric
;
816 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
817 metric
= MAX_WIDE_PATH_METRIC
;
819 if (!src_p
|| !src_p
->prefixlen
) {
820 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
821 isis_area_ipv6_topology(area
),
823 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
824 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
831 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
833 lsp_build_ext_reach_ipv4(lsp
, area
);
834 lsp_build_ext_reach_ipv6(lsp
, area
);
837 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
838 struct isis_area
*area
, int level
)
840 struct isis_lsp
*lsp
;
841 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
843 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
844 LSP_FRAGMENT(frag_id
) = frag_num
;
846 lsp
= lsp_search(frag_id
, area
->lspdb
[level
- 1]);
849 if (!lsp
->lspu
.zero_lsp
)
850 lsp_link_fragment(lsp
, lsp0
);
854 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
855 lsp_bits_generate(level
, area
->overload_bit
,
859 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
864 * Builds the LSP data part. This func creates a new frag whenever
865 * area->lsp_frag_threshold is exceeded.
867 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
869 int level
= lsp
->level
;
870 char buf
[PREFIX2STR_BUFFER
];
871 struct listnode
*node
;
872 struct isis_lsp
*frag
;
875 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
876 lsp_clear_data(frag
);
878 lsp
->tlvs
= isis_alloc_tlvs();
879 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
880 area
->area_tag
, level
);
882 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
887 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
889 /* Protocols Supported */
890 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
891 struct nlpids nlpids
= {.count
= 0};
892 if (area
->ip_circuits
> 0) {
894 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
896 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
899 if (area
->ipv6_circuits
> 0) {
901 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
903 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
906 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
909 if (area_is_mt(area
)) {
910 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
912 struct isis_area_mt_setting
**mt_settings
;
913 unsigned int mt_count
;
915 mt_settings
= area_mt_settings(area
, &mt_count
);
916 for (unsigned int i
= 0; i
< mt_count
; i
++) {
917 isis_tlvs_add_mt_router_info(
918 lsp
->tlvs
, mt_settings
[i
]->mtid
,
919 mt_settings
[i
]->overload
, false);
920 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
921 isis_mtid2str(mt_settings
[i
]->mtid
));
924 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
927 /* Dynamic Hostname */
928 if (area
->dynhostname
) {
929 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
930 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
931 area
->area_tag
, cmd_hostname_get());
933 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
937 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
938 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
940 * LSP and this address is same as router id. */
941 if (isis
->router_id
!= 0) {
942 struct in_addr id
= {.s_addr
= isis
->router_id
};
943 inet_ntop(AF_INET
, &id
, buf
, sizeof(buf
));
944 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
945 area
->area_tag
, buf
);
946 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
948 /* Exactly same data is put into TE router ID TLV, but only if
950 * TLV's are in use. */
951 if (area
->newmetric
) {
954 "ISIS (%s): Adding router ID also as TE router ID tlv.",
956 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
959 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
963 lsp_debug("ISIS (%s): Adding circuit specific information.",
968 "ISIS (%s): Adding tier %" PRIu8
" spine-leaf-extension tlv.",
969 area
->area_tag
, fabricd_tier(area
));
970 isis_tlvs_add_spine_leaf(lsp
->tlvs
, fabricd_tier(area
), true,
971 false, false, false);
974 struct isis_circuit
*circuit
;
975 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
976 if (!circuit
->interface
)
978 "ISIS (%s): Processing %s circuit %p with unknown interface",
980 circuit_type2string(circuit
->circ_type
),
983 lsp_debug("ISIS (%s): Processing %s circuit %s",
985 circuit_type2string(circuit
->circ_type
),
986 circuit
->interface
->name
);
988 if (circuit
->state
!= C_STATE_UP
) {
989 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
994 uint32_t metric
= area
->oldmetric
995 ? circuit
->metric
[level
- 1]
996 : circuit
->te_metric
[level
- 1];
998 if (circuit
->ip_router
&& circuit
->ip_addrs
999 && circuit
->ip_addrs
->count
> 0) {
1001 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1003 struct listnode
*ipnode
;
1004 struct prefix_ipv4
*ipv4
;
1005 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
1007 if (area
->oldmetric
) {
1009 "ISIS (%s): Adding old-style IP reachability for %s",
1011 prefix2str(ipv4
, buf
,
1013 isis_tlvs_add_oldstyle_ip_reach(
1014 lsp
->tlvs
, ipv4
, metric
);
1017 if (area
->newmetric
) {
1019 "ISIS (%s): Adding te-style IP reachability for %s",
1021 prefix2str(ipv4
, buf
,
1023 isis_tlvs_add_extended_ip_reach(
1024 lsp
->tlvs
, ipv4
, metric
);
1029 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1030 && circuit
->ipv6_non_link
->count
> 0) {
1031 struct listnode
*ipnode
;
1032 struct prefix_ipv6
*ipv6
;
1033 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1036 "ISIS (%s): Adding IPv6 reachability for %s",
1038 prefix2str(ipv6
, buf
, sizeof(buf
)));
1039 isis_tlvs_add_ipv6_reach(
1041 isis_area_ipv6_topology(area
), ipv6
,
1046 switch (circuit
->circ_type
) {
1047 case CIRCUIT_T_BROADCAST
:
1048 if (level
& circuit
->is_type
) {
1050 (level
== IS_LEVEL_1
)
1051 ? circuit
->u
.bc
.l1_desig_is
1052 : circuit
->u
.bc
.l2_desig_is
;
1054 if (LSP_PSEUDO_ID(ne_id
)) {
1055 if (area
->oldmetric
) {
1057 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1060 LSP_PSEUDO_ID(ne_id
));
1061 isis_tlvs_add_oldstyle_reach(
1065 if (area
->newmetric
) {
1066 uint8_t subtlvs
[256];
1069 if (IS_MPLS_TE(isisMplsTE
)
1070 && circuit
->interface
1072 circuit
->interface
))
1073 subtlv_len
= add_te_subtlvs(
1081 level
, ne_id
, metric
,
1082 subtlvs
, subtlv_len
);
1087 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1091 case CIRCUIT_T_P2P
: {
1092 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1093 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1094 && (level
& nei
->circuit_t
)) {
1096 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1097 LSP_PSEUDO_ID(ne_id
) = 0;
1099 if (area
->oldmetric
) {
1101 "ISIS (%s): Adding old-style is reach for %s",
1103 sysid_print(ne_id
));
1104 isis_tlvs_add_oldstyle_reach(
1105 lsp
->tlvs
, ne_id
, metric
);
1107 if (area
->newmetric
) {
1108 uint8_t subtlvs
[256];
1111 if (IS_MPLS_TE(isisMplsTE
)
1112 && circuit
->interface
!= NULL
1114 circuit
->interface
))
1115 /* Update Local and Remote IP
1116 * address for MPLS TE circuit
1118 /* NOTE sure that it is the
1119 * pertinent place for that
1121 /* Local IP address could be
1122 * updated in isis_circuit.c -
1123 * isis_circuit_add_addr() */
1124 /* But, where update remote IP
1125 * address ? in isis_pdu.c -
1126 * process_p2p_hello() ? */
1128 /* Add SubTLVs & Adjust real
1129 * size of SubTLVs */
1130 subtlv_len
= add_te_subtlvs(
1131 subtlvs
, circuit
->mtc
);
1133 /* Or keep only TE metric with
1134 * no SubTLVs if MPLS_TE is off
1138 uint32_t neighbor_metric
;
1139 if (fabricd_tier(area
) == 0) {
1140 neighbor_metric
= 0xffe;
1142 neighbor_metric
= metric
;
1145 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1146 ne_id
, neighbor_metric
,
1147 subtlvs
, subtlv_len
);
1151 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1155 case CIRCUIT_T_LOOPBACK
:
1158 zlog_warn("lsp_area_create: unknown circuit type");
1162 lsp_build_ext_reach(lsp
, area
);
1164 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1167 lsp_adjust_stream(lsp
);
1169 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1170 lsp_clear_data(lsp
);
1172 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1174 zlog_warn("BUG: could not fragment own LSP:");
1175 log_multiline(LOG_WARNING
, " ", "%s",
1176 isis_format_tlvs(tlvs
));
1177 isis_free_tlvs(tlvs
);
1180 isis_free_tlvs(tlvs
);
1182 bool fragment_overflow
= false;
1184 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1185 if (node
!= listhead(fragments
)) {
1186 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1187 if (!fragment_overflow
) {
1188 fragment_overflow
= true;
1190 "ISIS (%s): Too much information for 256 fragments",
1193 isis_free_tlvs(tlvs
);
1197 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1199 lsp_adjust_stream(frag
);
1204 list_delete(&fragments
);
1205 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1211 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1213 int lsp_generate(struct isis_area
*area
, int level
)
1215 struct isis_lsp
*oldlsp
, *newlsp
;
1216 uint32_t seq_num
= 0;
1217 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1218 uint16_t rem_lifetime
, refresh_time
;
1220 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1223 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1224 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1226 /* only builds the lsp if the area shares the level */
1227 oldlsp
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
1229 /* FIXME: we should actually initiate a purge */
1230 seq_num
= oldlsp
->hdr
.seqno
;
1231 lsp_search_and_destroy(oldlsp
->hdr
.lsp_id
,
1232 area
->lspdb
[level
- 1]);
1234 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1236 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1237 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1239 newlsp
->area
= area
;
1240 newlsp
->own_lsp
= 1;
1242 lsp_insert(newlsp
, area
->lspdb
[level
- 1]);
1243 /* build_lsp_data (newlsp, area); */
1244 lsp_build(newlsp
, area
);
1245 /* time to calculate our checksum */
1246 lsp_seqno_update(newlsp
);
1247 newlsp
->last_generated
= time(NULL
);
1248 lsp_flood(newlsp
, NULL
);
1250 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1252 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
1253 area
->lsp_regenerate_pending
[level
- 1] = 0;
1254 if (level
== IS_LEVEL_1
)
1255 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
1256 &area
->t_lsp_refresh
[level
- 1]);
1257 else if (level
== IS_LEVEL_2
)
1258 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
1259 &area
->t_lsp_refresh
[level
- 1]);
1261 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1262 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1263 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1264 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1265 area
->area_tag
, level
,
1266 rawlspid_print(newlsp
->hdr
.lsp_id
),
1267 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1268 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1272 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1273 area
->area_tag
, level
);
1279 * Search own LSPs, update holding time and flood
1281 static int lsp_regenerate(struct isis_area
*area
, int level
)
1284 struct isis_lsp
*lsp
, *frag
;
1285 struct listnode
*node
;
1286 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1287 uint16_t rem_lifetime
, refresh_time
;
1289 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1292 lspdb
= area
->lspdb
[level
- 1];
1294 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1295 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1297 lsp
= lsp_search(lspid
, lspdb
);
1300 flog_err(EC_LIB_DEVELOPMENT
,
1301 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1302 area
->area_tag
, level
);
1306 lsp_clear_data(lsp
);
1307 lsp_build(lsp
, area
);
1308 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1309 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1310 lsp
->last_generated
= time(NULL
);
1311 lsp_flood(lsp
, NULL
);
1312 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1313 frag
->hdr
.lsp_bits
= lsp_bits_generate(
1314 level
, area
->overload_bit
, area
->attached_bit
);
1315 /* Set the lifetime values of all the fragments to the same
1317 * so that no fragment expires before the lsp is refreshed.
1319 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1320 frag
->age_out
= ZERO_AGE_LIFETIME
;
1321 lsp_flood(frag
, NULL
);
1323 lsp_seqno_update(lsp
);
1325 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1326 if (level
== IS_LEVEL_1
)
1327 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
1328 &area
->t_lsp_refresh
[level
- 1]);
1329 else if (level
== IS_LEVEL_2
)
1330 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
1331 &area
->t_lsp_refresh
[level
- 1]);
1332 area
->lsp_regenerate_pending
[level
- 1] = 0;
1334 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1336 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1337 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1338 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1339 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1340 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1341 lsp
->hdr
.rem_lifetime
, refresh_time
);
1344 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1345 area
->area_tag
, level
);
1351 * Something has changed or periodic refresh -> regenerate LSP
1353 static int lsp_l1_refresh(struct thread
*thread
)
1355 struct isis_area
*area
;
1357 area
= THREAD_ARG(thread
);
1360 area
->t_lsp_refresh
[0] = NULL
;
1361 area
->lsp_regenerate_pending
[0] = 0;
1363 if ((area
->is_type
& IS_LEVEL_1
) == 0)
1367 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
1369 return lsp_regenerate(area
, IS_LEVEL_1
);
1372 static int lsp_l2_refresh(struct thread
*thread
)
1374 struct isis_area
*area
;
1376 area
= THREAD_ARG(thread
);
1379 area
->t_lsp_refresh
[1] = NULL
;
1380 area
->lsp_regenerate_pending
[1] = 0;
1382 if ((area
->is_type
& IS_LEVEL_2
) == 0)
1386 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
1388 return lsp_regenerate(area
, IS_LEVEL_2
);
1391 int lsp_regenerate_schedule(struct isis_area
*area
, int level
, int all_pseudo
)
1393 struct isis_lsp
*lsp
;
1394 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1397 struct listnode
*cnode
;
1398 struct isis_circuit
*circuit
;
1405 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
1406 area
->area_tag
, circuit_t2string(level
),
1407 all_pseudo
? "" : "not ");
1409 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1410 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1413 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1414 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1418 "ISIS (%s): Checking whether L%d needs to be scheduled",
1419 area
->area_tag
, lvl
);
1421 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
1422 struct timeval remain
= thread_timer_remain(
1423 area
->t_lsp_refresh
[lvl
- 1]);
1425 "ISIS (%s): Regeneration is already pending, nothing todo."
1426 " (Due in %lld.%03lld seconds)",
1427 area
->area_tag
, (long long)remain
.tv_sec
,
1428 (long long)remain
.tv_usec
/ 1000);
1432 lsp
= lsp_search(id
, area
->lspdb
[lvl
- 1]);
1435 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1441 * Throttle avoidance
1444 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1445 area
->area_tag
, (long long)lsp
->last_generated
,
1447 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1448 diff
= now
- lsp
->last_generated
;
1449 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
1451 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1453 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1454 area
->area_tag
, timeout
);
1457 * lsps are not regenerated if lsp_regenerate function
1459 * directly. However if the lsp_regenerate call is
1461 * later execution it works.
1465 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1466 " Scheduling for execution in %ld ms.",
1467 area
->area_tag
, timeout
);
1470 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1471 if (lvl
== IS_LEVEL_1
) {
1472 thread_add_timer_msec(master
, lsp_l1_refresh
, area
,
1474 &area
->t_lsp_refresh
[lvl
- 1]);
1475 } else if (lvl
== IS_LEVEL_2
) {
1476 thread_add_timer_msec(master
, lsp_l2_refresh
, area
,
1478 &area
->t_lsp_refresh
[lvl
- 1]);
1483 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1484 lsp_regenerate_schedule_pseudo(circuit
, level
);
1491 * Funcs for pseudonode LSPs
1495 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1497 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1500 struct isis_adjacency
*adj
;
1501 struct list
*adj_list
;
1502 struct listnode
*node
;
1503 struct isis_area
*area
= circuit
->area
;
1505 lsp_clear_data(lsp
);
1506 lsp
->tlvs
= isis_alloc_tlvs();
1508 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1509 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1510 circuit
->interface
->name
, level
);
1513 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1515 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
1518 * add self to IS neighbours
1520 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1522 memcpy(ne_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1523 LSP_PSEUDO_ID(ne_id
) = 0;
1525 if (circuit
->area
->oldmetric
) {
1526 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1528 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1529 area
->area_tag
, sysid_print(ne_id
),
1530 LSP_PSEUDO_ID(ne_id
));
1532 if (circuit
->area
->newmetric
) {
1533 isis_tlvs_add_extended_reach(lsp
->tlvs
, ISIS_MT_IPV4_UNICAST
,
1536 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1537 area
->area_tag
, sysid_print(ne_id
),
1538 LSP_PSEUDO_ID(ne_id
));
1541 adj_list
= list_new();
1542 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1544 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1545 if (!(adj
->level
& level
)) {
1547 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1548 area
->area_tag
, sysid_print(adj
->sysid
));
1552 if (!(level
== IS_LEVEL_1
1553 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1554 && !(level
== IS_LEVEL_1
1555 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1556 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1557 && !(level
== IS_LEVEL_2
1558 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1560 "ISIS (%s): Ignoring neighbor %s, level does not match",
1561 area
->area_tag
, sysid_print(adj
->sysid
));
1565 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1566 if (circuit
->area
->oldmetric
) {
1567 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1569 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1570 area
->area_tag
, sysid_print(ne_id
),
1571 LSP_PSEUDO_ID(ne_id
));
1573 if (circuit
->area
->newmetric
) {
1574 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1575 ISIS_MT_IPV4_UNICAST
,
1578 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1579 area
->area_tag
, sysid_print(ne_id
),
1580 LSP_PSEUDO_ID(ne_id
));
1583 list_delete(&adj_list
);
1587 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1589 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1590 struct isis_lsp
*lsp
;
1591 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1592 uint16_t rem_lifetime
, refresh_time
;
1594 if ((circuit
->is_type
& level
) != level
1595 || (circuit
->state
!= C_STATE_UP
)
1596 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1597 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1600 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1601 LSP_FRAGMENT(lsp_id
) = 0;
1602 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1605 * If for some reason have a pseudo LSP in the db already -> regenerate
1607 if (lsp_search(lsp_id
, lspdb
))
1608 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1610 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1611 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1612 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1613 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
1615 lsp
->area
= circuit
->area
;
1617 lsp_build_pseudo(lsp
, circuit
, level
);
1620 lsp_insert(lsp
, lspdb
);
1621 lsp_flood(lsp
, NULL
);
1623 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1624 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1625 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1626 if (level
== IS_LEVEL_1
)
1628 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1629 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1630 else if (level
== IS_LEVEL_2
)
1632 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1633 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1635 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1637 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1638 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1639 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1640 circuit
->area
->area_tag
, level
,
1641 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1642 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1643 lsp
->hdr
.rem_lifetime
, refresh_time
);
1649 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1651 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1652 struct isis_lsp
*lsp
;
1653 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1654 uint16_t rem_lifetime
, refresh_time
;
1656 if ((circuit
->is_type
& level
) != level
1657 || (circuit
->state
!= C_STATE_UP
)
1658 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1659 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1662 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1663 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1664 LSP_FRAGMENT(lsp_id
) = 0;
1666 lsp
= lsp_search(lsp_id
, lspdb
);
1669 flog_err(EC_LIB_DEVELOPMENT
,
1670 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1671 rawlspid_print(lsp_id
));
1675 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1676 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1677 lsp_build_pseudo(lsp
, circuit
, level
);
1678 lsp_inc_seqno(lsp
, 0);
1679 lsp
->last_generated
= time(NULL
);
1680 lsp_flood(lsp
, NULL
);
1682 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1683 if (level
== IS_LEVEL_1
)
1685 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1686 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1687 else if (level
== IS_LEVEL_2
)
1689 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1690 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1692 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1694 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1695 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1696 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1697 circuit
->area
->area_tag
, level
,
1698 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1699 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1700 lsp
->hdr
.rem_lifetime
, refresh_time
);
1707 * Something has changed or periodic refresh -> regenerate pseudo LSP
1709 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1711 struct isis_circuit
*circuit
;
1712 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1714 circuit
= THREAD_ARG(thread
);
1716 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1717 circuit
->lsp_regenerate_pending
[0] = 0;
1719 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1720 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1721 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1722 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1723 LSP_FRAGMENT(id
) = 0;
1724 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1728 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1731 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1733 struct isis_circuit
*circuit
;
1734 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1736 circuit
= THREAD_ARG(thread
);
1738 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1739 circuit
->lsp_regenerate_pending
[1] = 0;
1741 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1742 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1743 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1744 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1745 LSP_FRAGMENT(id
) = 0;
1746 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1750 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1753 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1755 struct isis_lsp
*lsp
;
1756 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1760 struct isis_area
*area
= circuit
->area
;
1762 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1763 || circuit
->state
!= C_STATE_UP
)
1767 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1768 area
->area_tag
, circuit_t2string(level
),
1769 circuit
->interface
->name
);
1771 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1772 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1773 LSP_FRAGMENT(lsp_id
) = 0;
1776 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1778 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1779 area
->area_tag
, lvl
);
1781 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1782 sched_debug("ISIS (%s): Level is not active on circuit",
1787 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1789 "ISIS (%s): This IS is not DR, nothing to do.",
1794 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1795 struct timeval remain
= thread_timer_remain(
1796 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1798 "ISIS (%s): Regenerate is already pending, nothing todo."
1799 " (Due in %lld.%03lld seconds)",
1800 area
->area_tag
, (long long)remain
.tv_sec
,
1801 (long long)remain
.tv_usec
/ 1000);
1805 lsp
= lsp_search(lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
1808 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1814 * Throttle avoidance
1817 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1818 area
->area_tag
, (long long)lsp
->last_generated
,
1820 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1821 diff
= now
- lsp
->last_generated
;
1822 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1824 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1827 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1828 area
->area_tag
, timeout
);
1832 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1833 " Scheduling for execution in %ld ms.",
1834 area
->area_tag
, timeout
);
1837 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1839 if (lvl
== IS_LEVEL_1
) {
1840 thread_add_timer_msec(
1841 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1842 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1843 } else if (lvl
== IS_LEVEL_2
) {
1844 thread_add_timer_msec(
1845 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1846 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1854 * Walk through LSPs for an area
1855 * - set remaining lifetime
1857 int lsp_tick(struct thread
*thread
)
1859 struct isis_area
*area
;
1860 struct isis_lsp
*lsp
;
1861 dnode_t
*dnode
, *dnode_next
;
1863 uint16_t rem_lifetime
;
1864 bool fabricd_sync_incomplete
= false;
1866 area
= THREAD_ARG(thread
);
1868 area
->t_tick
= NULL
;
1869 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1871 struct isis_circuit
*fabricd_init_c
= fabricd_initial_sync_circuit(area
);
1874 * Remove LSPs which have aged out
1876 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1877 if (area
->lspdb
[level
] && dict_count(area
->lspdb
[level
]) > 0) {
1878 for (dnode
= dict_first(area
->lspdb
[level
]);
1879 dnode
!= NULL
; dnode
= dnode_next
) {
1881 dict_next(area
->lspdb
[level
], dnode
);
1882 lsp
= dnode_get(dnode
);
1885 * The lsp rem_lifetime is kept at 0 for MaxAge
1887 * ZeroAgeLifetime depending on explicit purge
1889 * natural age out. So schedule spf only once
1891 * the first time rem_lifetime becomes 0.
1893 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1897 * Schedule may run spf which should be done
1899 * the lsp rem_lifetime becomes 0 for the first
1901 * ISO 10589 - 7.3.16.4 first paragraph.
1903 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
1904 /* 7.3.16.4 a) set SRM flags on all */
1905 /* 7.3.16.4 b) retain only the header */
1906 if (lsp
->area
->purge_originator
)
1907 lsp_purge(lsp
, lsp
->level
, NULL
);
1909 lsp_flood(lsp
, NULL
);
1910 /* 7.3.16.4 c) record the time to purge
1912 isis_spf_schedule(lsp
->area
, lsp
->level
);
1915 if (lsp
->age_out
== 0) {
1917 "ISIS-Upd (%s): L%u LSP %s seq "
1918 "0x%08" PRIx32
" aged out",
1919 area
->area_tag
, lsp
->level
,
1920 rawlspid_print(lsp
->hdr
.lsp_id
),
1924 dict_delete_free(area
->lspdb
[level
],
1928 if (fabricd_init_c
&& lsp
) {
1929 fabricd_sync_incomplete
|=
1930 ISIS_CHECK_FLAG(lsp
->SSNflags
,
1938 && !fabricd_sync_incomplete
1939 && !isis_tx_queue_len(fabricd_init_c
->tx_queue
)) {
1940 fabricd_initial_sync_finish(area
);
1946 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
1948 struct isis_lsp
*lsp
;
1950 lsp
= lsp_search(id
, circuit
->area
->lspdb
[level
- 1]);
1954 lsp_purge(lsp
, level
, NULL
);
1958 * Purge own LSP that is received and we don't have.
1959 * -> Do as in 7.3.16.4
1961 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
1962 struct isis_area
*area
)
1964 struct isis_lsp
*lsp
;
1967 * We need to create the LSP to be purged
1969 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
1972 lsp_adjust_stream(lsp
);
1973 lsp
->age_out
= ZERO_AGE_LIFETIME
;
1975 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
1976 lsp
->hdr
.rem_lifetime
= 0;
1978 lsp_purge_add_poi(lsp
, NULL
);
1982 lsp_insert(lsp
, area
->lspdb
[lsp
->level
- 1]);
1983 lsp_flood(lsp
, NULL
);
1988 void lsp_set_all_srmflags(struct isis_lsp
*lsp
, bool set
)
1990 struct listnode
*node
;
1991 struct isis_circuit
*circuit
;
1998 struct list
*circuit_list
= lsp
->area
->circuit_list
;
1999 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
2001 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
2004 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2009 void lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
)
2012 lsp_set_all_srmflags(lsp
, true);
2014 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2016 fabricd_lsp_flood(lsp
);
2020 static int lsp_handle_adj_state_change(struct isis_adjacency
*adj
)
2022 lsp_regenerate_schedule(adj
->circuit
->area
, IS_LEVEL_1
| IS_LEVEL_2
, 0);
2028 hook_register(isis_adj_state_change_hook
,
2029 lsp_handle_adj_state_change
);