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 static int lsp_refresh(struct thread
*thread
);
64 static int lsp_l1_refresh_pseudo(struct thread
*thread
);
65 static int lsp_l2_refresh_pseudo(struct thread
*thread
);
67 static void lsp_destroy(struct isis_lsp
*lsp
);
69 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
71 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
74 int lspdb_compare(const struct isis_lsp
*a
, const struct isis_lsp
*b
)
76 return memcmp(a
->hdr
.lsp_id
, b
->hdr
.lsp_id
, sizeof(a
->hdr
.lsp_id
));
79 void lsp_db_init(struct lspdb_head
*head
)
84 void lsp_db_fini(struct lspdb_head
*head
)
88 while ((lsp
= lspdb_pop(head
)))
93 struct isis_lsp
*lsp_search(struct lspdb_head
*head
, const uint8_t *id
)
95 struct isis_lsp searchfor
;
96 memcpy(searchfor
.hdr
.lsp_id
, id
, sizeof(searchfor
.hdr
.lsp_id
));
98 return lspdb_find(head
, &searchfor
);
101 static void lsp_clear_data(struct isis_lsp
*lsp
)
106 isis_free_tlvs(lsp
->tlvs
);
110 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
);
112 static void lsp_destroy(struct isis_lsp
*lsp
)
114 struct listnode
*cnode
;
115 struct isis_circuit
*circuit
;
120 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
, circuit
))
121 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
123 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
127 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
128 if (lsp
->lspu
.frags
) {
129 lsp_remove_frags(&lsp
->area
->lspdb
[lsp
->level
- 1],
131 list_delete(&lsp
->lspu
.frags
);
134 if (lsp
->lspu
.zero_lsp
135 && lsp
->lspu
.zero_lsp
->lspu
.frags
) {
136 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
140 isis_spf_schedule(lsp
->area
, lsp
->level
);
143 stream_free(lsp
->pdu
);
145 fabricd_lsp_free(lsp
);
146 XFREE(MTYPE_ISIS_LSP
, lsp
);
150 * Remove all the frags belonging to the given lsp
152 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
)
154 struct listnode
*lnode
, *lnnode
;
155 struct isis_lsp
*lsp
;
157 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
158 lsp
= lsp_search(head
, lsp
->hdr
.lsp_id
);
159 lspdb_del(head
, lsp
);
164 void lsp_search_and_destroy(struct lspdb_head
*head
, const uint8_t *id
)
166 struct isis_lsp
*lsp
;
168 lsp
= lsp_search(head
, id
);
170 lspdb_del(head
, lsp
);
172 * If this is a zero lsp, remove all the frags now
174 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
176 lsp_remove_frags(head
, lsp
->lspu
.frags
);
179 * else just remove this frag, from the zero lsps' frag
182 if (lsp
->lspu
.zero_lsp
183 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
184 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
192 * Compares a LSP to given values
193 * Params are given in net order
195 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
196 uint16_t checksum
, uint16_t rem_lifetime
)
198 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
199 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
200 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
201 if (IS_DEBUG_SNP_PACKETS
) {
203 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
204 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
205 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
206 lsp
->hdr
.rem_lifetime
);
208 "ISIS-Snp (%s): is equal to ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
209 areatag
, seqno
, checksum
, rem_lifetime
);
215 * LSPs with identical checksums should only be treated as newer if:
216 * a) The current LSP has a remaining lifetime != 0 and the other LSP
218 * remaining lifetime == 0. In this case, we should participate in
220 * and should not treat the current LSP with remaining lifetime == 0
222 * b) The LSP has an incorrect checksum. In this case, we need to react
226 if (seqno
> lsp
->hdr
.seqno
227 || (seqno
== lsp
->hdr
.seqno
228 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
229 || (lsp
->hdr
.checksum
!= checksum
230 && lsp
->hdr
.rem_lifetime
)))) {
231 if (IS_DEBUG_SNP_PACKETS
) {
233 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
234 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
235 checksum
, rem_lifetime
);
237 "ISIS-Snp (%s): is newer than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
238 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
239 lsp
->hdr
.rem_lifetime
);
243 if (IS_DEBUG_SNP_PACKETS
) {
244 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
245 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
246 checksum
, rem_lifetime
);
248 "ISIS-Snp (%s): is older than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
249 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
250 lsp
->hdr
.rem_lifetime
);
256 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
259 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
260 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
261 struct stream
*stream
= lsp
->pdu
;
262 size_t orig_getp
= 0, orig_endp
= 0;
265 orig_getp
= stream_get_getp(lsp
->pdu
);
266 orig_endp
= stream_get_endp(lsp
->pdu
);
269 stream_set_getp(lsp
->pdu
, 0);
270 stream_set_endp(lsp
->pdu
, 0);
272 fill_fixed_hdr(pdu_type
, stream
);
275 *len_pointer
= stream_get_endp(stream
);
276 stream_putw(stream
, hdr
->pdu_len
);
277 stream_putw(stream
, hdr
->rem_lifetime
);
278 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
279 stream_putl(stream
, hdr
->seqno
);
280 stream_putw(stream
, hdr
->checksum
);
281 stream_putc(stream
, hdr
->lsp_bits
);
284 stream_set_endp(lsp
->pdu
, orig_endp
);
285 stream_set_getp(lsp
->pdu
, orig_getp
);
289 static void lsp_add_auth(struct isis_lsp
*lsp
)
291 struct isis_passwd
*passwd
;
292 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
293 : &lsp
->area
->domain_passwd
;
294 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
297 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
300 lsp
->tlvs
= isis_alloc_tlvs();
305 put_lsp_hdr(lsp
, &len_pointer
, false);
306 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
308 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
310 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
311 stream_get_endp(lsp
->pdu
) - 12, 12));
314 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
318 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
319 newseq
= lsp
->hdr
.seqno
+ 1;
324 /* check for overflow */
325 if (newseq
< lsp
->hdr
.seqno
) {
326 /* send northbound notification */
327 isis_notif_lsp_exceed_max(lsp
->area
,
328 rawlspid_print(lsp
->hdr
.lsp_id
));
330 #endif /* ifndef FABRICD */
332 lsp
->hdr
.seqno
= newseq
;
335 isis_spf_schedule(lsp
->area
, lsp
->level
);
338 static void lsp_purge_add_poi(struct isis_lsp
*lsp
,
339 const uint8_t *sender
)
341 if (lsp
->area
== NULL
)
344 if (!lsp
->area
->purge_originator
)
347 /* add purge originator identification */
349 lsp
->tlvs
= isis_alloc_tlvs();
350 isis_tlvs_set_purge_originator(lsp
->tlvs
, lsp
->area
->isis
->sysid
,
352 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
355 static void lsp_purge(struct isis_lsp
*lsp
, int level
,
356 const uint8_t *sender
)
360 stream_reset(lsp
->pdu
);
363 lsp
->hdr
.checksum
= 0;
364 lsp
->hdr
.rem_lifetime
= 0;
366 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
367 lsp
->area
->lsp_purge_count
[level
- 1]++;
369 lsp_purge_add_poi(lsp
, sender
);
372 lsp_flood(lsp
, NULL
);
376 * Generates checksum for LSP and its frags
378 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
380 struct isis_lsp
*lsp
;
381 struct listnode
*node
;
383 lsp_inc_seqno(lsp0
, 0);
385 if (!lsp0
->lspu
.frags
)
388 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
390 lsp_inc_seqno(lsp
, 0);
391 else if (lsp
->hdr
.rem_lifetime
) {
392 /* Purge should only be applied when the fragment has
393 * non-zero remaining lifetime.
395 lsp_purge(lsp
, lsp0
->level
, NULL
);
402 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
404 uint8_t lsp_bits
= 0;
405 if (level
== IS_LEVEL_1
)
406 lsp_bits
= IS_LEVEL_1
;
408 lsp_bits
= IS_LEVEL_1_AND_2
;
410 lsp_bits
|= overload_bit
;
412 lsp_bits
|= attached_bit
;
416 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
417 struct isis_tlvs
*tlvs
, struct stream
*stream
,
418 struct isis_area
*area
, int level
)
420 /* free the old lsp data */
423 /* copying only the relevant part of our stream */
424 if (lsp
->pdu
!= NULL
)
425 stream_free(lsp
->pdu
);
426 lsp
->pdu
= stream_dup(stream
);
428 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
431 lsp
->age_out
= ZERO_AGE_LIFETIME
;
432 lsp
->installed
= time(NULL
);
436 if (area
->dynhostname
&& lsp
->tlvs
->hostname
437 && lsp
->hdr
.rem_lifetime
) {
438 isis_dynhn_insert(lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
439 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
)
448 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
450 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
451 /* zero lsp -> create list to store fragments */
452 lsp
->lspu
.frags
= list_new();
454 /* fragment -> set backpointer and add to zero lsps list */
456 lsp
->lspu
.zero_lsp
= lsp0
;
457 listnode_add(lsp0
->lspu
.frags
, lsp
);
461 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
462 struct isis_tlvs
*tlvs
, struct stream
*stream
,
463 struct isis_area
*area
, int level
, bool confusion
)
468 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
469 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
475 lsp_purge(lsp
, level
, NULL
);
477 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
480 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
481 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
482 struct isis_lsp
*lsp0
;
484 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
485 LSP_FRAGMENT(lspid
) = 0;
486 lsp0
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
488 lsp_link_fragment(lsp
, lsp0
);
492 isis_spf_schedule(lsp
->area
, lsp
->level
);
495 /* creation of LSP directly from what we received */
496 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
497 struct isis_tlvs
*tlvs
,
498 struct stream
*stream
, struct isis_lsp
*lsp0
,
499 struct isis_area
*area
, int level
)
501 struct isis_lsp
*lsp
;
503 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
504 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
505 lsp_link_fragment(lsp
, lsp0
);
510 static void lsp_adjust_stream(struct isis_lsp
*lsp
)
513 if (STREAM_SIZE(lsp
->pdu
) == LLC_LEN
+ lsp
->area
->lsp_mtu
)
515 stream_free(lsp
->pdu
);
518 lsp
->pdu
= stream_new(LLC_LEN
+ lsp
->area
->lsp_mtu
);
521 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
522 uint16_t rem_lifetime
, uint32_t seqno
,
523 uint8_t lsp_bits
, uint16_t checksum
,
524 struct isis_lsp
*lsp0
, int level
)
526 struct isis_lsp
*lsp
;
528 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
531 lsp_adjust_stream(lsp
);
533 /* Minimal LSP PDU size */
534 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
535 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
536 lsp
->hdr
.checksum
= checksum
;
537 lsp
->hdr
.seqno
= seqno
;
538 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
539 lsp
->hdr
.lsp_bits
= lsp_bits
;
541 lsp
->age_out
= ZERO_AGE_LIFETIME
;
542 lsp_link_fragment(lsp
, lsp0
);
543 put_lsp_hdr(lsp
, NULL
, false);
546 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
547 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
548 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
554 void lsp_insert(struct lspdb_head
*head
, struct isis_lsp
*lsp
)
556 lspdb_add(head
, lsp
);
558 isis_spf_schedule(lsp
->area
, lsp
->level
);
562 * Build a list of LSPs with non-zero ht bounded by start and stop ids
564 void lsp_build_list_nonzero_ht(struct lspdb_head
*head
, const uint8_t *start_id
,
565 const uint8_t *stop_id
, struct list
*list
)
567 struct isis_lsp searchfor
;
568 struct isis_lsp
*lsp
, *start
;
570 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
572 start
= lspdb_find_gteq(head
, &searchfor
);
573 frr_each_from (lspdb
, head
, lsp
, start
) {
574 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
,
575 ISIS_SYS_ID_LEN
+ 2) > 0)
578 if (lsp
->hdr
.rem_lifetime
)
579 listnode_add(list
, lsp
);
583 static void lsp_set_time(struct isis_lsp
*lsp
)
587 if (lsp
->hdr
.rem_lifetime
== 0) {
588 if (lsp
->age_out
> 0)
593 lsp
->hdr
.rem_lifetime
--;
594 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
595 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
598 void lspid_print(uint8_t *lsp_id
, char *dest
, char dynhost
, char frag
,
601 struct isis_dynhn
*dyn
= NULL
;
602 char id
[SYSID_STRLEN
];
605 dyn
= dynhn_find_by_id(lsp_id
);
610 snprintf(id
, sizeof(id
), "%.14s", dyn
->hostname
);
611 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
612 snprintf(id
, sizeof(id
), "%.14s", cmd_hostname_get());
614 memcpy(id
, sysid_print(lsp_id
), 15);
617 sprintf(dest
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
618 LSP_FRAGMENT(lsp_id
));
620 sprintf(dest
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
623 /* Convert the lsp attribute bits to attribute string */
624 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
631 if (buf_size
< 2 * 3)
634 /* we only focus on the default metric */
635 pos
+= sprintf(pos
, "%d/",
636 ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits
) ? 1 : 0);
638 pos
+= sprintf(pos
, "%d/",
639 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
641 sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
646 /* this function prints the lsp on show isis database */
647 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
,
654 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, dynhost
, 1, isis
);
655 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
656 vty_out(vty
, "%5hu ", lsp
->hdr
.pdu_len
);
657 vty_out(vty
, "0x%08x ", lsp
->hdr
.seqno
);
658 vty_out(vty
, "0x%04hx ", lsp
->hdr
.checksum
);
659 if (lsp
->hdr
.rem_lifetime
== 0) {
660 snprintf(age_out
, sizeof(age_out
), "(%d)", lsp
->age_out
);
662 vty_out(vty
, "%7s ", age_out
);
664 vty_out(vty
, " %5hu ", lsp
->hdr
.rem_lifetime
);
665 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
668 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
,
671 lsp_print(lsp
, vty
, dynhost
, isis
);
673 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
677 /* print all the lsps info in the local lspdb */
678 int lsp_print_all(struct vty
*vty
, struct lspdb_head
*head
, char detail
,
679 char dynhost
, struct isis
*isis
)
681 struct isis_lsp
*lsp
;
684 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
685 frr_each (lspdb
, head
, lsp
) {
686 lsp_print(lsp
, vty
, dynhost
, isis
);
689 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
690 frr_each (lspdb
, head
, lsp
) {
691 lsp_print_detail(lsp
, vty
, dynhost
, isis
);
699 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
701 uint16_t rem_lifetime
;
703 /* Add jitter to configured LSP lifetime */
705 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
707 /* No jitter if the max refresh will be less than configure gen interval
709 /* N.B. this calucation is acceptable since rem_lifetime is in
712 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
713 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
718 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
720 struct isis_area
*area
= lsp
->area
;
721 int level
= lsp
->level
;
722 uint16_t refresh_time
;
724 /* Add jitter to LSP refresh time */
726 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
728 /* RFC 4444 : make sure the refresh time is at least less than 300
729 * of the remaining lifetime and more than gen interval */
730 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
731 || refresh_time
> (rem_lifetime
- 300))
732 refresh_time
= rem_lifetime
- 300;
734 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
735 * we accept this violation to satisfy refresh_time <= rem_lifetime -
741 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
742 struct isis_area
*area
)
744 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
748 for (struct route_node
*rn
= route_top(er_table
); rn
;
749 rn
= route_next(rn
)) {
753 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
754 struct isis_ext_info
*info
= rn
->info
;
756 uint32_t metric
= info
->metric
;
757 if (metric
> MAX_WIDE_PATH_METRIC
)
758 metric
= MAX_WIDE_PATH_METRIC
;
759 if (area
->oldmetric
&& metric
> 0x3f)
763 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
765 if (area
->newmetric
) {
766 struct sr_prefix_cfg
*pcfg
= NULL
;
768 if (area
->srdb
.enabled
)
769 pcfg
= isis_sr_cfg_prefix_find(area
, ipv4
);
771 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
, metric
,
777 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
778 struct isis_area
*area
)
780 struct route_table
*er_table
=
781 get_ext_reach(area
, AF_INET6
, lsp
->level
);
785 for (struct route_node
*rn
= route_top(er_table
); rn
;
786 rn
= srcdest_route_next(rn
)) {
789 struct isis_ext_info
*info
= rn
->info
;
790 struct prefix_ipv6
*p
, *src_p
;
792 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
793 (const struct prefix
**)&src_p
);
795 uint32_t metric
= info
->metric
;
796 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
797 metric
= MAX_WIDE_PATH_METRIC
;
799 if (!src_p
|| !src_p
->prefixlen
) {
800 struct sr_prefix_cfg
*pcfg
= NULL
;
802 if (area
->srdb
.enabled
)
803 pcfg
= isis_sr_cfg_prefix_find(area
, p
);
805 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
806 isis_area_ipv6_topology(area
),
807 p
, metric
, true, pcfg
);
808 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
809 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
816 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
818 lsp_build_ext_reach_ipv4(lsp
, area
);
819 lsp_build_ext_reach_ipv6(lsp
, area
);
822 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
823 struct isis_area
*area
, int level
)
825 struct isis_lsp
*lsp
;
826 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
828 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
829 LSP_FRAGMENT(frag_id
) = frag_num
;
831 lsp
= lsp_search(&area
->lspdb
[level
- 1], frag_id
);
834 if (!lsp
->lspu
.zero_lsp
)
835 lsp_link_fragment(lsp
, lsp0
);
839 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
840 lsp_bits_generate(level
, area
->overload_bit
,
844 lsp_insert(&area
->lspdb
[level
- 1], lsp
);
849 * Builds the LSP data part. This func creates a new frag whenever
850 * area->lsp_frag_threshold is exceeded.
852 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
854 int level
= lsp
->level
;
855 char buf
[PREFIX2STR_BUFFER
];
856 struct listnode
*node
;
857 struct isis_lsp
*frag
;
860 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
861 lsp_clear_data(frag
);
863 lsp
->tlvs
= isis_alloc_tlvs();
864 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
865 area
->area_tag
, level
);
867 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
872 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
874 /* Protocols Supported */
875 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
876 struct nlpids nlpids
= {.count
= 0};
878 if (area
->ip_circuits
> 0) {
880 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
882 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
885 if (area
->ipv6_circuits
> 0) {
887 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
889 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
892 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
895 if (area_is_mt(area
)) {
896 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
898 struct isis_area_mt_setting
**mt_settings
;
899 unsigned int mt_count
;
901 mt_settings
= area_mt_settings(area
, &mt_count
);
902 for (unsigned int i
= 0; i
< mt_count
; i
++) {
903 isis_tlvs_add_mt_router_info(
904 lsp
->tlvs
, mt_settings
[i
]->mtid
,
905 mt_settings
[i
]->overload
, false);
906 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
907 isis_mtid2str(mt_settings
[i
]->mtid
));
910 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
913 /* Dynamic Hostname */
914 if (area
->dynhostname
) {
915 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
916 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
917 area
->area_tag
, cmd_hostname_get());
919 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
923 /* Add Router Capability TLV. */
924 if (area
->isis
->router_id
!= 0) {
925 struct isis_router_cap cap
= {};
927 cap
.router_id
.s_addr
= area
->isis
->router_id
;
929 /* Add SR Sub-TLVs if SR is enabled. */
930 if (area
->srdb
.enabled
) {
931 struct isis_sr_db
*srdb
= &area
->srdb
;
935 range_size
= srdb
->config
.srgb_upper_bound
936 - srdb
->config
.srgb_lower_bound
+ 1;
937 cap
.srgb
.flags
= ISIS_SUBTLV_SRGB_FLAG_I
938 | ISIS_SUBTLV_SRGB_FLAG_V
;
939 cap
.srgb
.range_size
= range_size
;
940 cap
.srgb
.lower_bound
= srdb
->config
.srgb_lower_bound
;
942 cap
.algo
[0] = SR_ALGORITHM_SPF
;
943 cap
.algo
[1] = SR_ALGORITHM_UNSET
;
946 range_size
= srdb
->config
.srlb_upper_bound
947 - srdb
->config
.srlb_lower_bound
+ 1;
948 cap
.srlb
.range_size
= range_size
;
949 cap
.srlb
.lower_bound
= srdb
->config
.srlb_lower_bound
;
950 /* And finally MSD */
951 cap
.msd
= srdb
->config
.msd
;
954 isis_tlvs_set_router_capability(lsp
->tlvs
, &cap
);
955 lsp_debug("ISIS (%s): Adding Router Capabilities information",
959 /* IPv4 address and TE router ID TLVs.
960 * In case of the first one we don't follow "C" vendor,
961 * but "J" vendor behavior - one IPv4 address is put
962 * into LSP. TE router ID will be the same if MPLS-TE
963 * is not activate or MPLS-TE router-id not specified
965 if (area
->isis
->router_id
!= 0) {
966 struct in_addr id
= {.s_addr
= area
->isis
->router_id
};
967 inet_ntop(AF_INET
, &id
, buf
, sizeof(buf
));
968 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
969 area
->area_tag
, buf
);
970 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
972 /* If new style TLV's are in use, add TE router ID TLV
973 * Check if MPLS-TE is activate and mpls-te router-id set
974 * otherwise add exactly same data as for IPv4 address
976 if (area
->newmetric
) {
977 if (IS_MPLS_TE(area
->mta
)
978 && area
->mta
->router_id
.s_addr
!= 0)
979 id
.s_addr
= area
->mta
->router_id
.s_addr
;
981 "ISIS (%s): Adding router ID also as TE router ID tlv.",
983 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
986 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
990 lsp_debug("ISIS (%s): Adding circuit specific information.",
995 "ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
996 area
->area_tag
, fabricd_tier(area
));
997 isis_tlvs_add_spine_leaf(lsp
->tlvs
, fabricd_tier(area
), true,
998 false, false, false);
1001 struct isis_circuit
*circuit
;
1002 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
1003 if (!circuit
->interface
)
1005 "ISIS (%s): Processing %s circuit %p with unknown interface",
1007 circuit_type2string(circuit
->circ_type
),
1010 lsp_debug("ISIS (%s): Processing %s circuit %s",
1012 circuit_type2string(circuit
->circ_type
),
1013 circuit
->interface
->name
);
1015 if (circuit
->state
!= C_STATE_UP
) {
1016 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1021 uint32_t metric
= area
->oldmetric
1022 ? circuit
->metric
[level
- 1]
1023 : circuit
->te_metric
[level
- 1];
1025 if (circuit
->ip_router
&& circuit
->ip_addrs
1026 && circuit
->ip_addrs
->count
> 0) {
1028 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1030 struct listnode
*ipnode
;
1031 struct prefix_ipv4
*ipv4
;
1032 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
1034 if (area
->oldmetric
) {
1036 "ISIS (%s): Adding old-style IP reachability for %s",
1038 prefix2str(ipv4
, buf
,
1040 isis_tlvs_add_oldstyle_ip_reach(
1041 lsp
->tlvs
, ipv4
, metric
);
1044 if (area
->newmetric
) {
1045 struct sr_prefix_cfg
*pcfg
= NULL
;
1048 "ISIS (%s): Adding te-style IP reachability for %s",
1050 prefix2str(ipv4
, buf
,
1053 if (area
->srdb
.enabled
)
1054 pcfg
= isis_sr_cfg_prefix_find(
1057 isis_tlvs_add_extended_ip_reach(
1058 lsp
->tlvs
, ipv4
, metric
, false,
1064 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1065 && circuit
->ipv6_non_link
->count
> 0) {
1066 struct listnode
*ipnode
;
1067 struct prefix_ipv6
*ipv6
;
1069 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1071 struct sr_prefix_cfg
*pcfg
= NULL
;
1074 "ISIS (%s): Adding IPv6 reachability for %s",
1076 prefix2str(ipv6
, buf
, sizeof(buf
)));
1078 if (area
->srdb
.enabled
)
1079 pcfg
= isis_sr_cfg_prefix_find(area
,
1082 isis_tlvs_add_ipv6_reach(
1084 isis_area_ipv6_topology(area
), ipv6
,
1085 metric
, false, pcfg
);
1089 switch (circuit
->circ_type
) {
1090 case CIRCUIT_T_BROADCAST
:
1091 if (level
& circuit
->is_type
) {
1093 (level
== IS_LEVEL_1
)
1094 ? circuit
->u
.bc
.l1_desig_is
1095 : circuit
->u
.bc
.l2_desig_is
;
1097 if (LSP_PSEUDO_ID(ne_id
)) {
1098 if (area
->oldmetric
) {
1100 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1103 LSP_PSEUDO_ID(ne_id
));
1104 isis_tlvs_add_oldstyle_reach(
1108 if (area
->newmetric
)
1111 level
, ne_id
, metric
);
1115 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1119 case CIRCUIT_T_P2P
: {
1120 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1121 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1122 && (level
& nei
->circuit_t
)) {
1124 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1125 LSP_PSEUDO_ID(ne_id
) = 0;
1127 if (area
->oldmetric
) {
1129 "ISIS (%s): Adding old-style is reach for %s",
1131 sysid_print(ne_id
));
1132 isis_tlvs_add_oldstyle_reach(
1133 lsp
->tlvs
, ne_id
, metric
);
1135 if (area
->newmetric
) {
1136 uint32_t neighbor_metric
;
1137 if (fabricd_tier(area
) == 0) {
1138 neighbor_metric
= 0xffe;
1140 neighbor_metric
= metric
;
1143 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1144 ne_id
, neighbor_metric
);
1148 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1152 case CIRCUIT_T_LOOPBACK
:
1155 zlog_warn("lsp_area_create: unknown circuit type");
1159 lsp_build_ext_reach(lsp
, area
);
1161 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1164 lsp_adjust_stream(lsp
);
1166 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1167 lsp_clear_data(lsp
);
1169 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1171 zlog_warn("BUG: could not fragment own LSP:");
1172 log_multiline(LOG_WARNING
, " ", "%s",
1173 isis_format_tlvs(tlvs
));
1174 isis_free_tlvs(tlvs
);
1177 isis_free_tlvs(tlvs
);
1179 bool fragment_overflow
= false;
1181 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1182 if (node
!= listhead(fragments
)) {
1183 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1184 if (!fragment_overflow
) {
1185 fragment_overflow
= true;
1187 "ISIS (%s): Too much information for 256 fragments",
1190 isis_free_tlvs(tlvs
);
1194 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1196 lsp_adjust_stream(frag
);
1201 list_delete(&fragments
);
1202 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1208 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1210 int lsp_generate(struct isis_area
*area
, int level
)
1212 struct isis_lsp
*oldlsp
, *newlsp
;
1213 uint32_t seq_num
= 0;
1214 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1215 uint16_t rem_lifetime
, refresh_time
;
1217 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1220 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1222 memcpy(&lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1224 /* only builds the lsp if the area shares the level */
1225 oldlsp
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
1227 /* FIXME: we should actually initiate a purge */
1228 seq_num
= oldlsp
->hdr
.seqno
;
1229 lsp_search_and_destroy(&area
->lspdb
[level
- 1],
1230 oldlsp
->hdr
.lsp_id
);
1232 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1234 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1235 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1237 newlsp
->area
= area
;
1238 newlsp
->own_lsp
= 1;
1240 lsp_insert(&area
->lspdb
[level
- 1], newlsp
);
1241 /* build_lsp_data (newlsp, area); */
1242 lsp_build(newlsp
, area
);
1243 /* time to calculate our checksum */
1244 lsp_seqno_update(newlsp
);
1245 newlsp
->last_generated
= time(NULL
);
1246 lsp_flood(newlsp
, NULL
);
1247 area
->lsp_gen_count
[level
- 1]++;
1249 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1251 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
1252 area
->lsp_regenerate_pending
[level
- 1] = 0;
1253 thread_add_timer(master
, lsp_refresh
,
1254 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1255 &area
->t_lsp_refresh
[level
- 1]);
1257 if (IS_DEBUG_UPDATE_PACKETS
) {
1258 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1259 area
->area_tag
, level
,
1260 rawlspid_print(newlsp
->hdr
.lsp_id
),
1261 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1262 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1266 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1267 area
->area_tag
, level
);
1270 /* send northbound notification */
1271 isis_notif_lsp_gen(area
, rawlspid_print(newlsp
->hdr
.lsp_id
),
1272 newlsp
->hdr
.seqno
, newlsp
->last_generated
);
1273 #endif /* ifndef FABRICD */
1279 * Search own LSPs, update holding time and flood
1281 static int lsp_regenerate(struct isis_area
*area
, int level
)
1283 struct lspdb_head
*head
;
1284 struct isis_lsp
*lsp
, *frag
;
1285 struct listnode
*node
;
1286 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1287 uint16_t rem_lifetime
, refresh_time
;
1289 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1292 head
= &area
->lspdb
[level
- 1];
1293 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1294 memcpy(lspid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1296 lsp
= lsp_search(head
, lspid
);
1299 flog_err(EC_LIB_DEVELOPMENT
,
1300 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1301 area
->area_tag
, level
);
1305 lsp_clear_data(lsp
);
1306 lsp_build(lsp
, area
);
1307 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1308 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1309 lsp
->last_generated
= time(NULL
);
1310 lsp_flood(lsp
, NULL
);
1311 area
->lsp_gen_count
[level
- 1]++;
1312 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1314 /* Updating and flooding should only affect fragments
1320 frag
->hdr
.lsp_bits
= lsp_bits_generate(
1321 level
, area
->overload_bit
, area
->attached_bit
);
1322 /* Set the lifetime values of all the fragments to the same
1324 * so that no fragment expires before the lsp is refreshed.
1326 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1327 frag
->age_out
= ZERO_AGE_LIFETIME
;
1328 lsp_flood(frag
, NULL
);
1330 lsp_seqno_update(lsp
);
1332 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1333 thread_add_timer(master
, lsp_refresh
,
1334 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1335 &area
->t_lsp_refresh
[level
- 1]);
1336 area
->lsp_regenerate_pending
[level
- 1] = 0;
1338 if (IS_DEBUG_UPDATE_PACKETS
) {
1340 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1341 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1342 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1343 lsp
->hdr
.rem_lifetime
, refresh_time
);
1346 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1347 area
->area_tag
, level
);
1353 * Something has changed or periodic refresh -> regenerate LSP
1355 static int lsp_refresh(struct thread
*thread
)
1357 struct lsp_refresh_arg
*arg
= THREAD_ARG(thread
);
1361 struct isis_area
*area
= arg
->area
;
1365 int level
= arg
->level
;
1367 area
->t_lsp_refresh
[level
- 1] = NULL
;
1368 area
->lsp_regenerate_pending
[level
- 1] = 0;
1370 if ((area
->is_type
& level
) == 0)
1374 * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
1377 if (monotime_since(&area
->last_lsp_refresh_event
[level
- 1], NULL
)
1379 && !(area
->bfd_force_spf_refresh
)) {
1380 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1381 area
->area_tag
, level
);
1382 _lsp_regenerate_schedule(area
, level
, 0, false,
1383 __func__
, __FILE__
, __LINE__
);
1388 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1389 area
->area_tag
, level
);
1390 return lsp_regenerate(area
, level
);
1393 int _lsp_regenerate_schedule(struct isis_area
*area
, int level
,
1394 int all_pseudo
, bool postpone
,
1395 const char *func
, const char *file
,
1398 struct isis_lsp
*lsp
;
1399 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1402 struct listnode
*cnode
;
1403 struct isis_circuit
*circuit
;
1410 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
1411 area
->area_tag
, circuit_t2string(level
),
1412 all_pseudo
? "" : "not ",
1415 memcpy(id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1416 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1419 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1420 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1424 monotime(&area
->last_lsp_refresh_event
[lvl
- 1]);
1428 "ISIS (%s): Checking whether L%d needs to be scheduled",
1429 area
->area_tag
, lvl
);
1431 if (area
->lsp_regenerate_pending
[lvl
- 1]
1432 && !(area
->bfd_signalled_down
)) {
1434 * Note: in case of a BFD 'down' message the refresh is
1435 * scheduled once again just to be sure
1437 struct timeval remain
= thread_timer_remain(
1438 area
->t_lsp_refresh
[lvl
- 1]);
1440 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1441 area
->area_tag
, (long long)remain
.tv_sec
,
1442 (long long)remain
.tv_usec
/ 1000);
1446 lsp
= lsp_search(&area
->lspdb
[lvl
- 1], id
);
1449 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1455 * Throttle avoidance
1458 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1459 area
->area_tag
, (long long)lsp
->last_generated
,
1461 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1462 diff
= now
- lsp
->last_generated
;
1463 if (diff
< area
->lsp_gen_interval
[lvl
- 1]
1464 && !(area
->bfd_signalled_down
)) {
1466 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1468 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1469 area
->area_tag
, timeout
);
1472 * Schedule LSP refresh ASAP
1476 if (area
->bfd_signalled_down
) {
1478 "ISIS (%s): Scheduling immediately due to BDF 'down' message.",
1480 area
->bfd_signalled_down
= false;
1481 area
->bfd_force_spf_refresh
= true;
1484 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
1489 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1490 thread_add_timer_msec(master
, lsp_refresh
,
1491 &area
->lsp_refresh_arg
[lvl
- 1],
1493 &area
->t_lsp_refresh
[lvl
- 1]);
1497 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1498 lsp_regenerate_schedule_pseudo(circuit
, level
);
1505 * Funcs for pseudonode LSPs
1509 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1511 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1514 struct isis_adjacency
*adj
;
1515 struct list
*adj_list
;
1516 struct listnode
*node
;
1517 struct isis_area
*area
= circuit
->area
;
1519 lsp_clear_data(lsp
);
1520 lsp
->tlvs
= isis_alloc_tlvs();
1522 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1523 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1524 circuit
->interface
->name
, level
);
1527 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1529 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
1532 * add self to IS neighbours
1534 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1536 memcpy(ne_id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1537 LSP_PSEUDO_ID(ne_id
) = 0;
1539 if (circuit
->area
->oldmetric
) {
1540 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1542 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1543 area
->area_tag
, sysid_print(ne_id
),
1544 LSP_PSEUDO_ID(ne_id
));
1546 if (circuit
->area
->newmetric
) {
1547 isis_tlvs_add_extended_reach(lsp
->tlvs
, ISIS_MT_IPV4_UNICAST
,
1550 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1551 area
->area_tag
, sysid_print(ne_id
),
1552 LSP_PSEUDO_ID(ne_id
));
1555 adj_list
= list_new();
1556 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1558 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1559 if (!(adj
->level
& level
)) {
1561 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1562 area
->area_tag
, sysid_print(adj
->sysid
));
1566 if (!(level
== IS_LEVEL_1
1567 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1568 && !(level
== IS_LEVEL_1
1569 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1570 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1571 && !(level
== IS_LEVEL_2
1572 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1574 "ISIS (%s): Ignoring neighbor %s, level does not match",
1575 area
->area_tag
, sysid_print(adj
->sysid
));
1579 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1580 if (circuit
->area
->oldmetric
) {
1581 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1583 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1584 area
->area_tag
, sysid_print(ne_id
),
1585 LSP_PSEUDO_ID(ne_id
));
1587 if (circuit
->area
->newmetric
) {
1588 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1589 ISIS_MT_IPV4_UNICAST
,
1592 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1593 area
->area_tag
, sysid_print(ne_id
),
1594 LSP_PSEUDO_ID(ne_id
));
1597 list_delete(&adj_list
);
1601 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1603 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1604 struct isis_lsp
*lsp
;
1605 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1606 uint16_t rem_lifetime
, refresh_time
;
1608 if ((circuit
->is_type
& level
) != level
1609 || (circuit
->state
!= C_STATE_UP
)
1610 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1611 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1614 memcpy(lsp_id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1615 LSP_FRAGMENT(lsp_id
) = 0;
1616 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1619 * If for some reason have a pseudo LSP in the db already -> regenerate
1621 if (lsp_search(head
, lsp_id
))
1622 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1624 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1625 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1626 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1627 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
1629 lsp
->area
= circuit
->area
;
1631 lsp_build_pseudo(lsp
, circuit
, level
);
1634 lsp_insert(head
, lsp
);
1635 lsp_flood(lsp
, NULL
);
1637 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1638 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1639 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1640 if (level
== IS_LEVEL_1
)
1642 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1643 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1644 else if (level
== IS_LEVEL_2
)
1646 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1647 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1649 if (IS_DEBUG_UPDATE_PACKETS
) {
1651 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1652 circuit
->area
->area_tag
, level
,
1653 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1654 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1655 lsp
->hdr
.rem_lifetime
, refresh_time
);
1661 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1663 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1664 struct isis_lsp
*lsp
;
1665 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1666 uint16_t rem_lifetime
, refresh_time
;
1668 if ((circuit
->is_type
& level
) != level
1669 || (circuit
->state
!= C_STATE_UP
)
1670 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1671 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1674 memcpy(lsp_id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1675 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1676 LSP_FRAGMENT(lsp_id
) = 0;
1678 lsp
= lsp_search(head
, lsp_id
);
1681 flog_err(EC_LIB_DEVELOPMENT
,
1682 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1683 rawlspid_print(lsp_id
));
1687 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1688 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1689 lsp_build_pseudo(lsp
, circuit
, level
);
1690 lsp_inc_seqno(lsp
, 0);
1691 lsp
->last_generated
= time(NULL
);
1692 lsp_flood(lsp
, NULL
);
1694 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1695 if (level
== IS_LEVEL_1
)
1697 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1698 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1699 else if (level
== IS_LEVEL_2
)
1701 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1702 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1704 if (IS_DEBUG_UPDATE_PACKETS
) {
1706 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1707 circuit
->area
->area_tag
, level
,
1708 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1709 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1710 lsp
->hdr
.rem_lifetime
, refresh_time
);
1717 * Something has changed or periodic refresh -> regenerate pseudo LSP
1719 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1721 struct isis_circuit
*circuit
;
1722 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1724 circuit
= THREAD_ARG(thread
);
1726 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1727 circuit
->lsp_regenerate_pending
[0] = 0;
1729 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1730 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1731 memcpy(id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1732 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1733 LSP_FRAGMENT(id
) = 0;
1734 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1738 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1741 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1743 struct isis_circuit
*circuit
;
1744 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1746 circuit
= THREAD_ARG(thread
);
1748 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1749 circuit
->lsp_regenerate_pending
[1] = 0;
1751 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1752 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1753 memcpy(id
, circuit
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1754 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1755 LSP_FRAGMENT(id
) = 0;
1756 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1760 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1763 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1765 struct isis_lsp
*lsp
;
1766 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1770 struct isis_area
*area
= circuit
->area
;
1772 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1773 || circuit
->state
!= C_STATE_UP
)
1777 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1778 area
->area_tag
, circuit_t2string(level
),
1779 circuit
->interface
->name
);
1781 memcpy(lsp_id
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1782 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1783 LSP_FRAGMENT(lsp_id
) = 0;
1786 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1788 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1789 area
->area_tag
, lvl
);
1791 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1792 sched_debug("ISIS (%s): Level is not active on circuit",
1797 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1799 "ISIS (%s): This IS is not DR, nothing to do.",
1804 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1805 struct timeval remain
= thread_timer_remain(
1806 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1808 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1809 area
->area_tag
, (long long)remain
.tv_sec
,
1810 (long long)remain
.tv_usec
/ 1000);
1814 lsp
= lsp_search(&circuit
->area
->lspdb
[lvl
- 1], lsp_id
);
1817 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1823 * Throttle avoidance
1826 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1827 area
->area_tag
, (long long)lsp
->last_generated
,
1829 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1830 diff
= now
- lsp
->last_generated
;
1831 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1833 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1836 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1837 area
->area_tag
, timeout
);
1841 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
1842 area
->area_tag
, timeout
);
1845 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1847 if (lvl
== IS_LEVEL_1
) {
1848 thread_add_timer_msec(
1849 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1850 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1851 } else if (lvl
== IS_LEVEL_2
) {
1852 thread_add_timer_msec(
1853 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1854 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1862 * Walk through LSPs for an area
1863 * - set remaining lifetime
1865 int lsp_tick(struct thread
*thread
)
1867 struct isis_area
*area
;
1868 struct isis_lsp
*lsp
;
1870 uint16_t rem_lifetime
;
1871 bool fabricd_sync_incomplete
= false;
1873 area
= THREAD_ARG(thread
);
1875 area
->t_tick
= NULL
;
1876 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1878 struct isis_circuit
*fabricd_init_c
= fabricd_initial_sync_circuit(area
);
1881 * Remove LSPs which have aged out
1883 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1884 struct isis_lsp
*next
= lspdb_first(&area
->lspdb
[level
]);
1885 frr_each_from (lspdb
, &area
->lspdb
[level
], lsp
, next
) {
1887 * The lsp rem_lifetime is kept at 0 for MaxAge
1889 * ZeroAgeLifetime depending on explicit purge
1891 * natural age out. So schedule spf only once
1893 * the first time rem_lifetime becomes 0.
1895 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1899 * Schedule may run spf which should be done
1901 * the lsp rem_lifetime becomes 0 for the first
1903 * ISO 10589 - 7.3.16.4 first paragraph.
1905 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
1906 /* 7.3.16.4 a) set SRM flags on all */
1907 /* 7.3.16.4 b) retain only the header */
1908 if (lsp
->area
->purge_originator
)
1909 lsp_purge(lsp
, lsp
->level
, NULL
);
1911 lsp_flood(lsp
, NULL
);
1912 /* 7.3.16.4 c) record the time to purge
1914 isis_spf_schedule(lsp
->area
, lsp
->level
);
1917 if (lsp
->age_out
== 0) {
1919 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
1920 area
->area_tag
, lsp
->level
,
1921 rawlspid_print(lsp
->hdr
.lsp_id
),
1924 /* if we're aging out fragment 0, lsp_destroy()
1925 * below will delete all other fragments too,
1926 * so we need to skip over those
1928 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1930 !memcmp(next
->hdr
.lsp_id
,
1932 ISIS_SYS_ID_LEN
+ 1))
1934 &area
->lspdb
[level
],
1937 lspdb_del(&area
->lspdb
[level
], lsp
);
1942 if (fabricd_init_c
&& lsp
) {
1943 fabricd_sync_incomplete
|=
1944 ISIS_CHECK_FLAG(lsp
->SSNflags
,
1951 && !fabricd_sync_incomplete
1952 && !isis_tx_queue_len(fabricd_init_c
->tx_queue
)) {
1953 fabricd_initial_sync_finish(area
);
1959 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
1961 struct isis_lsp
*lsp
;
1963 lsp
= lsp_search(&circuit
->area
->lspdb
[level
- 1], id
);
1967 lsp_purge(lsp
, level
, NULL
);
1971 * Purge own LSP that is received and we don't have.
1972 * -> Do as in 7.3.16.4
1974 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
1975 struct isis_area
*area
)
1977 struct isis_lsp
*lsp
;
1980 * We need to create the LSP to be purged
1982 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
1985 lsp_adjust_stream(lsp
);
1986 lsp
->age_out
= ZERO_AGE_LIFETIME
;
1987 lsp
->area
->lsp_purge_count
[level
- 1]++;
1989 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
1990 lsp
->hdr
.rem_lifetime
= 0;
1992 lsp_purge_add_poi(lsp
, NULL
);
1996 lsp_insert(&area
->lspdb
[lsp
->level
- 1], lsp
);
1997 lsp_flood(lsp
, NULL
);
2002 void lsp_set_all_srmflags(struct isis_lsp
*lsp
, bool set
)
2004 struct listnode
*node
;
2005 struct isis_circuit
*circuit
;
2012 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2013 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
2015 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
2018 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2023 void _lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2024 const char *func
, const char *file
, int line
)
2026 if (IS_DEBUG_FLOODING
) {
2027 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2028 rawlspid_print(lsp
->hdr
.lsp_id
),
2029 circuit
? " except on " : "",
2030 circuit
? circuit
->interface
->name
: "",
2035 lsp_set_all_srmflags(lsp
, true);
2037 fabricd_lsp_flood(lsp
, circuit
);
2040 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2043 static int lsp_handle_adj_state_change(struct isis_adjacency
*adj
)
2045 lsp_regenerate_schedule(adj
->circuit
->area
, IS_LEVEL_1
| IS_LEVEL_2
, 0);
2050 * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
2051 * address-family and MT-ID.
2053 int isis_lsp_iterate_ip_reach(struct isis_lsp
*lsp
, int family
, uint16_t mtid
,
2054 lsp_ip_reach_iter_cb cb
, void *arg
)
2056 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
2057 struct isis_lsp
*frag
;
2058 struct listnode
*node
;
2060 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
2061 return LSP_ITER_CONTINUE
;
2063 /* Parse main LSP. */
2065 if (!fabricd
&& !pseudo_lsp
&& family
== AF_INET
2066 && mtid
== ISIS_MT_IPV4_UNICAST
) {
2067 struct isis_item_list
*reachs
[] = {
2068 &lsp
->tlvs
->oldstyle_ip_reach
,
2069 &lsp
->tlvs
->oldstyle_ip_reach_ext
};
2071 for (unsigned int i
= 0; i
< array_size(reachs
); i
++) {
2072 struct isis_oldstyle_ip_reach
*r
;
2074 for (r
= (struct isis_oldstyle_ip_reach
*)
2078 bool external
= i
? true : false;
2080 if ((*cb
)((struct prefix
*)&r
->prefix
,
2081 r
->metric
, external
, NULL
,
2084 return LSP_ITER_STOP
;
2089 if (!pseudo_lsp
&& family
== AF_INET
) {
2090 struct isis_item_list
*ipv4_reachs
;
2092 if (mtid
== ISIS_MT_IPV4_UNICAST
)
2093 ipv4_reachs
= &lsp
->tlvs
->extended_ip_reach
;
2095 ipv4_reachs
= isis_lookup_mt_items(
2096 &lsp
->tlvs
->mt_ip_reach
, mtid
);
2098 struct isis_extended_ip_reach
*r
;
2099 for (r
= ipv4_reachs
? (struct isis_extended_ip_reach
*)
2103 if ((*cb
)((struct prefix
*)&r
->prefix
,
2104 r
->metric
, false, r
->subtlvs
, arg
)
2106 return LSP_ITER_STOP
;
2110 if (!pseudo_lsp
&& family
== AF_INET6
) {
2111 struct isis_item_list
*ipv6_reachs
;
2112 struct isis_ipv6_reach
*r
;
2114 if (mtid
== ISIS_MT_IPV4_UNICAST
)
2115 ipv6_reachs
= &lsp
->tlvs
->ipv6_reach
;
2117 ipv6_reachs
= isis_lookup_mt_items(
2118 &lsp
->tlvs
->mt_ipv6_reach
, mtid
);
2120 for (r
= ipv6_reachs
? (struct isis_ipv6_reach
*)
2124 if ((*cb
)((struct prefix
*)&r
->prefix
,
2125 r
->metric
, r
->external
, r
->subtlvs
,
2128 return LSP_ITER_STOP
;
2133 /* Parse LSP fragments. */
2134 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2138 isis_lsp_iterate_ip_reach(frag
, family
, mtid
, cb
, arg
);
2141 return LSP_ITER_CONTINUE
;
2145 * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
2148 int isis_lsp_iterate_is_reach(struct isis_lsp
*lsp
, uint16_t mtid
,
2149 lsp_is_reach_iter_cb cb
, void *arg
)
2151 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
2152 struct isis_lsp
*frag
;
2153 struct listnode
*node
;
2154 struct isis_item
*head
;
2155 struct isis_item_list
*te_neighs
;
2157 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
2158 return LSP_ITER_CONTINUE
;
2160 /* Parse main LSP. */
2162 if (pseudo_lsp
|| mtid
== ISIS_MT_IPV4_UNICAST
) {
2163 head
= lsp
->tlvs
->oldstyle_reach
.head
;
2164 for (struct isis_oldstyle_reach
*reach
=
2165 (struct isis_oldstyle_reach
*)head
;
2166 reach
; reach
= reach
->next
) {
2167 if ((*cb
)(reach
->id
, reach
->metric
, true, NULL
,
2170 return LSP_ITER_STOP
;
2174 if (pseudo_lsp
|| mtid
== ISIS_MT_IPV4_UNICAST
)
2175 te_neighs
= &lsp
->tlvs
->extended_reach
;
2178 isis_get_mt_items(&lsp
->tlvs
->mt_reach
, mtid
);
2180 head
= te_neighs
->head
;
2181 for (struct isis_extended_reach
*reach
=
2182 (struct isis_extended_reach
*)head
;
2183 reach
; reach
= reach
->next
) {
2184 if ((*cb
)(reach
->id
, reach
->metric
, false,
2185 reach
->subtlvs
, arg
)
2187 return LSP_ITER_STOP
;
2192 /* Parse LSP fragments. */
2193 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2197 isis_lsp_iterate_is_reach(frag
, mtid
, cb
, arg
);
2200 return LSP_ITER_CONTINUE
;
2205 hook_register(isis_adj_state_change_hook
,
2206 lsp_handle_adj_state_change
);