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/isis_constants.h"
44 #include "isisd/isis_common.h"
45 #include "isisd/isis_flags.h"
46 #include "isisd/isis_circuit.h"
47 #include "isisd/isisd.h"
48 #include "isisd/isis_lsp.h"
49 #include "isisd/isis_pdu.h"
50 #include "isisd/isis_dynhn.h"
51 #include "isisd/isis_misc.h"
52 #include "isisd/isis_csm.h"
53 #include "isisd/isis_adjacency.h"
54 #include "isisd/isis_spf.h"
55 #include "isisd/isis_mt.h"
56 #include "isisd/isis_tlvs.h"
57 #include "isisd/isis_te.h"
58 #include "isisd/isis_sr.h"
59 #include "isisd/fabricd.h"
60 #include "isisd/isis_tx_queue.h"
61 #include "isisd/isis_nb.h"
63 DEFINE_MTYPE_STATIC(ISISD
, ISIS_LSP
, "ISIS LSP");
65 static int lsp_refresh(struct thread
*thread
);
66 static int lsp_l1_refresh_pseudo(struct thread
*thread
);
67 static int lsp_l2_refresh_pseudo(struct thread
*thread
);
69 static void lsp_destroy(struct isis_lsp
*lsp
);
71 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
73 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
76 int lspdb_compare(const struct isis_lsp
*a
, const struct isis_lsp
*b
)
78 return memcmp(a
->hdr
.lsp_id
, b
->hdr
.lsp_id
, sizeof(a
->hdr
.lsp_id
));
81 void lsp_db_init(struct lspdb_head
*head
)
86 void lsp_db_fini(struct lspdb_head
*head
)
90 while ((lsp
= lspdb_pop(head
)))
95 struct isis_lsp
*lsp_search(struct lspdb_head
*head
, const uint8_t *id
)
97 struct isis_lsp searchfor
;
98 memcpy(searchfor
.hdr
.lsp_id
, id
, sizeof(searchfor
.hdr
.lsp_id
));
100 return lspdb_find(head
, &searchfor
);
103 static void lsp_clear_data(struct isis_lsp
*lsp
)
108 isis_free_tlvs(lsp
->tlvs
);
112 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
);
114 static void lsp_destroy(struct isis_lsp
*lsp
)
116 struct listnode
*cnode
;
117 struct isis_circuit
*circuit
;
122 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
, circuit
))
123 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
125 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
129 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
130 if (lsp
->lspu
.frags
) {
131 lsp_remove_frags(&lsp
->area
->lspdb
[lsp
->level
- 1],
133 list_delete(&lsp
->lspu
.frags
);
136 if (lsp
->lspu
.zero_lsp
137 && lsp
->lspu
.zero_lsp
->lspu
.frags
) {
138 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
142 isis_spf_schedule(lsp
->area
, lsp
->level
);
145 stream_free(lsp
->pdu
);
147 fabricd_lsp_free(lsp
);
148 XFREE(MTYPE_ISIS_LSP
, lsp
);
152 * Remove all the frags belonging to the given lsp
154 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
)
156 struct listnode
*lnode
, *lnnode
;
157 struct isis_lsp
*lsp
;
159 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
160 lsp
= lsp_search(head
, lsp
->hdr
.lsp_id
);
161 lspdb_del(head
, lsp
);
166 void lsp_search_and_destroy(struct lspdb_head
*head
, const uint8_t *id
)
168 struct isis_lsp
*lsp
;
170 lsp
= lsp_search(head
, id
);
172 lspdb_del(head
, lsp
);
174 * If this is a zero lsp, remove all the frags now
176 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
178 lsp_remove_frags(head
, lsp
->lspu
.frags
);
181 * else just remove this frag, from the zero lsps' frag
184 if (lsp
->lspu
.zero_lsp
185 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
186 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
194 * Compares a LSP to given values
195 * Params are given in net order
197 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
198 uint16_t checksum
, uint16_t rem_lifetime
)
200 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
201 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
202 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
203 if (IS_DEBUG_SNP_PACKETS
) {
205 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
206 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
207 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
208 lsp
->hdr
.rem_lifetime
);
210 "ISIS-Snp (%s): is equal to ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
211 areatag
, seqno
, checksum
, rem_lifetime
);
217 * LSPs with identical checksums should only be treated as newer if:
218 * a) The current LSP has a remaining lifetime != 0 and the other LSP
220 * remaining lifetime == 0. In this case, we should participate in
222 * and should not treat the current LSP with remaining lifetime == 0
224 * b) The LSP has an incorrect checksum. In this case, we need to react
228 if (seqno
> lsp
->hdr
.seqno
229 || (seqno
== lsp
->hdr
.seqno
230 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
231 || (lsp
->hdr
.checksum
!= checksum
232 && lsp
->hdr
.rem_lifetime
)))) {
233 if (IS_DEBUG_SNP_PACKETS
) {
235 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
236 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
237 checksum
, rem_lifetime
);
239 "ISIS-Snp (%s): is newer than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
240 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
241 lsp
->hdr
.rem_lifetime
);
245 if (IS_DEBUG_SNP_PACKETS
) {
246 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
247 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
248 checksum
, rem_lifetime
);
250 "ISIS-Snp (%s): is older than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
251 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
252 lsp
->hdr
.rem_lifetime
);
258 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
261 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
262 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
263 struct stream
*stream
= lsp
->pdu
;
264 size_t orig_getp
= 0, orig_endp
= 0;
267 orig_getp
= stream_get_getp(lsp
->pdu
);
268 orig_endp
= stream_get_endp(lsp
->pdu
);
271 stream_set_getp(lsp
->pdu
, 0);
272 stream_set_endp(lsp
->pdu
, 0);
274 fill_fixed_hdr(pdu_type
, stream
);
277 *len_pointer
= stream_get_endp(stream
);
278 stream_putw(stream
, hdr
->pdu_len
);
279 stream_putw(stream
, hdr
->rem_lifetime
);
280 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
281 stream_putl(stream
, hdr
->seqno
);
282 stream_putw(stream
, hdr
->checksum
);
283 stream_putc(stream
, hdr
->lsp_bits
);
286 stream_set_endp(lsp
->pdu
, orig_endp
);
287 stream_set_getp(lsp
->pdu
, orig_getp
);
291 static void lsp_add_auth(struct isis_lsp
*lsp
)
293 struct isis_passwd
*passwd
;
294 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
295 : &lsp
->area
->domain_passwd
;
296 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
299 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
302 lsp
->tlvs
= isis_alloc_tlvs();
307 put_lsp_hdr(lsp
, &len_pointer
, false);
308 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
310 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
312 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
313 stream_get_endp(lsp
->pdu
) - 12, 12));
316 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
320 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
321 newseq
= lsp
->hdr
.seqno
+ 1;
326 /* check for overflow */
327 if (newseq
< lsp
->hdr
.seqno
) {
328 /* send northbound notification */
329 lsp
->area
->lsp_exceeded_max_counter
++;
330 isis_notif_lsp_exceed_max(lsp
->area
, lsp
->hdr
.lsp_id
);
332 #endif /* ifndef FABRICD */
334 lsp
->hdr
.seqno
= newseq
;
337 isis_spf_schedule(lsp
->area
, lsp
->level
);
340 static void lsp_purge_add_poi(struct isis_lsp
*lsp
,
341 const uint8_t *sender
)
343 if (lsp
->area
== NULL
)
346 if (!lsp
->area
->purge_originator
)
349 /* add purge originator identification */
351 lsp
->tlvs
= isis_alloc_tlvs();
352 isis_tlvs_set_purge_originator(lsp
->tlvs
, lsp
->area
->isis
->sysid
,
354 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
357 static void lsp_purge(struct isis_lsp
*lsp
, int level
,
358 const uint8_t *sender
)
362 stream_reset(lsp
->pdu
);
365 lsp
->hdr
.checksum
= 0;
366 lsp
->hdr
.rem_lifetime
= 0;
368 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
369 lsp
->area
->lsp_purge_count
[level
- 1]++;
371 lsp_purge_add_poi(lsp
, sender
);
374 lsp_flood(lsp
, NULL
);
378 * Generates checksum for LSP and its frags
380 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
382 struct isis_lsp
*lsp
;
383 struct listnode
*node
;
385 lsp_inc_seqno(lsp0
, 0);
387 if (!lsp0
->lspu
.frags
)
390 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
392 lsp_inc_seqno(lsp
, 0);
393 else if (lsp
->hdr
.rem_lifetime
) {
394 /* Purge should only be applied when the fragment has
395 * non-zero remaining lifetime.
397 lsp_purge(lsp
, lsp0
->level
, NULL
);
404 bool isis_level2_adj_up(struct isis_area
*area
)
406 struct listnode
*node
, *cnode
;
407 struct isis_circuit
*circuit
;
409 struct isis_adjacency
*adj
;
411 if (area
->is_type
== IS_LEVEL_1
)
414 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
)) {
415 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
416 adjdb
= circuit
->u
.bc
.adjdb
[1];
417 if (!adjdb
|| !adjdb
->count
)
420 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
)) {
421 if (adj
->level
!= ISIS_ADJ_LEVEL1
422 && adj
->adj_state
== ISIS_ADJ_UP
)
425 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
426 && circuit
->u
.p2p
.neighbor
) {
427 adj
= circuit
->u
.p2p
.neighbor
;
428 if (adj
->level
!= ISIS_ADJ_LEVEL1
429 && adj
->adj_state
== ISIS_ADJ_UP
)
437 static void isis_reset_attach_bit(struct isis_adjacency
*adj
)
439 struct isis_area
*area
= adj
->circuit
->area
;
440 struct lspdb_head
*head
;
441 struct isis_lsp
*lsp
;
442 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
445 * If an L2 adjacency changed its state in L-1-2 area, we have to:
446 * - set the attached bit in L1 LSPs if it's the first L2 adjacency
447 * - remove the attached bit in L1 LSPs if it's the last L2 adjacency
450 if (area
->is_type
!= IS_LEVEL_1_AND_2
|| adj
->level
== ISIS_ADJ_LEVEL1
)
453 if (!area
->attached_bit_send
)
456 head
= &area
->lspdb
[IS_LEVEL_1
- 1];
457 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
458 memcpy(lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
460 lsp
= lsp_search(head
, lspid
);
464 if (adj
->adj_state
== ISIS_ADJ_UP
465 && !(lsp
->hdr
.lsp_bits
& LSPBIT_ATT
)) {
466 sched_debug("ISIS (%s): adj going up regenerate lsp-bits",
468 lsp_regenerate_schedule(area
, IS_LEVEL_1
, 0);
469 } else if (adj
->adj_state
== ISIS_ADJ_DOWN
470 && (lsp
->hdr
.lsp_bits
& LSPBIT_ATT
)
471 && !isis_level2_adj_up(area
)) {
472 sched_debug("ISIS (%s): adj going down regenerate lsp-bits",
474 lsp_regenerate_schedule(area
, IS_LEVEL_1
, 0);
478 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
,
479 struct isis_area
*area
)
481 uint8_t lsp_bits
= 0;
482 if (area
->is_type
== IS_LEVEL_1
)
483 lsp_bits
= IS_LEVEL_1
;
485 lsp_bits
= IS_LEVEL_1_AND_2
;
487 lsp_bits
|= overload_bit
;
489 /* only set the attach bit if we are a level-1-2 router and this is
490 * a level-1 LSP and we have a level-2 adjacency up from another area
492 if (area
->is_type
== IS_LEVEL_1_AND_2
&& level
== IS_LEVEL_1
493 && attached_bit
&& isis_level2_adj_up(area
))
494 lsp_bits
|= LSPBIT_ATT
;
498 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
499 struct isis_tlvs
*tlvs
, struct stream
*stream
,
500 struct isis_area
*area
, int level
)
502 /* free the old lsp data */
505 /* copying only the relevant part of our stream */
506 if (lsp
->pdu
!= NULL
)
507 stream_free(lsp
->pdu
);
508 lsp
->pdu
= stream_dup(stream
);
510 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
513 lsp
->age_out
= ZERO_AGE_LIFETIME
;
514 lsp
->installed
= time(NULL
);
518 if (area
->dynhostname
&& lsp
->tlvs
->hostname
519 && lsp
->hdr
.rem_lifetime
) {
521 area
->isis
, lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
522 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
) == IS_LEVEL_1_AND_2
530 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
532 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
533 /* zero lsp -> create list to store fragments */
534 lsp
->lspu
.frags
= list_new();
536 /* fragment -> set backpointer and add to zero lsps list */
538 lsp
->lspu
.zero_lsp
= lsp0
;
539 listnode_add(lsp0
->lspu
.frags
, lsp
);
543 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
544 struct isis_tlvs
*tlvs
, struct stream
*stream
,
545 struct isis_area
*area
, int level
, bool confusion
)
550 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
551 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
557 lsp_purge(lsp
, level
, NULL
);
559 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
562 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
563 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
564 struct isis_lsp
*lsp0
;
566 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
567 LSP_FRAGMENT(lspid
) = 0;
568 lsp0
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
570 lsp_link_fragment(lsp
, lsp0
);
574 isis_spf_schedule(lsp
->area
, lsp
->level
);
577 /* creation of LSP directly from what we received */
578 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
579 struct isis_tlvs
*tlvs
,
580 struct stream
*stream
, struct isis_lsp
*lsp0
,
581 struct isis_area
*area
, int level
)
583 struct isis_lsp
*lsp
;
585 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
586 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
587 lsp_link_fragment(lsp
, lsp0
);
592 static void lsp_adjust_stream(struct isis_lsp
*lsp
)
595 if (STREAM_SIZE(lsp
->pdu
) == LLC_LEN
+ lsp
->area
->lsp_mtu
)
597 stream_free(lsp
->pdu
);
600 lsp
->pdu
= stream_new(LLC_LEN
+ lsp
->area
->lsp_mtu
);
603 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
604 uint16_t rem_lifetime
, uint32_t seqno
,
605 uint8_t lsp_bits
, uint16_t checksum
,
606 struct isis_lsp
*lsp0
, int level
)
608 struct isis_lsp
*lsp
;
610 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
613 lsp_adjust_stream(lsp
);
615 /* Minimal LSP PDU size */
616 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
617 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
618 lsp
->hdr
.checksum
= checksum
;
619 lsp
->hdr
.seqno
= seqno
;
620 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
621 lsp
->hdr
.lsp_bits
= lsp_bits
;
623 lsp
->age_out
= ZERO_AGE_LIFETIME
;
624 lsp_link_fragment(lsp
, lsp0
);
625 put_lsp_hdr(lsp
, NULL
, false);
628 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
629 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
630 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
636 void lsp_insert(struct lspdb_head
*head
, struct isis_lsp
*lsp
)
638 lspdb_add(head
, lsp
);
640 isis_spf_schedule(lsp
->area
, lsp
->level
);
644 * Build a list of LSPs with non-zero ht and seqno bounded by start and stop ids
646 void lsp_build_list_nonzero_ht(struct lspdb_head
*head
, const uint8_t *start_id
,
647 const uint8_t *stop_id
, struct list
*list
)
649 struct isis_lsp searchfor
;
650 struct isis_lsp
*lsp
, *start
;
652 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
654 start
= lspdb_find_gteq(head
, &searchfor
);
655 frr_each_from (lspdb
, head
, lsp
, start
) {
656 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
,
657 ISIS_SYS_ID_LEN
+ 2) > 0)
660 if (lsp
->hdr
.rem_lifetime
&& lsp
->hdr
.seqno
)
661 listnode_add(list
, lsp
);
665 static void lsp_set_time(struct isis_lsp
*lsp
)
669 if (lsp
->hdr
.rem_lifetime
== 0) {
670 if (lsp
->age_out
> 0)
675 lsp
->hdr
.rem_lifetime
--;
676 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
677 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
680 void lspid_print(uint8_t *lsp_id
, char *dest
, size_t dest_len
, char dynhost
,
681 char frag
, struct isis
*isis
)
683 struct isis_dynhn
*dyn
= NULL
;
684 char id
[SYSID_STRLEN
];
687 dyn
= dynhn_find_by_id(isis
, lsp_id
);
692 snprintf(id
, sizeof(id
), "%.14s", dyn
->hostname
);
693 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
694 snprintf(id
, sizeof(id
), "%.14s", cmd_hostname_get());
696 memcpy(id
, sysid_print(lsp_id
), 15);
699 snprintf(dest
, dest_len
, "%s.%02x-%02x", id
,
700 LSP_PSEUDO_ID(lsp_id
), LSP_FRAGMENT(lsp_id
));
702 snprintf(dest
, dest_len
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
705 /* Convert the lsp attribute bits to attribute string */
706 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
713 if (buf_size
< 2 * 3)
716 /* we only focus on the default metric */
717 pos
+= snprintf(pos
, buf_size
, "%d/",
718 ISIS_MASK_LSP_ATT_BITS(lsp_bits
) ? 1 : 0);
720 pos
+= snprintf(pos
, buf_size
, "%d/",
721 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
723 snprintf(pos
, buf_size
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
728 /* this function prints the lsp on show isis database */
729 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
,
736 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, sizeof(LSPid
), dynhost
, 1, isis
);
737 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
738 vty_out(vty
, "%5hu ", lsp
->hdr
.pdu_len
);
739 vty_out(vty
, "0x%08x ", lsp
->hdr
.seqno
);
740 vty_out(vty
, "0x%04hx ", lsp
->hdr
.checksum
);
741 if (lsp
->hdr
.rem_lifetime
== 0) {
742 snprintf(age_out
, sizeof(age_out
), "(%d)", lsp
->age_out
);
744 vty_out(vty
, "%7s ", age_out
);
746 vty_out(vty
, " %5hu ", lsp
->hdr
.rem_lifetime
);
747 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
750 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
,
753 lsp_print(lsp
, vty
, dynhost
, isis
);
755 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
759 /* print all the lsps info in the local lspdb */
760 int lsp_print_all(struct vty
*vty
, struct lspdb_head
*head
, char detail
,
761 char dynhost
, struct isis
*isis
)
763 struct isis_lsp
*lsp
;
766 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
767 frr_each (lspdb
, head
, lsp
) {
768 lsp_print(lsp
, vty
, dynhost
, isis
);
771 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
772 frr_each (lspdb
, head
, lsp
) {
773 lsp_print_detail(lsp
, vty
, dynhost
, isis
);
781 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
783 uint16_t rem_lifetime
;
785 /* Add jitter to configured LSP lifetime */
787 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
789 /* No jitter if the max refresh will be less than configure gen interval
791 /* N.B. this calucation is acceptable since rem_lifetime is in
794 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
795 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
800 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
802 struct isis_area
*area
= lsp
->area
;
803 int level
= lsp
->level
;
804 uint16_t refresh_time
;
806 /* Add jitter to LSP refresh time */
808 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
810 /* RFC 4444 : make sure the refresh time is at least less than 300
811 * of the remaining lifetime and more than gen interval */
812 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
813 || refresh_time
> (rem_lifetime
- 300))
814 refresh_time
= rem_lifetime
- 300;
816 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
817 * we accept this violation to satisfy refresh_time <= rem_lifetime -
823 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
824 struct isis_area
*area
)
826 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
830 for (struct route_node
*rn
= route_top(er_table
); rn
;
831 rn
= route_next(rn
)) {
835 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
836 struct isis_ext_info
*info
= rn
->info
;
838 uint32_t metric
= info
->metric
;
839 if (metric
> MAX_WIDE_PATH_METRIC
)
840 metric
= MAX_WIDE_PATH_METRIC
;
841 if (area
->oldmetric
&& metric
> 0x3f)
845 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
847 if (area
->newmetric
) {
848 struct sr_prefix_cfg
*pcfg
= NULL
;
850 if (area
->srdb
.enabled
)
851 pcfg
= isis_sr_cfg_prefix_find(area
, ipv4
);
853 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
, metric
,
859 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
860 struct isis_area
*area
)
862 struct route_table
*er_table
=
863 get_ext_reach(area
, AF_INET6
, lsp
->level
);
867 for (struct route_node
*rn
= route_top(er_table
); rn
;
868 rn
= srcdest_route_next(rn
)) {
871 struct isis_ext_info
*info
= rn
->info
;
872 struct prefix_ipv6
*p
, *src_p
;
874 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
875 (const struct prefix
**)&src_p
);
877 uint32_t metric
= info
->metric
;
878 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
879 metric
= MAX_WIDE_PATH_METRIC
;
881 if (!src_p
|| !src_p
->prefixlen
) {
882 struct sr_prefix_cfg
*pcfg
= NULL
;
884 if (area
->srdb
.enabled
)
885 pcfg
= isis_sr_cfg_prefix_find(area
, p
);
887 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
888 isis_area_ipv6_topology(area
),
889 p
, metric
, true, pcfg
);
890 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
891 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
898 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
900 lsp_build_ext_reach_ipv4(lsp
, area
);
901 lsp_build_ext_reach_ipv6(lsp
, area
);
904 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
905 struct isis_area
*area
, int level
)
907 struct isis_lsp
*lsp
;
908 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
910 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
911 LSP_FRAGMENT(frag_id
) = frag_num
;
913 lsp
= lsp_search(&area
->lspdb
[level
- 1], frag_id
);
916 if (!lsp
->lspu
.zero_lsp
)
917 lsp_link_fragment(lsp
, lsp0
);
921 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
922 lsp_bits_generate(level
, area
->overload_bit
,
923 area
->attached_bit_send
, area
),
926 lsp_insert(&area
->lspdb
[level
- 1], lsp
);
931 * Builds the LSP data part. This func creates a new frag whenever
932 * area->lsp_frag_threshold is exceeded.
934 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
936 int level
= lsp
->level
;
937 struct listnode
*node
;
938 struct isis_lsp
*frag
;
941 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
942 lsp_clear_data(frag
);
944 lsp
->tlvs
= isis_alloc_tlvs();
945 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
946 area
->area_tag
, level
);
948 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
949 area
->attached_bit_send
, area
);
953 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
955 /* Protocols Supported */
956 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
957 struct nlpids nlpids
= {.count
= 0};
959 if (area
->ip_circuits
> 0) {
961 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
963 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
966 if (area
->ipv6_circuits
> 0) {
968 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
970 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
973 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
976 if (area_is_mt(area
)) {
977 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
979 struct isis_area_mt_setting
**mt_settings
;
980 unsigned int mt_count
;
982 mt_settings
= area_mt_settings(area
, &mt_count
);
983 for (unsigned int i
= 0; i
< mt_count
; i
++) {
984 isis_tlvs_add_mt_router_info(
985 lsp
->tlvs
, mt_settings
[i
]->mtid
,
986 mt_settings
[i
]->overload
, false);
987 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
988 isis_mtid2str(mt_settings
[i
]->mtid
));
991 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
994 /* Dynamic Hostname */
995 if (area
->dynhostname
) {
996 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
997 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
998 area
->area_tag
, cmd_hostname_get());
1000 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1004 /* Add Router Capability TLV. */
1005 if (area
->isis
->router_id
!= 0) {
1006 struct isis_router_cap cap
= {};
1008 cap
.router_id
.s_addr
= area
->isis
->router_id
;
1010 /* Add SR Sub-TLVs if SR is enabled. */
1011 if (area
->srdb
.enabled
) {
1012 struct isis_sr_db
*srdb
= &area
->srdb
;
1013 uint32_t range_size
;
1016 range_size
= srdb
->config
.srgb_upper_bound
1017 - srdb
->config
.srgb_lower_bound
+ 1;
1018 cap
.srgb
.flags
= ISIS_SUBTLV_SRGB_FLAG_I
1019 | ISIS_SUBTLV_SRGB_FLAG_V
;
1020 cap
.srgb
.range_size
= range_size
;
1021 cap
.srgb
.lower_bound
= srdb
->config
.srgb_lower_bound
;
1022 /* Then Algorithm */
1023 cap
.algo
[0] = SR_ALGORITHM_SPF
;
1024 cap
.algo
[1] = SR_ALGORITHM_UNSET
;
1027 range_size
= srdb
->config
.srlb_upper_bound
1028 - srdb
->config
.srlb_lower_bound
+ 1;
1029 cap
.srlb
.range_size
= range_size
;
1030 cap
.srlb
.lower_bound
= srdb
->config
.srlb_lower_bound
;
1031 /* And finally MSD */
1032 cap
.msd
= srdb
->config
.msd
;
1035 isis_tlvs_set_router_capability(lsp
->tlvs
, &cap
);
1036 lsp_debug("ISIS (%s): Adding Router Capabilities information",
1040 /* IPv4 address and TE router ID TLVs.
1041 * In case of the first one we don't follow "C" vendor,
1042 * but "J" vendor behavior - one IPv4 address is put
1043 * into LSP. TE router ID will be the same if MPLS-TE
1044 * is not activate or MPLS-TE router-id not specified
1046 if (area
->isis
->router_id
!= 0) {
1047 struct in_addr id
= {.s_addr
= area
->isis
->router_id
};
1048 lsp_debug("ISIS (%s): Adding router ID %pI4 as IPv4 tlv.",
1049 area
->area_tag
, &id
);
1050 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
1052 /* If new style TLV's are in use, add TE router ID TLV
1053 * Check if MPLS-TE is activate and mpls-te router-id set
1054 * otherwise add exactly same data as for IPv4 address
1056 if (area
->newmetric
) {
1057 if (IS_MPLS_TE(area
->mta
)
1058 && area
->mta
->router_id
.s_addr
!= INADDR_ANY
)
1059 id
.s_addr
= area
->mta
->router_id
.s_addr
;
1061 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1063 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
1066 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1070 if (IS_MPLS_TE(area
->mta
)
1071 && !IN6_IS_ADDR_UNSPECIFIED(&area
->mta
->router_id_ipv6
)) {
1072 lsp_debug("ISIS (%s): Adding IPv6 TE Router ID tlv.",
1074 isis_tlvs_set_te_router_id_ipv6(lsp
->tlvs
,
1075 &area
->mta
->router_id_ipv6
);
1078 lsp_debug("ISIS (%s): Adding circuit specific information.",
1083 "ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
1084 area
->area_tag
, fabricd_tier(area
));
1085 isis_tlvs_add_spine_leaf(lsp
->tlvs
, fabricd_tier(area
), true,
1086 false, false, false);
1089 struct isis_circuit
*circuit
;
1090 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
1091 if (!circuit
->interface
)
1093 "ISIS (%s): Processing %s circuit %p with unknown interface",
1095 circuit_type2string(circuit
->circ_type
),
1098 lsp_debug("ISIS (%s): Processing %s circuit %s",
1100 circuit_type2string(circuit
->circ_type
),
1101 circuit
->interface
->name
);
1103 if (circuit
->state
!= C_STATE_UP
) {
1104 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1109 uint32_t metric
= area
->oldmetric
1110 ? circuit
->metric
[level
- 1]
1111 : circuit
->te_metric
[level
- 1];
1113 if (circuit
->ip_router
&& circuit
->ip_addrs
1114 && circuit
->ip_addrs
->count
> 0) {
1116 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1118 struct listnode
*ipnode
;
1119 struct prefix_ipv4
*ipv4
;
1120 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
1122 if (area
->oldmetric
) {
1124 "ISIS (%s): Adding old-style IP reachability for %pFX",
1125 area
->area_tag
, ipv4
);
1126 isis_tlvs_add_oldstyle_ip_reach(
1127 lsp
->tlvs
, ipv4
, metric
);
1130 if (area
->newmetric
) {
1131 struct sr_prefix_cfg
*pcfg
= NULL
;
1134 "ISIS (%s): Adding te-style IP reachability for %pFX",
1135 area
->area_tag
, ipv4
);
1137 if (area
->srdb
.enabled
)
1138 pcfg
= isis_sr_cfg_prefix_find(
1141 isis_tlvs_add_extended_ip_reach(
1142 lsp
->tlvs
, ipv4
, metric
, false,
1148 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1149 && circuit
->ipv6_non_link
->count
> 0) {
1150 struct listnode
*ipnode
;
1151 struct prefix_ipv6
*ipv6
;
1153 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1155 struct sr_prefix_cfg
*pcfg
= NULL
;
1158 "ISIS (%s): Adding IPv6 reachability for %pFX",
1159 area
->area_tag
, ipv6
);
1161 if (area
->srdb
.enabled
)
1162 pcfg
= isis_sr_cfg_prefix_find(area
,
1165 isis_tlvs_add_ipv6_reach(
1167 isis_area_ipv6_topology(area
), ipv6
,
1168 metric
, false, pcfg
);
1172 switch (circuit
->circ_type
) {
1173 case CIRCUIT_T_BROADCAST
:
1174 if (level
& circuit
->is_type
) {
1176 (level
== IS_LEVEL_1
)
1177 ? circuit
->u
.bc
.l1_desig_is
1178 : circuit
->u
.bc
.l2_desig_is
;
1180 if (LSP_PSEUDO_ID(ne_id
)) {
1181 if (area
->oldmetric
) {
1183 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1186 LSP_PSEUDO_ID(ne_id
));
1187 isis_tlvs_add_oldstyle_reach(
1191 if (area
->newmetric
)
1194 level
, ne_id
, metric
);
1198 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1202 case CIRCUIT_T_P2P
: {
1203 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1204 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1205 && (level
& nei
->circuit_t
)) {
1207 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1208 LSP_PSEUDO_ID(ne_id
) = 0;
1210 if (area
->oldmetric
) {
1212 "ISIS (%s): Adding old-style is reach for %s",
1214 sysid_print(ne_id
));
1215 isis_tlvs_add_oldstyle_reach(
1216 lsp
->tlvs
, ne_id
, metric
);
1218 if (area
->newmetric
) {
1219 uint32_t neighbor_metric
;
1220 if (fabricd_tier(area
) == 0) {
1221 neighbor_metric
= 0xffe;
1223 neighbor_metric
= metric
;
1226 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1227 ne_id
, neighbor_metric
);
1231 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1235 case CIRCUIT_T_LOOPBACK
:
1238 zlog_warn("lsp_area_create: unknown circuit type");
1242 lsp_build_ext_reach(lsp
, area
);
1244 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1247 lsp_adjust_stream(lsp
);
1249 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1250 lsp_clear_data(lsp
);
1252 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1254 zlog_warn("BUG: could not fragment own LSP:");
1255 log_multiline(LOG_WARNING
, " ", "%s",
1256 isis_format_tlvs(tlvs
));
1257 isis_free_tlvs(tlvs
);
1260 isis_free_tlvs(tlvs
);
1262 bool fragment_overflow
= false;
1264 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1265 if (node
!= listhead(fragments
)) {
1266 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1267 if (!fragment_overflow
) {
1268 fragment_overflow
= true;
1270 "ISIS (%s): Too much information for 256 fragments",
1273 isis_free_tlvs(tlvs
);
1277 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1279 lsp_adjust_stream(frag
);
1284 list_delete(&fragments
);
1285 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1291 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1293 int lsp_generate(struct isis_area
*area
, int level
)
1295 struct isis_lsp
*oldlsp
, *newlsp
;
1296 uint32_t seq_num
= 0;
1297 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1298 uint16_t rem_lifetime
, refresh_time
;
1300 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1303 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1305 memcpy(&lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1307 /* only builds the lsp if the area shares the level */
1308 oldlsp
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
1310 /* FIXME: we should actually initiate a purge */
1311 seq_num
= oldlsp
->hdr
.seqno
;
1312 lsp_search_and_destroy(&area
->lspdb
[level
- 1],
1313 oldlsp
->hdr
.lsp_id
);
1315 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1316 newlsp
= lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1317 lsp_bits_generate(area
->is_type
, area
->overload_bit
,
1318 area
->attached_bit_send
, area
),
1320 newlsp
->area
= area
;
1321 newlsp
->own_lsp
= 1;
1323 lsp_insert(&area
->lspdb
[level
- 1], newlsp
);
1324 /* build_lsp_data (newlsp, area); */
1325 lsp_build(newlsp
, area
);
1326 /* time to calculate our checksum */
1327 lsp_seqno_update(newlsp
);
1328 newlsp
->last_generated
= time(NULL
);
1329 lsp_flood(newlsp
, NULL
);
1330 area
->lsp_gen_count
[level
- 1]++;
1332 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1334 thread_cancel(&area
->t_lsp_refresh
[level
- 1]);
1335 area
->lsp_regenerate_pending
[level
- 1] = 0;
1336 thread_add_timer(master
, lsp_refresh
,
1337 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1338 &area
->t_lsp_refresh
[level
- 1]);
1340 if (IS_DEBUG_UPDATE_PACKETS
) {
1341 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1342 area
->area_tag
, level
,
1343 rawlspid_print(newlsp
->hdr
.lsp_id
),
1344 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1345 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1349 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1350 area
->area_tag
, level
);
1353 /* send northbound notification */
1354 isis_notif_lsp_gen(area
, newlsp
->hdr
.lsp_id
, newlsp
->hdr
.seqno
,
1355 newlsp
->last_generated
);
1356 #endif /* ifndef FABRICD */
1362 * Search own LSPs, update holding time and flood
1364 static int lsp_regenerate(struct isis_area
*area
, int level
)
1366 struct lspdb_head
*head
;
1367 struct isis_lsp
*lsp
, *frag
;
1368 struct listnode
*node
;
1369 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1370 uint16_t rem_lifetime
, refresh_time
;
1372 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1375 head
= &area
->lspdb
[level
- 1];
1376 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1377 memcpy(lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1379 lsp
= lsp_search(head
, lspid
);
1382 flog_err(EC_LIB_DEVELOPMENT
,
1383 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1384 area
->area_tag
, level
);
1388 lsp_clear_data(lsp
);
1389 lsp_build(lsp
, area
);
1390 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1391 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1392 lsp
->last_generated
= time(NULL
);
1393 lsp_flood(lsp
, NULL
);
1394 area
->lsp_gen_count
[level
- 1]++;
1395 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1397 /* Updating and flooding should only affect fragments
1403 frag
->hdr
.lsp_bits
=
1404 lsp_bits_generate(level
, area
->overload_bit
,
1405 area
->attached_bit_send
, area
);
1406 /* Set the lifetime values of all the fragments to the same
1408 * so that no fragment expires before the lsp is refreshed.
1410 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1411 frag
->age_out
= ZERO_AGE_LIFETIME
;
1412 lsp_flood(frag
, NULL
);
1414 lsp_seqno_update(lsp
);
1416 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1417 thread_add_timer(master
, lsp_refresh
,
1418 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1419 &area
->t_lsp_refresh
[level
- 1]);
1420 area
->lsp_regenerate_pending
[level
- 1] = 0;
1422 if (IS_DEBUG_UPDATE_PACKETS
) {
1424 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1425 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1426 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1427 lsp
->hdr
.rem_lifetime
, refresh_time
);
1430 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1431 area
->area_tag
, level
);
1437 * Something has changed or periodic refresh -> regenerate LSP
1439 static int lsp_refresh(struct thread
*thread
)
1441 struct lsp_refresh_arg
*arg
= THREAD_ARG(thread
);
1445 struct isis_area
*area
= arg
->area
;
1449 int level
= arg
->level
;
1451 area
->t_lsp_refresh
[level
- 1] = NULL
;
1452 area
->lsp_regenerate_pending
[level
- 1] = 0;
1454 if ((area
->is_type
& level
) == 0)
1458 * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
1461 if (monotime_since(&area
->last_lsp_refresh_event
[level
- 1], NULL
)
1463 && !(area
->bfd_force_spf_refresh
)) {
1464 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1465 area
->area_tag
, level
);
1466 _lsp_regenerate_schedule(area
, level
, 0, false,
1467 __func__
, __FILE__
, __LINE__
);
1472 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1473 area
->area_tag
, level
);
1474 return lsp_regenerate(area
, level
);
1477 int _lsp_regenerate_schedule(struct isis_area
*area
, int level
,
1478 int all_pseudo
, bool postpone
,
1479 const char *func
, const char *file
,
1482 struct isis_lsp
*lsp
;
1483 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1486 struct listnode
*cnode
;
1487 struct isis_circuit
*circuit
;
1494 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
1495 area
->area_tag
, circuit_t2string(level
),
1496 all_pseudo
? "" : "not ",
1499 memcpy(id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1500 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1503 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1504 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1508 monotime(&area
->last_lsp_refresh_event
[lvl
- 1]);
1512 "ISIS (%s): Checking whether L%d needs to be scheduled",
1513 area
->area_tag
, lvl
);
1515 if (area
->lsp_regenerate_pending
[lvl
- 1]
1516 && !(area
->bfd_signalled_down
)) {
1518 * Note: in case of a BFD 'down' message the refresh is
1519 * scheduled once again just to be sure
1521 struct timeval remain
= thread_timer_remain(
1522 area
->t_lsp_refresh
[lvl
- 1]);
1524 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1525 area
->area_tag
, (long long)remain
.tv_sec
,
1526 (long long)remain
.tv_usec
/ 1000);
1530 lsp
= lsp_search(&area
->lspdb
[lvl
- 1], id
);
1533 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1539 * Throttle avoidance
1542 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1543 area
->area_tag
, (long long)lsp
->last_generated
,
1545 thread_cancel(&area
->t_lsp_refresh
[lvl
- 1]);
1546 diff
= now
- lsp
->last_generated
;
1547 if (diff
< area
->lsp_gen_interval
[lvl
- 1]
1548 && !(area
->bfd_signalled_down
)) {
1550 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1552 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1553 area
->area_tag
, timeout
);
1556 * Schedule LSP refresh ASAP
1558 if (area
->bfd_signalled_down
) {
1560 "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
1562 area
->bfd_signalled_down
= false;
1563 area
->bfd_force_spf_refresh
= true;
1566 int64_t time_since_last
= monotime_since(
1567 &area
->last_lsp_refresh_event
[lvl
- 1],
1569 timeout
= time_since_last
< 100000L
1570 ? (100000L - time_since_last
)/1000
1574 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
1575 area
->area_tag
, timeout
);
1578 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
1583 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1584 thread_add_timer_msec(master
, lsp_refresh
,
1585 &area
->lsp_refresh_arg
[lvl
- 1],
1587 &area
->t_lsp_refresh
[lvl
- 1]);
1591 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1592 lsp_regenerate_schedule_pseudo(circuit
, level
);
1599 * Funcs for pseudonode LSPs
1603 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1605 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1608 struct isis_adjacency
*adj
;
1609 struct list
*adj_list
;
1610 struct listnode
*node
;
1611 struct isis_area
*area
= circuit
->area
;
1614 lsp_clear_data(lsp
);
1615 lsp
->tlvs
= isis_alloc_tlvs();
1617 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1618 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1619 circuit
->interface
->name
, level
);
1622 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1623 lsp
->hdr
.lsp_bits
= lsp_bits_generate(
1624 level
, 0, circuit
->area
->attached_bit_send
, area
);
1627 * add self to IS neighbours
1629 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1631 memcpy(ne_id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1632 LSP_PSEUDO_ID(ne_id
) = 0;
1634 if (circuit
->area
->oldmetric
) {
1635 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1637 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1638 area
->area_tag
, sysid_print(ne_id
),
1639 LSP_PSEUDO_ID(ne_id
));
1641 if (circuit
->area
->newmetric
) {
1642 if (area_is_mt(circuit
->area
))
1643 mtid
= ISIS_MT_IPV4_UNICAST
;
1645 mtid
= ISIS_MT_DISABLE
;
1646 isis_tlvs_add_extended_reach(lsp
->tlvs
, mtid
, ne_id
, 0, NULL
);
1648 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1649 area
->area_tag
, sysid_print(ne_id
),
1650 LSP_PSEUDO_ID(ne_id
));
1653 adj_list
= list_new();
1654 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1656 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1657 if (!(adj
->level
& level
)) {
1659 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1660 area
->area_tag
, sysid_print(adj
->sysid
));
1664 if (!(level
== IS_LEVEL_1
1665 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1666 && !(level
== IS_LEVEL_1
1667 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1668 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1669 && !(level
== IS_LEVEL_2
1670 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1672 "ISIS (%s): Ignoring neighbor %s, level does not match",
1673 area
->area_tag
, sysid_print(adj
->sysid
));
1677 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1678 if (circuit
->area
->oldmetric
) {
1679 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1681 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1682 area
->area_tag
, sysid_print(ne_id
),
1683 LSP_PSEUDO_ID(ne_id
));
1685 if (circuit
->area
->newmetric
) {
1686 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1687 ISIS_MT_IPV4_UNICAST
,
1690 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1691 area
->area_tag
, sysid_print(ne_id
),
1692 LSP_PSEUDO_ID(ne_id
));
1695 list_delete(&adj_list
);
1699 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1701 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1702 struct isis_lsp
*lsp
;
1703 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1704 uint16_t rem_lifetime
, refresh_time
;
1706 if ((circuit
->is_type
& level
) != level
1707 || (circuit
->state
!= C_STATE_UP
)
1708 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1709 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1712 memcpy(lsp_id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1713 LSP_FRAGMENT(lsp_id
) = 0;
1714 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1717 * If for some reason have a pseudo LSP in the db already -> regenerate
1719 if (lsp_search(head
, lsp_id
))
1720 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1722 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1723 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1724 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1725 lsp_bits_generate(circuit
->area
->is_type
, 0,
1726 circuit
->area
->attached_bit_send
,
1729 lsp
->area
= circuit
->area
;
1731 lsp_build_pseudo(lsp
, circuit
, level
);
1734 lsp_insert(head
, lsp
);
1735 lsp_flood(lsp
, NULL
);
1737 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1738 thread_cancel(&circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1739 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1740 if (level
== IS_LEVEL_1
)
1742 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1743 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1744 else if (level
== IS_LEVEL_2
)
1746 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1747 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1749 if (IS_DEBUG_UPDATE_PACKETS
) {
1751 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1752 circuit
->area
->area_tag
, level
,
1753 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1754 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1755 lsp
->hdr
.rem_lifetime
, refresh_time
);
1761 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1763 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1764 struct isis_lsp
*lsp
;
1765 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1766 uint16_t rem_lifetime
, refresh_time
;
1768 if ((circuit
->is_type
& level
) != level
1769 || (circuit
->state
!= C_STATE_UP
)
1770 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1771 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1774 memcpy(lsp_id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1775 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1776 LSP_FRAGMENT(lsp_id
) = 0;
1778 lsp
= lsp_search(head
, lsp_id
);
1781 flog_err(EC_LIB_DEVELOPMENT
,
1782 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1783 rawlspid_print(lsp_id
));
1787 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1788 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1789 lsp_build_pseudo(lsp
, circuit
, level
);
1790 lsp_inc_seqno(lsp
, 0);
1791 lsp
->last_generated
= time(NULL
);
1792 lsp_flood(lsp
, NULL
);
1794 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1795 if (level
== IS_LEVEL_1
)
1797 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1798 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1799 else if (level
== IS_LEVEL_2
)
1801 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1802 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1804 if (IS_DEBUG_UPDATE_PACKETS
) {
1806 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1807 circuit
->area
->area_tag
, level
,
1808 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1809 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1810 lsp
->hdr
.rem_lifetime
, refresh_time
);
1817 * Something has changed or periodic refresh -> regenerate pseudo LSP
1819 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1821 struct isis_circuit
*circuit
;
1822 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1824 circuit
= THREAD_ARG(thread
);
1826 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1827 circuit
->lsp_regenerate_pending
[0] = 0;
1829 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1830 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1831 memcpy(id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1832 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1833 LSP_FRAGMENT(id
) = 0;
1834 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1838 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1841 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1843 struct isis_circuit
*circuit
;
1844 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1846 circuit
= THREAD_ARG(thread
);
1848 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1849 circuit
->lsp_regenerate_pending
[1] = 0;
1851 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1852 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1853 memcpy(id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1854 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1855 LSP_FRAGMENT(id
) = 0;
1856 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1860 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1863 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1865 struct isis_lsp
*lsp
;
1866 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1870 struct isis_area
*area
= circuit
->area
;
1872 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1873 || circuit
->state
!= C_STATE_UP
)
1877 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1878 area
->area_tag
, circuit_t2string(level
),
1879 circuit
->interface
->name
);
1881 memcpy(lsp_id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1882 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1883 LSP_FRAGMENT(lsp_id
) = 0;
1886 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1888 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1889 area
->area_tag
, lvl
);
1891 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1892 sched_debug("ISIS (%s): Level is not active on circuit",
1897 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1899 "ISIS (%s): This IS is not DR, nothing to do.",
1904 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1905 struct timeval remain
= thread_timer_remain(
1906 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1908 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1909 area
->area_tag
, (long long)remain
.tv_sec
,
1910 (long long)remain
.tv_usec
/ 1000);
1914 lsp
= lsp_search(&circuit
->area
->lspdb
[lvl
- 1], lsp_id
);
1917 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1923 * Throttle avoidance
1926 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1927 area
->area_tag
, (long long)lsp
->last_generated
,
1929 thread_cancel(&circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1930 diff
= now
- lsp
->last_generated
;
1931 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1933 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1936 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1937 area
->area_tag
, timeout
);
1941 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
1942 area
->area_tag
, timeout
);
1945 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1947 if (lvl
== IS_LEVEL_1
) {
1948 thread_add_timer_msec(
1949 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1950 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1951 } else if (lvl
== IS_LEVEL_2
) {
1952 thread_add_timer_msec(
1953 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1954 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1962 * Walk through LSPs for an area
1963 * - set remaining lifetime
1965 int lsp_tick(struct thread
*thread
)
1967 struct isis_area
*area
;
1968 struct isis_lsp
*lsp
;
1970 uint16_t rem_lifetime
;
1971 bool fabricd_sync_incomplete
= false;
1973 area
= THREAD_ARG(thread
);
1975 area
->t_tick
= NULL
;
1976 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1978 struct isis_circuit
*fabricd_init_c
= fabricd_initial_sync_circuit(area
);
1981 * Remove LSPs which have aged out
1983 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1984 struct isis_lsp
*next
= lspdb_first(&area
->lspdb
[level
]);
1985 frr_each_from (lspdb
, &area
->lspdb
[level
], lsp
, next
) {
1987 * The lsp rem_lifetime is kept at 0 for MaxAge
1989 * ZeroAgeLifetime depending on explicit purge
1991 * natural age out. So schedule spf only once
1993 * the first time rem_lifetime becomes 0.
1995 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1999 * Schedule may run spf which should be done
2001 * the lsp rem_lifetime becomes 0 for the first
2003 * ISO 10589 - 7.3.16.4 first paragraph.
2005 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
2006 /* 7.3.16.4 a) set SRM flags on all */
2007 /* 7.3.16.4 b) retain only the header */
2008 if (lsp
->area
->purge_originator
)
2009 lsp_purge(lsp
, lsp
->level
, NULL
);
2011 lsp_flood(lsp
, NULL
);
2012 /* 7.3.16.4 c) record the time to purge
2014 isis_spf_schedule(lsp
->area
, lsp
->level
);
2017 if (lsp
->age_out
== 0) {
2019 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2020 area
->area_tag
, lsp
->level
,
2021 rawlspid_print(lsp
->hdr
.lsp_id
),
2024 /* if we're aging out fragment 0, lsp_destroy()
2025 * below will delete all other fragments too,
2026 * so we need to skip over those
2028 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
2030 !memcmp(next
->hdr
.lsp_id
,
2032 ISIS_SYS_ID_LEN
+ 1))
2034 &area
->lspdb
[level
],
2037 lspdb_del(&area
->lspdb
[level
], lsp
);
2042 if (fabricd_init_c
&& lsp
) {
2043 fabricd_sync_incomplete
|=
2044 ISIS_CHECK_FLAG(lsp
->SSNflags
,
2051 && !fabricd_sync_incomplete
2052 && !isis_tx_queue_len(fabricd_init_c
->tx_queue
)) {
2053 fabricd_initial_sync_finish(area
);
2059 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
2061 struct isis_lsp
*lsp
;
2063 lsp
= lsp_search(&circuit
->area
->lspdb
[level
- 1], id
);
2067 lsp_purge(lsp
, level
, NULL
);
2071 * Purge own LSP that is received and we don't have.
2072 * -> Do as in 7.3.16.4
2074 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
2075 struct isis_area
*area
)
2077 struct isis_lsp
*lsp
;
2080 * We need to create the LSP to be purged
2082 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
2085 lsp_adjust_stream(lsp
);
2086 lsp
->age_out
= ZERO_AGE_LIFETIME
;
2087 lsp
->area
->lsp_purge_count
[level
- 1]++;
2089 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
2090 lsp
->hdr
.rem_lifetime
= 0;
2092 lsp_purge_add_poi(lsp
, NULL
);
2096 lsp_insert(&area
->lspdb
[lsp
->level
- 1], lsp
);
2097 lsp_flood(lsp
, NULL
);
2102 void lsp_set_all_srmflags(struct isis_lsp
*lsp
, bool set
)
2104 struct listnode
*node
;
2105 struct isis_circuit
*circuit
;
2112 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2113 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
2115 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
2118 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2123 void _lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2124 const char *func
, const char *file
, int line
)
2126 if (IS_DEBUG_FLOODING
) {
2127 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2128 rawlspid_print(lsp
->hdr
.lsp_id
),
2129 circuit
? " except on " : "",
2130 circuit
? circuit
->interface
->name
: "",
2135 lsp_set_all_srmflags(lsp
, true);
2137 fabricd_lsp_flood(lsp
, circuit
);
2140 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2143 static int lsp_handle_adj_state_change(struct isis_adjacency
*adj
)
2145 lsp_regenerate_schedule(adj
->circuit
->area
, IS_LEVEL_1
| IS_LEVEL_2
, 0);
2147 /* when an adjacency state changes determine if we need to
2148 * change attach_bits in other area's LSPs
2150 isis_reset_attach_bit(adj
);
2156 * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
2157 * address-family and MT-ID.
2159 int isis_lsp_iterate_ip_reach(struct isis_lsp
*lsp
, int family
, uint16_t mtid
,
2160 lsp_ip_reach_iter_cb cb
, void *arg
)
2162 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
2163 struct isis_lsp
*frag
;
2164 struct listnode
*node
;
2166 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
2167 return LSP_ITER_CONTINUE
;
2169 /* Parse main LSP. */
2171 if (!fabricd
&& !pseudo_lsp
&& family
== AF_INET
2172 && mtid
== ISIS_MT_IPV4_UNICAST
) {
2173 struct isis_item_list
*reachs
[] = {
2174 &lsp
->tlvs
->oldstyle_ip_reach
,
2175 &lsp
->tlvs
->oldstyle_ip_reach_ext
};
2177 for (unsigned int i
= 0; i
< array_size(reachs
); i
++) {
2178 struct isis_oldstyle_ip_reach
*r
;
2180 for (r
= (struct isis_oldstyle_ip_reach
*)
2184 bool external
= i
? true : false;
2186 if ((*cb
)((struct prefix
*)&r
->prefix
,
2187 r
->metric
, external
, NULL
,
2190 return LSP_ITER_STOP
;
2195 if (!pseudo_lsp
&& family
== AF_INET
) {
2196 struct isis_item_list
*ipv4_reachs
;
2198 if (mtid
== ISIS_MT_IPV4_UNICAST
)
2199 ipv4_reachs
= &lsp
->tlvs
->extended_ip_reach
;
2201 ipv4_reachs
= isis_lookup_mt_items(
2202 &lsp
->tlvs
->mt_ip_reach
, mtid
);
2204 struct isis_extended_ip_reach
*r
;
2205 for (r
= ipv4_reachs
? (struct isis_extended_ip_reach
*)
2209 if ((*cb
)((struct prefix
*)&r
->prefix
,
2210 r
->metric
, false, r
->subtlvs
, arg
)
2212 return LSP_ITER_STOP
;
2216 if (!pseudo_lsp
&& family
== AF_INET6
) {
2217 struct isis_item_list
*ipv6_reachs
;
2218 struct isis_ipv6_reach
*r
;
2220 if (mtid
== ISIS_MT_IPV4_UNICAST
)
2221 ipv6_reachs
= &lsp
->tlvs
->ipv6_reach
;
2223 ipv6_reachs
= isis_lookup_mt_items(
2224 &lsp
->tlvs
->mt_ipv6_reach
, mtid
);
2226 for (r
= ipv6_reachs
? (struct isis_ipv6_reach
*)
2230 if ((*cb
)((struct prefix
*)&r
->prefix
,
2231 r
->metric
, r
->external
, r
->subtlvs
,
2234 return LSP_ITER_STOP
;
2239 /* Parse LSP fragments. */
2240 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2244 isis_lsp_iterate_ip_reach(frag
, family
, mtid
, cb
, arg
);
2247 return LSP_ITER_CONTINUE
;
2251 * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
2254 int isis_lsp_iterate_is_reach(struct isis_lsp
*lsp
, uint16_t mtid
,
2255 lsp_is_reach_iter_cb cb
, void *arg
)
2257 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
2258 struct isis_lsp
*frag
;
2259 struct listnode
*node
;
2260 struct isis_item
*head
;
2261 struct isis_item_list
*te_neighs
;
2263 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
2264 return LSP_ITER_CONTINUE
;
2266 /* Parse main LSP. */
2268 if (pseudo_lsp
|| mtid
== ISIS_MT_IPV4_UNICAST
) {
2269 head
= lsp
->tlvs
->oldstyle_reach
.head
;
2270 for (struct isis_oldstyle_reach
*reach
=
2271 (struct isis_oldstyle_reach
*)head
;
2272 reach
; reach
= reach
->next
) {
2273 if ((*cb
)(reach
->id
, reach
->metric
, true, NULL
,
2276 return LSP_ITER_STOP
;
2280 if (pseudo_lsp
|| mtid
== ISIS_MT_IPV4_UNICAST
)
2281 te_neighs
= &lsp
->tlvs
->extended_reach
;
2284 isis_get_mt_items(&lsp
->tlvs
->mt_reach
, mtid
);
2286 head
= te_neighs
->head
;
2287 for (struct isis_extended_reach
*reach
=
2288 (struct isis_extended_reach
*)head
;
2289 reach
; reach
= reach
->next
) {
2290 if ((*cb
)(reach
->id
, reach
->metric
, false,
2291 reach
->subtlvs
, arg
)
2293 return LSP_ITER_STOP
;
2298 /* Parse LSP fragments. */
2299 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2303 isis_lsp_iterate_is_reach(frag
, mtid
, cb
, arg
);
2306 return LSP_ITER_CONTINUE
;
2311 hook_register(isis_adj_state_change_hook
,
2312 lsp_handle_adj_state_change
);