1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - isis_lsp.c
6 * Copyright (C) 2001,2002 Sampo Saaristo
7 * Tampere University of Technology
8 * Institute of Communications Engineering
9 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
27 #include "srcdest_table.h"
28 #include "lib_errors.h"
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_common.h"
32 #include "isisd/isis_flags.h"
33 #include "isisd/isis_circuit.h"
34 #include "isisd/isisd.h"
35 #include "isisd/isis_lsp.h"
36 #include "isisd/isis_pdu.h"
37 #include "isisd/isis_dynhn.h"
38 #include "isisd/isis_misc.h"
39 #include "isisd/isis_csm.h"
40 #include "isisd/isis_adjacency.h"
41 #include "isisd/isis_spf.h"
42 #include "isisd/isis_mt.h"
43 #include "isisd/isis_tlvs.h"
44 #include "isisd/isis_te.h"
45 #include "isisd/isis_sr.h"
46 #include "isisd/fabricd.h"
47 #include "isisd/isis_tx_queue.h"
48 #include "isisd/isis_nb.h"
50 DEFINE_MTYPE_STATIC(ISISD
, ISIS_LSP
, "ISIS LSP");
52 static void lsp_refresh(struct event
*thread
);
53 static void lsp_l1_refresh_pseudo(struct event
*thread
);
54 static void lsp_l2_refresh_pseudo(struct event
*thread
);
56 static void lsp_destroy(struct isis_lsp
*lsp
);
58 static bool device_startup
;
60 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
62 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
65 int lspdb_compare(const struct isis_lsp
*a
, const struct isis_lsp
*b
)
67 return memcmp(a
->hdr
.lsp_id
, b
->hdr
.lsp_id
, sizeof(a
->hdr
.lsp_id
));
70 void lsp_db_init(struct lspdb_head
*head
)
75 void lsp_db_fini(struct lspdb_head
*head
)
79 while ((lsp
= lspdb_pop(head
)))
84 struct isis_lsp
*lsp_search(struct lspdb_head
*head
, const uint8_t *id
)
86 struct isis_lsp searchfor
;
87 memcpy(searchfor
.hdr
.lsp_id
, id
, sizeof(searchfor
.hdr
.lsp_id
));
89 return lspdb_find(head
, &searchfor
);
92 static void lsp_clear_data(struct isis_lsp
*lsp
)
97 isis_free_tlvs(lsp
->tlvs
);
101 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
);
103 static void lsp_destroy(struct isis_lsp
*lsp
)
105 struct listnode
*cnode
;
106 struct isis_circuit
*circuit
;
111 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
, circuit
))
112 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
114 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
116 isis_te_lsp_event(lsp
, LSP_DEL
);
120 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
121 if (lsp
->lspu
.frags
) {
122 lsp_remove_frags(&lsp
->area
->lspdb
[lsp
->level
- 1],
124 list_delete(&lsp
->lspu
.frags
);
127 if (lsp
->lspu
.zero_lsp
128 && lsp
->lspu
.zero_lsp
->lspu
.frags
) {
129 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
133 isis_spf_schedule(lsp
->area
, lsp
->level
);
136 stream_free(lsp
->pdu
);
138 fabricd_lsp_free(lsp
);
139 XFREE(MTYPE_ISIS_LSP
, lsp
);
143 * Remove all the frags belonging to the given lsp
145 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
)
147 struct listnode
*lnode
, *lnnode
;
148 struct isis_lsp
*lsp
;
150 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
151 lsp
= lsp_search(head
, lsp
->hdr
.lsp_id
);
152 lspdb_del(head
, lsp
);
157 void lsp_search_and_destroy(struct lspdb_head
*head
, const uint8_t *id
)
159 struct isis_lsp
*lsp
;
161 lsp
= lsp_search(head
, id
);
163 lspdb_del(head
, lsp
);
165 * If this is a zero lsp, remove all the frags now
167 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
169 lsp_remove_frags(head
, lsp
->lspu
.frags
);
172 * else just remove this frag, from the zero lsps' frag
175 if (lsp
->lspu
.zero_lsp
176 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
177 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
185 * Compares a LSP to given values
186 * Params are given in net order
188 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
189 uint16_t checksum
, uint16_t rem_lifetime
)
191 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
192 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
193 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
194 if (IS_DEBUG_SNP_PACKETS
) {
196 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
197 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
198 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
199 lsp
->hdr
.rem_lifetime
);
201 "ISIS-Snp (%s): is equal to ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
202 areatag
, seqno
, checksum
, rem_lifetime
);
208 * LSPs with identical checksums should only be treated as newer if:
209 * a) The current LSP has a remaining lifetime != 0 and the other LSP
211 * remaining lifetime == 0. In this case, we should participate in
213 * and should not treat the current LSP with remaining lifetime == 0
215 * b) The LSP has an incorrect checksum. In this case, we need to react
219 if (seqno
> lsp
->hdr
.seqno
220 || (seqno
== lsp
->hdr
.seqno
221 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
222 || (lsp
->hdr
.checksum
!= checksum
223 && lsp
->hdr
.rem_lifetime
)))) {
224 if (IS_DEBUG_SNP_PACKETS
) {
226 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
227 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
228 checksum
, rem_lifetime
);
230 "ISIS-Snp (%s): is newer than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
231 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
232 lsp
->hdr
.rem_lifetime
);
236 if (IS_DEBUG_SNP_PACKETS
) {
237 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
238 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
239 checksum
, rem_lifetime
);
241 "ISIS-Snp (%s): is older than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
242 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
243 lsp
->hdr
.rem_lifetime
);
249 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
252 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
253 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
254 struct stream
*stream
= lsp
->pdu
;
255 size_t orig_getp
= 0, orig_endp
= 0;
258 orig_getp
= stream_get_getp(lsp
->pdu
);
259 orig_endp
= stream_get_endp(lsp
->pdu
);
262 stream_set_getp(lsp
->pdu
, 0);
263 stream_set_endp(lsp
->pdu
, 0);
265 fill_fixed_hdr(pdu_type
, stream
);
268 *len_pointer
= stream_get_endp(stream
);
269 stream_putw(stream
, hdr
->pdu_len
);
270 stream_putw(stream
, hdr
->rem_lifetime
);
271 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
272 stream_putl(stream
, hdr
->seqno
);
273 stream_putw(stream
, hdr
->checksum
);
274 stream_putc(stream
, hdr
->lsp_bits
);
277 stream_set_endp(lsp
->pdu
, orig_endp
);
278 stream_set_getp(lsp
->pdu
, orig_getp
);
282 static void lsp_add_auth(struct isis_lsp
*lsp
)
284 struct isis_passwd
*passwd
;
285 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
286 : &lsp
->area
->domain_passwd
;
287 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
290 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
293 lsp
->tlvs
= isis_alloc_tlvs();
298 put_lsp_hdr(lsp
, &len_pointer
, false);
299 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
301 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
303 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
304 stream_get_endp(lsp
->pdu
) - 12, 12));
307 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
311 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
312 newseq
= lsp
->hdr
.seqno
+ 1;
317 /* check for overflow */
318 if (newseq
< lsp
->hdr
.seqno
) {
319 /* send northbound notification */
320 lsp
->area
->lsp_exceeded_max_counter
++;
321 isis_notif_lsp_exceed_max(lsp
->area
, lsp
->hdr
.lsp_id
);
323 #endif /* ifndef FABRICD */
325 lsp
->hdr
.seqno
= newseq
;
328 isis_spf_schedule(lsp
->area
, lsp
->level
);
329 isis_te_lsp_event(lsp
, LSP_INC
);
332 static void lsp_purge_add_poi(struct isis_lsp
*lsp
,
333 const uint8_t *sender
)
335 if (lsp
->area
== NULL
)
338 if (!lsp
->area
->purge_originator
)
341 /* add purge originator identification */
343 lsp
->tlvs
= isis_alloc_tlvs();
344 isis_tlvs_set_purge_originator(lsp
->tlvs
, lsp
->area
->isis
->sysid
,
346 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
349 static void lsp_purge(struct isis_lsp
*lsp
, int level
,
350 const uint8_t *sender
)
354 stream_reset(lsp
->pdu
);
357 lsp
->hdr
.checksum
= 0;
358 lsp
->hdr
.rem_lifetime
= 0;
360 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
361 lsp
->area
->lsp_purge_count
[level
- 1]++;
363 lsp_purge_add_poi(lsp
, sender
);
366 lsp_flood(lsp
, NULL
);
370 * Generates checksum for LSP and its frags
372 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
374 struct isis_lsp
*lsp
;
375 struct listnode
*node
;
377 lsp_inc_seqno(lsp0
, 0);
379 if (!lsp0
->lspu
.frags
)
382 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
384 lsp_inc_seqno(lsp
, 0);
385 else if (lsp
->hdr
.rem_lifetime
) {
386 /* Purge should only be applied when the fragment has
387 * non-zero remaining lifetime.
389 lsp_purge(lsp
, lsp0
->level
, NULL
);
396 bool isis_level2_adj_up(struct isis_area
*area
)
398 struct listnode
*node
, *cnode
;
399 struct isis_circuit
*circuit
;
401 struct isis_adjacency
*adj
;
403 if (area
->is_type
== IS_LEVEL_1
)
406 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
)) {
407 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
408 adjdb
= circuit
->u
.bc
.adjdb
[1];
409 if (!adjdb
|| !adjdb
->count
)
412 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
)) {
413 if (adj
->level
!= ISIS_ADJ_LEVEL1
414 && adj
->adj_state
== ISIS_ADJ_UP
)
417 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
418 && circuit
->u
.p2p
.neighbor
) {
419 adj
= circuit
->u
.p2p
.neighbor
;
420 if (adj
->level
!= ISIS_ADJ_LEVEL1
421 && adj
->adj_state
== ISIS_ADJ_UP
)
430 * Unset the overload bit after the timer expires
432 void set_overload_on_start_timer(struct event
*thread
)
434 struct isis_area
*area
= EVENT_ARG(thread
);
437 area
->t_overload_on_startup_timer
= NULL
;
439 /* Check if set-overload-bit is not currently configured */
440 if (!area
->overload_configured
)
441 isis_area_overload_bit_set(area
, false);
444 static void isis_reset_attach_bit(struct isis_adjacency
*adj
)
446 struct isis_area
*area
= adj
->circuit
->area
;
447 struct lspdb_head
*head
;
448 struct isis_lsp
*lsp
;
449 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
452 * If an L2 adjacency changed its state in L-1-2 area, we have to:
453 * - set the attached bit in L1 LSPs if it's the first L2 adjacency
454 * - remove the attached bit in L1 LSPs if it's the last L2 adjacency
457 if (area
->is_type
!= IS_LEVEL_1_AND_2
|| adj
->level
== ISIS_ADJ_LEVEL1
)
460 if (!area
->attached_bit_send
)
463 head
= &area
->lspdb
[IS_LEVEL_1
- 1];
464 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
465 memcpy(lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
467 lsp
= lsp_search(head
, lspid
);
471 if (adj
->adj_state
== ISIS_ADJ_UP
472 && !(lsp
->hdr
.lsp_bits
& LSPBIT_ATT
)) {
473 sched_debug("ISIS (%s): adj going up regenerate lsp-bits",
475 lsp_regenerate_schedule(area
, IS_LEVEL_1
, 0);
476 } else if (adj
->adj_state
== ISIS_ADJ_DOWN
477 && (lsp
->hdr
.lsp_bits
& LSPBIT_ATT
)
478 && !isis_level2_adj_up(area
)) {
479 sched_debug("ISIS (%s): adj going down regenerate lsp-bits",
481 lsp_regenerate_schedule(area
, IS_LEVEL_1
, 0);
485 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
,
486 struct isis_area
*area
)
488 uint8_t lsp_bits
= 0;
489 if (area
->is_type
== IS_LEVEL_1
)
490 lsp_bits
= IS_LEVEL_1
;
492 lsp_bits
= IS_LEVEL_1_AND_2
;
494 lsp_bits
|= overload_bit
;
496 /* only set the attach bit if we are a level-1-2 router and this is
497 * a level-1 LSP and we have a level-2 adjacency up from another area
499 if (area
->is_type
== IS_LEVEL_1_AND_2
&& level
== IS_LEVEL_1
500 && attached_bit
&& isis_level2_adj_up(area
))
501 lsp_bits
|= LSPBIT_ATT
;
505 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
506 struct isis_tlvs
*tlvs
, struct stream
*stream
,
507 struct isis_area
*area
, int level
)
509 /* free the old lsp data */
512 /* copying only the relevant part of our stream */
513 if (lsp
->pdu
!= NULL
)
514 stream_free(lsp
->pdu
);
515 lsp
->pdu
= stream_dup(stream
);
517 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
520 lsp
->age_out
= ZERO_AGE_LIFETIME
;
521 lsp
->installed
= time(NULL
);
525 if (area
->dynhostname
&& lsp
->tlvs
->hostname
526 && lsp
->hdr
.rem_lifetime
) {
528 area
->isis
, lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
529 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
) == IS_LEVEL_1_AND_2
537 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
539 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
540 /* zero lsp -> create list to store fragments */
541 lsp
->lspu
.frags
= list_new();
543 /* fragment -> set backpointer and add to zero lsps list */
545 lsp
->lspu
.zero_lsp
= lsp0
;
546 listnode_add(lsp0
->lspu
.frags
, lsp
);
550 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
551 struct isis_tlvs
*tlvs
, struct stream
*stream
,
552 struct isis_area
*area
, int level
, bool confusion
)
557 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
558 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
564 lsp_purge(lsp
, level
, NULL
);
566 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
569 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
570 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
571 struct isis_lsp
*lsp0
;
573 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
574 LSP_FRAGMENT(lspid
) = 0;
575 lsp0
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
577 lsp_link_fragment(lsp
, lsp0
);
580 if (lsp
->hdr
.seqno
) {
581 isis_spf_schedule(lsp
->area
, lsp
->level
);
582 isis_te_lsp_event(lsp
, LSP_UPD
);
586 /* creation of LSP directly from what we received */
587 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
588 struct isis_tlvs
*tlvs
,
589 struct stream
*stream
, struct isis_lsp
*lsp0
,
590 struct isis_area
*area
, int level
)
592 struct isis_lsp
*lsp
;
594 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
595 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
596 lsp_link_fragment(lsp
, lsp0
);
601 static void lsp_adjust_stream(struct isis_lsp
*lsp
)
604 if (STREAM_SIZE(lsp
->pdu
) == LLC_LEN
+ lsp
->area
->lsp_mtu
)
606 stream_free(lsp
->pdu
);
609 lsp
->pdu
= stream_new(LLC_LEN
+ lsp
->area
->lsp_mtu
);
612 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
613 uint16_t rem_lifetime
, uint32_t seqno
,
614 uint8_t lsp_bits
, uint16_t checksum
,
615 struct isis_lsp
*lsp0
, int level
)
617 struct isis_lsp
*lsp
;
619 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
622 lsp_adjust_stream(lsp
);
624 /* Minimal LSP PDU size */
625 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
626 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
627 lsp
->hdr
.checksum
= checksum
;
628 lsp
->hdr
.seqno
= seqno
;
629 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
630 lsp
->hdr
.lsp_bits
= lsp_bits
;
632 lsp
->age_out
= ZERO_AGE_LIFETIME
;
633 lsp_link_fragment(lsp
, lsp0
);
634 put_lsp_hdr(lsp
, NULL
, false);
637 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
638 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
639 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
645 void lsp_insert(struct lspdb_head
*head
, struct isis_lsp
*lsp
)
647 lspdb_add(head
, lsp
);
648 if (lsp
->hdr
.seqno
) {
649 isis_spf_schedule(lsp
->area
, lsp
->level
);
650 isis_te_lsp_event(lsp
, LSP_ADD
);
655 * Build a list of LSPs with non-zero ht and seqno bounded by start and stop ids
657 void lsp_build_list_nonzero_ht(struct lspdb_head
*head
, const uint8_t *start_id
,
658 const uint8_t *stop_id
, struct list
*list
)
660 struct isis_lsp searchfor
;
661 struct isis_lsp
*lsp
, *start
;
663 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
665 start
= lspdb_find_gteq(head
, &searchfor
);
666 frr_each_from (lspdb
, head
, lsp
, start
) {
667 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
,
668 ISIS_SYS_ID_LEN
+ 2) > 0)
671 if (lsp
->hdr
.rem_lifetime
&& lsp
->hdr
.seqno
)
672 listnode_add(list
, lsp
);
676 static void lsp_set_time(struct isis_lsp
*lsp
)
680 if (lsp
->hdr
.rem_lifetime
== 0) {
681 if (lsp
->age_out
> 0)
686 lsp
->hdr
.rem_lifetime
--;
687 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
688 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
691 void lspid_print(uint8_t *lsp_id
, char *dest
, size_t dest_len
, char dynhost
,
692 char frag
, struct isis
*isis
)
694 struct isis_dynhn
*dyn
= NULL
;
695 char id
[SYSID_STRLEN
];
698 dyn
= dynhn_find_by_id(isis
, lsp_id
);
703 snprintf(id
, sizeof(id
), "%.14s", dyn
->hostname
);
704 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
705 snprintf(id
, sizeof(id
), "%.14s", cmd_hostname_get());
707 memcpy(id
, sysid_print(lsp_id
), 15);
710 snprintf(dest
, dest_len
, "%s.%02x-%02x", id
,
711 LSP_PSEUDO_ID(lsp_id
), LSP_FRAGMENT(lsp_id
));
713 snprintf(dest
, dest_len
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
716 /* Convert the lsp attribute bits to attribute string */
717 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
724 if (buf_size
< 2 * 3)
727 /* we only focus on the default metric */
728 pos
+= snprintf(pos
, buf_size
, "%d/",
729 ISIS_MASK_LSP_ATT_BITS(lsp_bits
) ? 1 : 0);
731 pos
+= snprintf(pos
, buf_size
, "%d/",
732 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
734 snprintf(pos
, buf_size
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
739 /* this function prints the lsp on show isis database */
740 void lsp_print_common(struct isis_lsp
*lsp
, struct vty
*vty
, struct json_object
*json
,
741 char dynhost
, struct isis
*isis
)
744 return lsp_print_json(lsp
, json
, dynhost
, isis
);
746 return lsp_print_vty(lsp
, vty
, dynhost
, isis
);
750 void lsp_print_json(struct isis_lsp
*lsp
, struct json_object
*json
,
751 char dynhost
, struct isis
*isis
)
756 json_object
*own_json
;
759 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, sizeof(LSPid
), dynhost
, 1, isis
);
760 own_json
= json_object_new_object();
761 json_object_object_add(json
, "lsp", own_json
);
762 json_object_string_add(own_json
, "id", LSPid
);
763 json_object_string_add(own_json
, "own", lsp
->own_lsp
? "*" : " ");
764 json_object_int_add(json
, "pdu-len", lsp
->hdr
.pdu_len
);
765 snprintfrr(buf
, sizeof(buf
), "0x%08x", lsp
->hdr
.seqno
);
766 json_object_string_add(json
, "seq-number", buf
);
767 snprintfrr(buf
, sizeof(buf
), "0x%04hx", lsp
->hdr
.checksum
);
768 json_object_string_add(json
, "chksum", buf
);
769 if (lsp
->hdr
.rem_lifetime
== 0) {
770 snprintf(age_out
, sizeof(age_out
), "(%d)", lsp
->age_out
);
772 json_object_string_add(json
, "holdtime", age_out
);
774 json_object_int_add(json
, "holdtime", lsp
->hdr
.rem_lifetime
);
776 json_object_string_add(
777 json
, "att-p-ol", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
780 void lsp_print_vty(struct isis_lsp
*lsp
, struct vty
*vty
,
781 char dynhost
, struct isis
*isis
)
787 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, sizeof(LSPid
), dynhost
, 1, isis
);
788 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
789 vty_out(vty
, "%5hu ", lsp
->hdr
.pdu_len
);
790 vty_out(vty
, "0x%08x ", lsp
->hdr
.seqno
);
791 vty_out(vty
, "0x%04hx ", lsp
->hdr
.checksum
);
792 if (lsp
->hdr
.rem_lifetime
== 0) {
793 snprintf(age_out
, sizeof(age_out
), "(%d)", lsp
->age_out
);
795 vty_out(vty
, "%7s ", age_out
);
797 vty_out(vty
, " %5hu ", lsp
->hdr
.rem_lifetime
);
798 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
801 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
,
802 struct json_object
*json
, char dynhost
,
806 lsp_print_json(lsp
, json
, dynhost
, isis
);
808 isis_format_tlvs(lsp
->tlvs
, json
);
811 lsp_print_vty(lsp
, vty
, dynhost
, isis
);
813 vty_multiline(vty
, " ", "%s",
814 isis_format_tlvs(lsp
->tlvs
, NULL
));
819 /* print all the lsps info in the local lspdb */
820 int lsp_print_all(struct vty
*vty
, struct json_object
*json
,
821 struct lspdb_head
*head
, char detail
, char dynhost
,
824 struct isis_lsp
*lsp
;
827 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
828 frr_each (lspdb
, head
, lsp
) {
829 lsp_print_common(lsp
, vty
, json
, dynhost
, isis
);
832 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
833 frr_each (lspdb
, head
, lsp
) {
834 lsp_print_detail(lsp
, vty
, json
, dynhost
, isis
);
842 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
844 uint16_t rem_lifetime
;
846 /* Add jitter to configured LSP lifetime */
848 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
850 /* No jitter if the max refresh will be less than configure gen interval
852 /* N.B. this calucation is acceptable since rem_lifetime is in
855 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
856 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
861 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
863 struct isis_area
*area
= lsp
->area
;
864 int level
= lsp
->level
;
865 uint16_t refresh_time
;
867 /* Add jitter to LSP refresh time */
869 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
871 /* RFC 4444 : make sure the refresh time is at least less than 300
872 * of the remaining lifetime and more than gen interval */
873 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
874 || refresh_time
> (rem_lifetime
- 300))
875 refresh_time
= rem_lifetime
- 300;
877 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
878 * we accept this violation to satisfy refresh_time <= rem_lifetime -
884 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
885 struct isis_area
*area
)
887 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
891 for (struct route_node
*rn
= route_top(er_table
); rn
;
892 rn
= route_next(rn
)) {
896 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
897 struct isis_ext_info
*info
= rn
->info
;
899 uint32_t metric
= info
->metric
;
900 if (metric
> MAX_WIDE_PATH_METRIC
)
901 metric
= MAX_WIDE_PATH_METRIC
;
902 if (area
->oldmetric
&& metric
> 0x3f)
906 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
908 if (area
->newmetric
) {
909 struct sr_prefix_cfg
*pcfg
= NULL
;
911 if (area
->srdb
.enabled
)
912 pcfg
= isis_sr_cfg_prefix_find(area
, ipv4
);
914 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
, metric
,
920 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
921 struct isis_area
*area
)
923 struct route_table
*er_table
=
924 get_ext_reach(area
, AF_INET6
, lsp
->level
);
928 for (struct route_node
*rn
= route_top(er_table
); rn
;
929 rn
= srcdest_route_next(rn
)) {
932 struct isis_ext_info
*info
= rn
->info
;
933 struct prefix_ipv6
*p
, *src_p
;
935 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
936 (const struct prefix
**)&src_p
);
938 uint32_t metric
= info
->metric
;
939 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
940 metric
= MAX_WIDE_PATH_METRIC
;
942 if (!src_p
|| !src_p
->prefixlen
) {
943 struct sr_prefix_cfg
*pcfg
= NULL
;
945 if (area
->srdb
.enabled
)
946 pcfg
= isis_sr_cfg_prefix_find(area
, p
);
948 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
949 isis_area_ipv6_topology(area
),
950 p
, metric
, true, pcfg
);
951 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
952 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
959 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
961 lsp_build_ext_reach_ipv4(lsp
, area
);
962 lsp_build_ext_reach_ipv6(lsp
, area
);
965 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
966 struct isis_area
*area
, int level
)
968 struct isis_lsp
*lsp
;
969 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
971 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
972 LSP_FRAGMENT(frag_id
) = frag_num
;
974 lsp
= lsp_search(&area
->lspdb
[level
- 1], frag_id
);
977 if (!lsp
->lspu
.zero_lsp
)
978 lsp_link_fragment(lsp
, lsp0
);
982 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
983 lsp_bits_generate(level
, area
->overload_bit
,
984 area
->attached_bit_send
, area
),
987 lsp_insert(&area
->lspdb
[level
- 1], lsp
);
992 * Builds the LSP data part. This func creates a new frag whenever
993 * area->lsp_frag_threshold is exceeded.
995 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
997 int level
= lsp
->level
;
998 struct listnode
*node
;
999 struct isis_lsp
*frag
;
1001 lsp_clear_data(lsp
);
1002 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
1003 lsp_clear_data(frag
);
1005 lsp
->tlvs
= isis_alloc_tlvs();
1006 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1007 area
->area_tag
, level
);
1009 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
1010 area
->attached_bit_send
, area
);
1014 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
1016 /* Protocols Supported */
1017 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
1018 struct nlpids nlpids
= {.count
= 0};
1020 if (area
->ip_circuits
> 0) {
1022 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1024 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
1027 if (area
->ipv6_circuits
> 0) {
1029 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1031 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
1034 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
1037 if (area_is_mt(area
)) {
1038 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
1040 struct isis_area_mt_setting
**mt_settings
;
1041 unsigned int mt_count
;
1043 mt_settings
= area_mt_settings(area
, &mt_count
);
1044 for (unsigned int i
= 0; i
< mt_count
; i
++) {
1045 isis_tlvs_add_mt_router_info(
1046 lsp
->tlvs
, mt_settings
[i
]->mtid
,
1047 mt_settings
[i
]->overload
, false);
1048 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
1049 isis_mtid2str(mt_settings
[i
]->mtid
));
1052 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
1055 /* Dynamic Hostname */
1056 if (area
->dynhostname
) {
1057 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
1058 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
1059 area
->area_tag
, cmd_hostname_get());
1061 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1065 /* Add Router Capability TLV. */
1066 if (area
->isis
->router_id
!= 0) {
1067 struct isis_router_cap cap
= {};
1069 cap
.router_id
.s_addr
= area
->isis
->router_id
;
1071 /* Add SR Sub-TLVs if SR is enabled. */
1072 if (area
->srdb
.enabled
) {
1073 struct isis_sr_db
*srdb
= &area
->srdb
;
1074 uint32_t range_size
;
1077 range_size
= srdb
->config
.srgb_upper_bound
1078 - srdb
->config
.srgb_lower_bound
+ 1;
1079 cap
.srgb
.flags
= ISIS_SUBTLV_SRGB_FLAG_I
1080 | ISIS_SUBTLV_SRGB_FLAG_V
;
1081 cap
.srgb
.range_size
= range_size
;
1082 cap
.srgb
.lower_bound
= srdb
->config
.srgb_lower_bound
;
1083 /* Then Algorithm */
1084 cap
.algo
[0] = SR_ALGORITHM_SPF
;
1085 cap
.algo
[1] = SR_ALGORITHM_UNSET
;
1088 range_size
= srdb
->config
.srlb_upper_bound
1089 - srdb
->config
.srlb_lower_bound
+ 1;
1090 cap
.srlb
.range_size
= range_size
;
1091 cap
.srlb
.lower_bound
= srdb
->config
.srlb_lower_bound
;
1092 /* And finally MSD */
1093 cap
.msd
= srdb
->config
.msd
;
1095 /* Disable SR Algorithm */
1096 cap
.algo
[0] = SR_ALGORITHM_UNSET
;
1097 cap
.algo
[1] = SR_ALGORITHM_UNSET
;
1100 isis_tlvs_set_router_capability(lsp
->tlvs
, &cap
);
1101 lsp_debug("ISIS (%s): Adding Router Capabilities information",
1105 /* IPv4 address and TE router ID TLVs.
1106 * In case of the first one we don't follow "C" vendor,
1107 * but "J" vendor behavior - one IPv4 address is put
1108 * into LSP. TE router ID will be the same if MPLS-TE
1109 * is not activate or MPLS-TE router-id not specified
1111 if (area
->isis
->router_id
!= 0) {
1112 struct in_addr id
= {.s_addr
= area
->isis
->router_id
};
1113 lsp_debug("ISIS (%s): Adding router ID %pI4 as IPv4 tlv.",
1114 area
->area_tag
, &id
);
1115 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
1117 /* If new style TLV's are in use, add TE router ID TLV
1118 * Check if MPLS-TE is activate and mpls-te router-id set
1119 * otherwise add exactly same data as for IPv4 address
1121 if (area
->newmetric
) {
1122 if (IS_MPLS_TE(area
->mta
)
1123 && area
->mta
->router_id
.s_addr
!= INADDR_ANY
)
1124 id
.s_addr
= area
->mta
->router_id
.s_addr
;
1126 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1128 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
1131 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1135 if (IS_MPLS_TE(area
->mta
)
1136 && !IN6_IS_ADDR_UNSPECIFIED(&area
->mta
->router_id_ipv6
)) {
1137 lsp_debug("ISIS (%s): Adding IPv6 TE Router ID tlv.",
1139 isis_tlvs_set_te_router_id_ipv6(lsp
->tlvs
,
1140 &area
->mta
->router_id_ipv6
);
1143 lsp_debug("ISIS (%s): Adding circuit specific information.",
1148 "ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
1149 area
->area_tag
, fabricd_tier(area
));
1150 isis_tlvs_add_spine_leaf(lsp
->tlvs
, fabricd_tier(area
), true,
1151 false, false, false);
1154 struct isis_circuit
*circuit
;
1155 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
1156 if (!circuit
->interface
)
1158 "ISIS (%s): Processing %s circuit %p with unknown interface",
1160 circuit_type2string(circuit
->circ_type
),
1163 lsp_debug("ISIS (%s): Processing %s circuit %s",
1165 circuit_type2string(circuit
->circ_type
),
1166 circuit
->interface
->name
);
1168 if (circuit
->state
!= C_STATE_UP
) {
1169 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1174 if (area
->advertise_passive_only
&& !circuit
->is_passive
) {
1176 "ISIS (%s): Circuit is not passive, ignoring.",
1181 uint32_t metric
= area
->oldmetric
1182 ? circuit
->metric
[level
- 1]
1183 : circuit
->te_metric
[level
- 1];
1185 if (circuit
->ip_router
&& circuit
->ip_addrs
->count
> 0) {
1187 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1189 struct listnode
*ipnode
;
1190 struct prefix_ipv4
*ipv4
;
1191 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
1193 if (area
->oldmetric
) {
1195 "ISIS (%s): Adding old-style IP reachability for %pFX",
1196 area
->area_tag
, ipv4
);
1197 isis_tlvs_add_oldstyle_ip_reach(
1198 lsp
->tlvs
, ipv4
, metric
);
1201 if (area
->newmetric
) {
1202 struct sr_prefix_cfg
*pcfg
= NULL
;
1205 "ISIS (%s): Adding te-style IP reachability for %pFX",
1206 area
->area_tag
, ipv4
);
1208 if (area
->srdb
.enabled
)
1209 pcfg
= isis_sr_cfg_prefix_find(
1212 isis_tlvs_add_extended_ip_reach(
1213 lsp
->tlvs
, ipv4
, metric
, false,
1219 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
->count
> 0) {
1220 struct listnode
*ipnode
;
1221 struct prefix_ipv6
*ipv6
;
1223 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1225 struct sr_prefix_cfg
*pcfg
= NULL
;
1228 "ISIS (%s): Adding IPv6 reachability for %pFX",
1229 area
->area_tag
, ipv6
);
1231 if (area
->srdb
.enabled
)
1232 pcfg
= isis_sr_cfg_prefix_find(area
,
1235 isis_tlvs_add_ipv6_reach(
1237 isis_area_ipv6_topology(area
), ipv6
,
1238 metric
, false, pcfg
);
1242 switch (circuit
->circ_type
) {
1243 case CIRCUIT_T_BROADCAST
:
1244 if (level
& circuit
->is_type
) {
1246 (level
== IS_LEVEL_1
)
1247 ? circuit
->u
.bc
.l1_desig_is
1248 : circuit
->u
.bc
.l2_desig_is
;
1250 if (LSP_PSEUDO_ID(ne_id
)) {
1251 if (area
->oldmetric
) {
1253 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1256 LSP_PSEUDO_ID(ne_id
));
1257 isis_tlvs_add_oldstyle_reach(
1261 if (area
->newmetric
)
1264 level
, ne_id
, metric
);
1268 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1272 case CIRCUIT_T_P2P
: {
1273 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1274 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1275 && (level
& nei
->circuit_t
)) {
1277 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1278 LSP_PSEUDO_ID(ne_id
) = 0;
1280 if (area
->oldmetric
) {
1282 "ISIS (%s): Adding old-style is reach for %s",
1284 sysid_print(ne_id
));
1285 isis_tlvs_add_oldstyle_reach(
1286 lsp
->tlvs
, ne_id
, metric
);
1288 if (area
->newmetric
) {
1289 uint32_t neighbor_metric
;
1290 if (fabricd_tier(area
) == 0) {
1291 neighbor_metric
= 0xffe;
1293 neighbor_metric
= metric
;
1296 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1297 ne_id
, neighbor_metric
);
1301 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1305 case CIRCUIT_T_LOOPBACK
:
1308 zlog_warn("lsp_area_create: unknown circuit type");
1312 lsp_build_ext_reach(lsp
, area
);
1314 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1317 lsp_adjust_stream(lsp
);
1319 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1320 lsp_clear_data(lsp
);
1322 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1324 zlog_warn("BUG: could not fragment own LSP:");
1325 log_multiline(LOG_WARNING
, " ", "%s",
1326 isis_format_tlvs(tlvs
, NULL
));
1327 isis_free_tlvs(tlvs
);
1330 isis_free_tlvs(tlvs
);
1332 bool fragment_overflow
= false;
1334 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1335 if (node
!= listhead(fragments
)) {
1336 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1337 if (!fragment_overflow
) {
1338 fragment_overflow
= true;
1340 "ISIS (%s): Too much information for 256 fragments",
1343 isis_free_tlvs(tlvs
);
1347 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1349 lsp_adjust_stream(frag
);
1354 list_delete(&fragments
);
1355 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1361 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1363 int lsp_generate(struct isis_area
*area
, int level
)
1365 struct isis_lsp
*oldlsp
, *newlsp
;
1366 uint32_t seq_num
= 0;
1367 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1368 uint16_t rem_lifetime
, refresh_time
;
1369 uint32_t overload_time
;
1371 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1374 /* Check if config is still being processed */
1375 if (event_is_scheduled(t_isis_cfg
))
1378 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1380 memcpy(&lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1382 /* Check if device should be overloaded on startup */
1383 if (device_startup
) {
1384 overload_time
= isis_restart_read_overload_time(area
);
1385 if (overload_time
> 0) {
1386 isis_area_overload_bit_set(area
, true);
1387 event_add_timer(master
, set_overload_on_start_timer
,
1388 area
, overload_time
,
1389 &area
->t_overload_on_startup_timer
);
1391 device_startup
= false;
1394 /* only builds the lsp if the area shares the level */
1395 oldlsp
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
1397 /* FIXME: we should actually initiate a purge */
1398 seq_num
= oldlsp
->hdr
.seqno
;
1399 lsp_search_and_destroy(&area
->lspdb
[level
- 1],
1400 oldlsp
->hdr
.lsp_id
);
1402 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1403 newlsp
= lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1404 lsp_bits_generate(area
->is_type
, area
->overload_bit
,
1405 area
->attached_bit_send
, area
),
1407 newlsp
->area
= area
;
1408 newlsp
->own_lsp
= 1;
1410 lsp_insert(&area
->lspdb
[level
- 1], newlsp
);
1411 /* build_lsp_data (newlsp, area); */
1412 lsp_build(newlsp
, area
);
1413 /* time to calculate our checksum */
1414 lsp_seqno_update(newlsp
);
1415 newlsp
->last_generated
= time(NULL
);
1416 lsp_flood(newlsp
, NULL
);
1417 area
->lsp_gen_count
[level
- 1]++;
1419 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1421 EVENT_OFF(area
->t_lsp_refresh
[level
- 1]);
1422 area
->lsp_regenerate_pending
[level
- 1] = 0;
1423 event_add_timer(master
, lsp_refresh
, &area
->lsp_refresh_arg
[level
- 1],
1424 refresh_time
, &area
->t_lsp_refresh
[level
- 1]);
1426 if (IS_DEBUG_UPDATE_PACKETS
) {
1427 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1428 area
->area_tag
, level
,
1429 rawlspid_print(newlsp
->hdr
.lsp_id
),
1430 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1431 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1435 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1436 area
->area_tag
, level
);
1439 /* send northbound notification */
1440 isis_notif_lsp_gen(area
, newlsp
->hdr
.lsp_id
, newlsp
->hdr
.seqno
,
1441 newlsp
->last_generated
);
1442 #endif /* ifndef FABRICD */
1448 * Search own LSPs, update holding time and flood
1450 static int lsp_regenerate(struct isis_area
*area
, int level
)
1452 struct lspdb_head
*head
;
1453 struct isis_lsp
*lsp
, *frag
;
1454 struct listnode
*node
;
1455 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1456 uint16_t rem_lifetime
, refresh_time
;
1458 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1461 head
= &area
->lspdb
[level
- 1];
1462 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1463 memcpy(lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1465 lsp
= lsp_search(head
, lspid
);
1468 flog_err(EC_LIB_DEVELOPMENT
,
1469 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1470 area
->area_tag
, level
);
1474 lsp_clear_data(lsp
);
1475 lsp_build(lsp
, area
);
1476 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1477 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1478 lsp
->last_generated
= time(NULL
);
1479 lsp_flood(lsp
, NULL
);
1480 area
->lsp_gen_count
[level
- 1]++;
1481 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1483 /* Updating and flooding should only affect fragments
1489 frag
->hdr
.lsp_bits
=
1490 lsp_bits_generate(level
, area
->overload_bit
,
1491 area
->attached_bit_send
, area
);
1492 /* Set the lifetime values of all the fragments to the same
1494 * so that no fragment expires before the lsp is refreshed.
1496 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1497 frag
->age_out
= ZERO_AGE_LIFETIME
;
1498 lsp_flood(frag
, NULL
);
1500 lsp_seqno_update(lsp
);
1502 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1503 event_add_timer(master
, lsp_refresh
, &area
->lsp_refresh_arg
[level
- 1],
1504 refresh_time
, &area
->t_lsp_refresh
[level
- 1]);
1505 area
->lsp_regenerate_pending
[level
- 1] = 0;
1507 if (IS_DEBUG_UPDATE_PACKETS
) {
1509 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1510 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1511 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1512 lsp
->hdr
.rem_lifetime
, refresh_time
);
1515 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1516 area
->area_tag
, level
);
1522 * Something has changed or periodic refresh -> regenerate LSP
1524 static void lsp_refresh(struct event
*thread
)
1526 struct lsp_refresh_arg
*arg
= EVENT_ARG(thread
);
1530 struct isis_area
*area
= arg
->area
;
1534 int level
= arg
->level
;
1536 area
->t_lsp_refresh
[level
- 1] = NULL
;
1537 area
->lsp_regenerate_pending
[level
- 1] = 0;
1539 if ((area
->is_type
& level
) == 0)
1543 * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
1546 if (monotime_since(&area
->last_lsp_refresh_event
[level
- 1], NULL
)
1548 && !(area
->bfd_force_spf_refresh
)) {
1549 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1550 area
->area_tag
, level
);
1551 _lsp_regenerate_schedule(area
, level
, 0, false,
1552 __func__
, __FILE__
, __LINE__
);
1557 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1558 area
->area_tag
, level
);
1559 lsp_regenerate(area
, level
);
1562 int _lsp_regenerate_schedule(struct isis_area
*area
, int level
,
1563 int all_pseudo
, bool postpone
,
1564 const char *func
, const char *file
,
1567 struct isis_lsp
*lsp
;
1568 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1571 struct listnode
*cnode
;
1572 struct isis_circuit
*circuit
;
1579 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
1580 area
->area_tag
, circuit_t2string(level
),
1581 all_pseudo
? "" : "not ",
1584 memcpy(id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1585 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1588 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1589 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1593 monotime(&area
->last_lsp_refresh_event
[lvl
- 1]);
1597 "ISIS (%s): Checking whether L%d needs to be scheduled",
1598 area
->area_tag
, lvl
);
1600 if (area
->lsp_regenerate_pending
[lvl
- 1]
1601 && !(area
->bfd_signalled_down
)) {
1603 * Note: in case of a BFD 'down' message the refresh is
1604 * scheduled once again just to be sure
1606 struct timeval remain
= event_timer_remain(
1607 area
->t_lsp_refresh
[lvl
- 1]);
1609 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1610 area
->area_tag
, (long long)remain
.tv_sec
,
1611 (long long)remain
.tv_usec
/ 1000);
1615 lsp
= lsp_search(&area
->lspdb
[lvl
- 1], id
);
1618 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1624 * Throttle avoidance
1627 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1628 area
->area_tag
, (long long)lsp
->last_generated
,
1630 EVENT_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1631 diff
= now
- lsp
->last_generated
;
1632 if (diff
< area
->lsp_gen_interval
[lvl
- 1]
1633 && !(area
->bfd_signalled_down
)) {
1635 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1637 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1638 area
->area_tag
, timeout
);
1641 * Schedule LSP refresh ASAP
1643 if (area
->bfd_signalled_down
) {
1645 "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
1647 area
->bfd_signalled_down
= false;
1648 area
->bfd_force_spf_refresh
= true;
1651 int64_t time_since_last
= monotime_since(
1652 &area
->last_lsp_refresh_event
[lvl
- 1],
1654 timeout
= time_since_last
< 100000L
1655 ? (100000L - time_since_last
)/1000
1659 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
1660 area
->area_tag
, timeout
);
1663 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
1668 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1669 event_add_timer_msec(master
, lsp_refresh
,
1670 &area
->lsp_refresh_arg
[lvl
- 1], timeout
,
1671 &area
->t_lsp_refresh
[lvl
- 1]);
1675 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1676 lsp_regenerate_schedule_pseudo(circuit
, level
);
1683 * Funcs for pseudonode LSPs
1687 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1689 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1692 struct isis_adjacency
*adj
;
1693 struct list
*adj_list
;
1694 struct listnode
*node
;
1695 struct isis_area
*area
= circuit
->area
;
1698 lsp_clear_data(lsp
);
1699 lsp
->tlvs
= isis_alloc_tlvs();
1701 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1702 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1703 circuit
->interface
->name
, level
);
1706 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1707 lsp
->hdr
.lsp_bits
= lsp_bits_generate(
1708 level
, 0, circuit
->area
->attached_bit_send
, area
);
1711 * add self to IS neighbours
1713 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1715 memcpy(ne_id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1716 LSP_PSEUDO_ID(ne_id
) = 0;
1718 if (circuit
->area
->oldmetric
) {
1719 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1721 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1722 area
->area_tag
, sysid_print(ne_id
),
1723 LSP_PSEUDO_ID(ne_id
));
1725 if (circuit
->area
->newmetric
) {
1726 if (area_is_mt(circuit
->area
))
1727 mtid
= ISIS_MT_IPV4_UNICAST
;
1729 mtid
= ISIS_MT_DISABLE
;
1730 isis_tlvs_add_extended_reach(lsp
->tlvs
, mtid
, ne_id
, 0, NULL
);
1732 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1733 area
->area_tag
, sysid_print(ne_id
),
1734 LSP_PSEUDO_ID(ne_id
));
1737 adj_list
= list_new();
1738 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1740 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1741 if (!(adj
->level
& level
)) {
1743 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1744 area
->area_tag
, sysid_print(adj
->sysid
));
1748 if (!(level
== IS_LEVEL_1
1749 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1750 && !(level
== IS_LEVEL_1
1751 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1752 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1753 && !(level
== IS_LEVEL_2
1754 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1756 "ISIS (%s): Ignoring neighbor %s, level does not match",
1757 area
->area_tag
, sysid_print(adj
->sysid
));
1761 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1762 if (circuit
->area
->oldmetric
) {
1763 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1765 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1766 area
->area_tag
, sysid_print(ne_id
),
1767 LSP_PSEUDO_ID(ne_id
));
1769 if (circuit
->area
->newmetric
) {
1770 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1771 ISIS_MT_IPV4_UNICAST
,
1774 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1775 area
->area_tag
, sysid_print(ne_id
),
1776 LSP_PSEUDO_ID(ne_id
));
1779 list_delete(&adj_list
);
1783 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1785 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1786 struct isis_lsp
*lsp
;
1787 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1788 uint16_t rem_lifetime
, refresh_time
;
1790 if ((circuit
->is_type
& level
) != level
1791 || (circuit
->state
!= C_STATE_UP
)
1792 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1793 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1796 memcpy(lsp_id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1797 LSP_FRAGMENT(lsp_id
) = 0;
1798 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1801 * If for some reason have a pseudo LSP in the db already -> regenerate
1803 if (lsp_search(head
, lsp_id
))
1804 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1806 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1807 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1808 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1809 lsp_bits_generate(circuit
->area
->is_type
, 0,
1810 circuit
->area
->attached_bit_send
,
1813 lsp
->area
= circuit
->area
;
1815 lsp_build_pseudo(lsp
, circuit
, level
);
1818 lsp_insert(head
, lsp
);
1819 lsp_flood(lsp
, NULL
);
1821 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1822 EVENT_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1823 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1824 if (level
== IS_LEVEL_1
)
1825 event_add_timer(master
, lsp_l1_refresh_pseudo
, circuit
,
1827 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1828 else if (level
== IS_LEVEL_2
)
1829 event_add_timer(master
, lsp_l2_refresh_pseudo
, circuit
,
1831 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1833 if (IS_DEBUG_UPDATE_PACKETS
) {
1835 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1836 circuit
->area
->area_tag
, level
,
1837 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1838 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1839 lsp
->hdr
.rem_lifetime
, refresh_time
);
1845 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1847 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1848 struct isis_lsp
*lsp
;
1849 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1850 uint16_t rem_lifetime
, refresh_time
;
1852 if ((circuit
->is_type
& level
) != level
1853 || (circuit
->state
!= C_STATE_UP
)
1854 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1855 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1858 memcpy(lsp_id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1859 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1860 LSP_FRAGMENT(lsp_id
) = 0;
1862 lsp
= lsp_search(head
, lsp_id
);
1865 flog_err(EC_LIB_DEVELOPMENT
,
1866 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1867 rawlspid_print(lsp_id
));
1871 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1872 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1873 lsp_build_pseudo(lsp
, circuit
, level
);
1874 lsp_inc_seqno(lsp
, 0);
1875 lsp
->last_generated
= time(NULL
);
1876 lsp_flood(lsp
, NULL
);
1878 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1879 if (level
== IS_LEVEL_1
)
1880 event_add_timer(master
, lsp_l1_refresh_pseudo
, circuit
,
1882 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1883 else if (level
== IS_LEVEL_2
)
1884 event_add_timer(master
, lsp_l2_refresh_pseudo
, circuit
,
1886 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1888 if (IS_DEBUG_UPDATE_PACKETS
) {
1890 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1891 circuit
->area
->area_tag
, level
,
1892 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1893 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1894 lsp
->hdr
.rem_lifetime
, refresh_time
);
1901 * Something has changed or periodic refresh -> regenerate pseudo LSP
1903 static void lsp_l1_refresh_pseudo(struct event
*thread
)
1905 struct isis_circuit
*circuit
;
1906 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1908 circuit
= EVENT_ARG(thread
);
1910 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1911 circuit
->lsp_regenerate_pending
[0] = 0;
1913 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1914 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1915 memcpy(id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1916 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1917 LSP_FRAGMENT(id
) = 0;
1918 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1922 lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1925 static void lsp_l2_refresh_pseudo(struct event
*thread
)
1927 struct isis_circuit
*circuit
;
1928 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1930 circuit
= EVENT_ARG(thread
);
1932 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1933 circuit
->lsp_regenerate_pending
[1] = 0;
1935 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1936 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1937 memcpy(id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1938 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1939 LSP_FRAGMENT(id
) = 0;
1940 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1944 lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1947 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1949 struct isis_lsp
*lsp
;
1950 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1954 struct isis_area
*area
= circuit
->area
;
1956 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1957 || circuit
->state
!= C_STATE_UP
)
1961 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1962 area
->area_tag
, circuit_t2string(level
),
1963 circuit
->interface
->name
);
1965 memcpy(lsp_id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1966 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1967 LSP_FRAGMENT(lsp_id
) = 0;
1970 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1972 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1973 area
->area_tag
, lvl
);
1975 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1976 sched_debug("ISIS (%s): Level is not active on circuit",
1981 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1983 "ISIS (%s): This IS is not DR, nothing to do.",
1988 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1989 struct timeval remain
= event_timer_remain(
1990 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1992 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1993 area
->area_tag
, (long long)remain
.tv_sec
,
1994 (long long)remain
.tv_usec
/ 1000);
1998 lsp
= lsp_search(&circuit
->area
->lspdb
[lvl
- 1], lsp_id
);
2001 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2007 * Throttle avoidance
2010 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2011 area
->area_tag
, (long long)lsp
->last_generated
,
2013 EVENT_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2014 diff
= now
- lsp
->last_generated
;
2015 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
2017 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
2020 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2021 area
->area_tag
, timeout
);
2025 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
2026 area
->area_tag
, timeout
);
2029 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
2031 if (lvl
== IS_LEVEL_1
) {
2032 event_add_timer_msec(
2033 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
2034 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2035 } else if (lvl
== IS_LEVEL_2
) {
2036 event_add_timer_msec(
2037 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
2038 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2046 * Walk through LSPs for an area
2047 * - set remaining lifetime
2049 void lsp_tick(struct event
*thread
)
2051 struct isis_area
*area
;
2052 struct isis_lsp
*lsp
;
2054 uint16_t rem_lifetime
;
2055 bool fabricd_sync_incomplete
= false;
2057 area
= EVENT_ARG(thread
);
2059 area
->t_tick
= NULL
;
2060 event_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
2062 struct isis_circuit
*fabricd_init_c
= fabricd_initial_sync_circuit(area
);
2065 * Remove LSPs which have aged out
2067 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
2068 struct isis_lsp
*next
= lspdb_first(&area
->lspdb
[level
]);
2069 frr_each_from (lspdb
, &area
->lspdb
[level
], lsp
, next
) {
2071 * The lsp rem_lifetime is kept at 0 for MaxAge
2073 * ZeroAgeLifetime depending on explicit purge
2075 * natural age out. So schedule spf only once
2077 * the first time rem_lifetime becomes 0.
2079 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
2083 * Schedule may run spf which should be done
2085 * the lsp rem_lifetime becomes 0 for the first
2087 * ISO 10589 - 7.3.16.4 first paragraph.
2089 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
2090 /* 7.3.16.4 a) set SRM flags on all */
2091 /* 7.3.16.4 b) retain only the header */
2092 if (lsp
->area
->purge_originator
)
2093 lsp_purge(lsp
, lsp
->level
, NULL
);
2095 lsp_flood(lsp
, NULL
);
2096 /* 7.3.16.4 c) record the time to purge
2098 isis_spf_schedule(lsp
->area
, lsp
->level
);
2099 isis_te_lsp_event(lsp
, LSP_TICK
);
2102 if (lsp
->age_out
== 0) {
2104 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2105 area
->area_tag
, lsp
->level
,
2106 rawlspid_print(lsp
->hdr
.lsp_id
),
2109 /* if we're aging out fragment 0, lsp_destroy()
2110 * below will delete all other fragments too,
2111 * so we need to skip over those
2113 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
2115 !memcmp(next
->hdr
.lsp_id
,
2117 ISIS_SYS_ID_LEN
+ 1))
2119 &area
->lspdb
[level
],
2122 lspdb_del(&area
->lspdb
[level
], lsp
);
2127 if (fabricd_init_c
&& lsp
) {
2128 fabricd_sync_incomplete
|=
2129 ISIS_CHECK_FLAG(lsp
->SSNflags
,
2136 && !fabricd_sync_incomplete
2137 && !isis_tx_queue_len(fabricd_init_c
->tx_queue
)) {
2138 fabricd_initial_sync_finish(area
);
2142 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
2144 struct isis_lsp
*lsp
;
2146 lsp
= lsp_search(&circuit
->area
->lspdb
[level
- 1], id
);
2150 lsp_purge(lsp
, level
, NULL
);
2154 * Purge own LSP that is received and we don't have.
2155 * -> Do as in 7.3.16.4
2157 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
2158 struct isis_area
*area
)
2160 struct isis_lsp
*lsp
;
2163 * We need to create the LSP to be purged
2165 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
2168 lsp_adjust_stream(lsp
);
2169 lsp
->age_out
= ZERO_AGE_LIFETIME
;
2170 lsp
->area
->lsp_purge_count
[level
- 1]++;
2172 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
2173 lsp
->hdr
.rem_lifetime
= 0;
2175 lsp_purge_add_poi(lsp
, NULL
);
2179 lsp_insert(&area
->lspdb
[lsp
->level
- 1], lsp
);
2180 lsp_flood(lsp
, NULL
);
2185 void lsp_set_all_srmflags(struct isis_lsp
*lsp
, bool set
)
2187 struct listnode
*node
;
2188 struct isis_circuit
*circuit
;
2195 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2196 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
2198 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
2201 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2206 void _lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2207 const char *func
, const char *file
, int line
)
2209 if (IS_DEBUG_FLOODING
) {
2210 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2211 rawlspid_print(lsp
->hdr
.lsp_id
),
2212 circuit
? " except on " : "",
2213 circuit
? circuit
->interface
->name
: "",
2218 lsp_set_all_srmflags(lsp
, true);
2220 fabricd_lsp_flood(lsp
, circuit
);
2223 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2226 static int lsp_handle_adj_state_change(struct isis_adjacency
*adj
)
2228 lsp_regenerate_schedule(adj
->circuit
->area
, IS_LEVEL_1
| IS_LEVEL_2
, 0);
2230 /* when an adjacency state changes determine if we need to
2231 * change attach_bits in other area's LSPs
2233 isis_reset_attach_bit(adj
);
2239 * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
2240 * address-family and MT-ID.
2242 int isis_lsp_iterate_ip_reach(struct isis_lsp
*lsp
, int family
, uint16_t mtid
,
2243 lsp_ip_reach_iter_cb cb
, void *arg
)
2245 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
2246 struct isis_lsp
*frag
;
2247 struct listnode
*node
;
2249 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
2250 return LSP_ITER_CONTINUE
;
2254 if (!fabricd
&& !pseudo_lsp
&& family
== AF_INET
2255 && mtid
== ISIS_MT_IPV4_UNICAST
) {
2256 struct isis_item_list
*reachs
[] = {
2257 &lsp
->tlvs
->oldstyle_ip_reach
,
2258 &lsp
->tlvs
->oldstyle_ip_reach_ext
};
2260 for (unsigned int i
= 0; i
< array_size(reachs
); i
++) {
2261 struct isis_oldstyle_ip_reach
*r
;
2263 for (r
= (struct isis_oldstyle_ip_reach
*)
2267 bool external
= i
? true : false;
2269 if ((*cb
)((struct prefix
*)&r
->prefix
,
2270 r
->metric
, external
, NULL
,
2273 return LSP_ITER_STOP
;
2278 if (!pseudo_lsp
&& family
== AF_INET
) {
2279 struct isis_item_list
*ipv4_reachs
;
2281 if (mtid
== ISIS_MT_IPV4_UNICAST
)
2282 ipv4_reachs
= &lsp
->tlvs
->extended_ip_reach
;
2284 ipv4_reachs
= isis_lookup_mt_items(
2285 &lsp
->tlvs
->mt_ip_reach
, mtid
);
2287 struct isis_extended_ip_reach
*r
;
2288 for (r
= ipv4_reachs
? (struct isis_extended_ip_reach
*)
2292 if ((*cb
)((struct prefix
*)&r
->prefix
,
2293 r
->metric
, false, r
->subtlvs
, arg
)
2295 return LSP_ITER_STOP
;
2299 if (!pseudo_lsp
&& family
== AF_INET6
) {
2300 struct isis_item_list
*ipv6_reachs
;
2301 struct isis_ipv6_reach
*r
;
2303 if (mtid
== ISIS_MT_IPV4_UNICAST
)
2304 ipv6_reachs
= &lsp
->tlvs
->ipv6_reach
;
2306 ipv6_reachs
= isis_lookup_mt_items(
2307 &lsp
->tlvs
->mt_ipv6_reach
, mtid
);
2309 for (r
= ipv6_reachs
? (struct isis_ipv6_reach
*)
2313 if ((*cb
)((struct prefix
*)&r
->prefix
,
2314 r
->metric
, r
->external
, r
->subtlvs
,
2317 return LSP_ITER_STOP
;
2322 /* Parse LSP fragments if it is not a fragment itself */
2323 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
2324 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2328 if (isis_lsp_iterate_ip_reach(frag
, family
, mtid
, cb
,
2331 return LSP_ITER_STOP
;
2334 return LSP_ITER_CONTINUE
;
2338 * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
2341 int isis_lsp_iterate_is_reach(struct isis_lsp
*lsp
, uint16_t mtid
,
2342 lsp_is_reach_iter_cb cb
, void *arg
)
2344 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
2345 struct isis_lsp
*frag
;
2346 struct listnode
*node
;
2347 struct isis_item
*head
;
2348 struct isis_item_list
*te_neighs
;
2350 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
2351 return LSP_ITER_CONTINUE
;
2355 if (pseudo_lsp
|| mtid
== ISIS_MT_IPV4_UNICAST
) {
2356 head
= lsp
->tlvs
->oldstyle_reach
.head
;
2357 for (struct isis_oldstyle_reach
*reach
=
2358 (struct isis_oldstyle_reach
*)head
;
2359 reach
; reach
= reach
->next
) {
2360 if ((*cb
)(reach
->id
, reach
->metric
, true, NULL
,
2363 return LSP_ITER_STOP
;
2367 if (pseudo_lsp
|| mtid
== ISIS_MT_IPV4_UNICAST
)
2368 te_neighs
= &lsp
->tlvs
->extended_reach
;
2371 isis_get_mt_items(&lsp
->tlvs
->mt_reach
, mtid
);
2373 head
= te_neighs
->head
;
2374 for (struct isis_extended_reach
*reach
=
2375 (struct isis_extended_reach
*)head
;
2376 reach
; reach
= reach
->next
) {
2377 if ((*cb
)(reach
->id
, reach
->metric
, false,
2378 reach
->subtlvs
, arg
)
2380 return LSP_ITER_STOP
;
2385 /* Parse LSP fragments if it not a fragment itself. */
2386 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
2387 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2391 if (isis_lsp_iterate_is_reach(frag
, mtid
, cb
, arg
)
2393 return LSP_ITER_STOP
;
2396 return LSP_ITER_CONTINUE
;
2401 device_startup
= true;
2402 hook_register(isis_adj_state_change_hook
,
2403 lsp_handle_adj_state_change
);