2 * IS-IS Rout(e)ing protocol - isis_lsp.c
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40 #include "srcdest_table.h"
41 #include "lib_errors.h"
43 #include "isisd/dict.h"
44 #include "isisd/isis_constants.h"
45 #include "isisd/isis_common.h"
46 #include "isisd/isis_flags.h"
47 #include "isisd/isis_circuit.h"
48 #include "isisd/isisd.h"
49 #include "isisd/isis_lsp.h"
50 #include "isisd/isis_pdu.h"
51 #include "isisd/isis_dynhn.h"
52 #include "isisd/isis_misc.h"
53 #include "isisd/isis_csm.h"
54 #include "isisd/isis_adjacency.h"
55 #include "isisd/isis_spf.h"
56 #include "isisd/isis_te.h"
57 #include "isisd/isis_mt.h"
58 #include "isisd/isis_tlvs.h"
59 #include "isisd/fabricd.h"
60 #include "isisd/isis_tx_queue.h"
62 static int lsp_refresh(struct thread
*thread
);
63 static int lsp_l1_refresh_pseudo(struct thread
*thread
);
64 static int lsp_l2_refresh_pseudo(struct thread
*thread
);
66 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
68 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
71 dict_t
*lsp_db_init(void)
75 dict
= dict_create(DICTCOUNT_T_MAX
, (dict_comp_t
)lsp_id_cmp
);
80 struct isis_lsp
*lsp_search(uint8_t *id
, dict_t
*lspdb
)
87 zlog_debug("searching db");
88 for (dn
= dict_first(lspdb
); dn
; dn
= dict_next(lspdb
, dn
)) {
90 rawlspid_print((uint8_t *)dnode_getkey(dn
)),
93 #endif /* EXTREME DEBUG */
95 node
= dict_lookup(lspdb
, id
);
98 return (struct isis_lsp
*)dnode_get(node
);
103 static void lsp_clear_data(struct isis_lsp
*lsp
)
108 isis_free_tlvs(lsp
->tlvs
);
112 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
);
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
->lspu
.frags
,
132 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
);
151 void lsp_db_destroy(dict_t
*lspdb
)
153 dnode_t
*dnode
, *next
;
154 struct isis_lsp
*lsp
;
156 dnode
= dict_first(lspdb
);
158 next
= dict_next(lspdb
, dnode
);
159 lsp
= dnode_get(dnode
);
161 dict_delete_free(lspdb
, dnode
);
171 * Remove all the frags belonging to the given lsp
173 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
)
176 struct listnode
*lnode
, *lnnode
;
177 struct isis_lsp
*lsp
;
179 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
180 dnode
= dict_lookup(lspdb
, lsp
->hdr
.lsp_id
);
182 dnode_destroy(dict_delete(lspdb
, dnode
));
186 void lsp_search_and_destroy(uint8_t *id
, dict_t
*lspdb
)
189 struct isis_lsp
*lsp
;
191 node
= dict_lookup(lspdb
, id
);
193 node
= dict_delete(lspdb
, node
);
194 lsp
= dnode_get(node
);
196 * If this is a zero lsp, remove all the frags now
198 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
200 lsp_remove_frags(lsp
->lspu
.frags
, lspdb
);
203 * else just remove this frag, from the zero lsps' frag
206 if (lsp
->lspu
.zero_lsp
207 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
208 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
217 * Compares a LSP to given values
218 * Params are given in net order
220 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
221 uint16_t checksum
, uint16_t rem_lifetime
)
223 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
224 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
225 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
226 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
228 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
229 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
231 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
232 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
233 lsp
->hdr
.rem_lifetime
);
235 "ISIS-Snp (%s): is equal to ours seq 0x%08" PRIx32
236 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
238 areatag
, seqno
, checksum
, rem_lifetime
);
244 * LSPs with identical checksums should only be treated as newer if:
245 * a) The current LSP has a remaining lifetime != 0 and the other LSP
247 * remaining lifetime == 0. In this case, we should participate in
249 * and should not treat the current LSP with remaining lifetime == 0
251 * b) The LSP has an incorrect checksum. In this case, we need to react
255 if (seqno
> lsp
->hdr
.seqno
256 || (seqno
== lsp
->hdr
.seqno
257 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
258 || (lsp
->hdr
.checksum
!= checksum
259 && lsp
->hdr
.rem_lifetime
)))) {
260 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
262 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
263 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
265 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
266 checksum
, rem_lifetime
);
268 "ISIS-Snp (%s): is newer than ours seq 0x%08" PRIx32
269 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
271 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
272 lsp
->hdr
.rem_lifetime
);
276 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
277 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
278 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
279 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
280 checksum
, rem_lifetime
);
282 "ISIS-Snp (%s): is older than ours seq 0x%08" PRIx32
283 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
284 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
285 lsp
->hdr
.rem_lifetime
);
291 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
294 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
295 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
296 struct stream
*stream
= lsp
->pdu
;
297 size_t orig_getp
= 0, orig_endp
= 0;
300 orig_getp
= stream_get_getp(lsp
->pdu
);
301 orig_endp
= stream_get_endp(lsp
->pdu
);
304 stream_set_getp(lsp
->pdu
, 0);
305 stream_set_endp(lsp
->pdu
, 0);
307 fill_fixed_hdr(pdu_type
, stream
);
310 *len_pointer
= stream_get_endp(stream
);
311 stream_putw(stream
, hdr
->pdu_len
);
312 stream_putw(stream
, hdr
->rem_lifetime
);
313 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
314 stream_putl(stream
, hdr
->seqno
);
315 stream_putw(stream
, hdr
->checksum
);
316 stream_putc(stream
, hdr
->lsp_bits
);
319 stream_set_endp(lsp
->pdu
, orig_endp
);
320 stream_set_getp(lsp
->pdu
, orig_getp
);
324 static void lsp_add_auth(struct isis_lsp
*lsp
)
326 struct isis_passwd
*passwd
;
327 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
328 : &lsp
->area
->domain_passwd
;
329 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
332 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
335 lsp
->tlvs
= isis_alloc_tlvs();
340 put_lsp_hdr(lsp
, &len_pointer
, false);
341 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
343 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
345 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
346 stream_get_endp(lsp
->pdu
) - 12, 12));
349 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
353 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
354 newseq
= lsp
->hdr
.seqno
+ 1;
359 /* check for overflow */
360 if (newseq
< lsp
->hdr
.seqno
) {
361 /* send northbound notification */
362 isis_notif_lsp_exceed_max(lsp
->area
,
363 rawlspid_print(lsp
->hdr
.lsp_id
));
365 #endif /* ifndef FABRICD */
367 lsp
->hdr
.seqno
= newseq
;
370 isis_spf_schedule(lsp
->area
, lsp
->level
);
373 static void lsp_purge_add_poi(struct isis_lsp
*lsp
,
374 const uint8_t *sender
)
376 if (!lsp
->area
->purge_originator
)
379 /* add purge originator identification */
381 lsp
->tlvs
= isis_alloc_tlvs();
382 isis_tlvs_set_purge_originator(lsp
->tlvs
, isis
->sysid
, sender
);
383 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
386 static void lsp_purge(struct isis_lsp
*lsp
, int level
,
387 const uint8_t *sender
)
391 stream_reset(lsp
->pdu
);
394 lsp
->hdr
.checksum
= 0;
395 lsp
->hdr
.rem_lifetime
= 0;
397 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
398 lsp
->area
->lsp_purge_count
[level
- 1]++;
400 lsp_purge_add_poi(lsp
, sender
);
403 lsp_flood(lsp
, NULL
);
407 * Generates checksum for LSP and its frags
409 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
411 struct isis_lsp
*lsp
;
412 struct listnode
*node
;
414 lsp_inc_seqno(lsp0
, 0);
416 if (!lsp0
->lspu
.frags
)
419 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
421 lsp_inc_seqno(lsp
, 0);
422 else if (lsp
->hdr
.rem_lifetime
) {
423 /* Purge should only be applied when the fragment has
424 * non-zero remaining lifetime.
426 lsp_purge(lsp
, lsp0
->level
, NULL
);
433 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
435 uint8_t lsp_bits
= 0;
436 if (level
== IS_LEVEL_1
)
437 lsp_bits
= IS_LEVEL_1
;
439 lsp_bits
= IS_LEVEL_1_AND_2
;
441 lsp_bits
|= overload_bit
;
443 lsp_bits
|= attached_bit
;
447 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
448 struct isis_tlvs
*tlvs
, struct stream
*stream
,
449 struct isis_area
*area
, int level
)
451 /* free the old lsp data */
454 /* copying only the relevant part of our stream */
455 if (lsp
->pdu
!= NULL
)
456 stream_free(lsp
->pdu
);
457 lsp
->pdu
= stream_dup(stream
);
459 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
462 lsp
->age_out
= ZERO_AGE_LIFETIME
;
463 lsp
->installed
= time(NULL
);
467 if (area
->dynhostname
&& lsp
->tlvs
->hostname
468 && lsp
->hdr
.rem_lifetime
) {
469 isis_dynhn_insert(lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
470 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
)
479 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
481 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
482 /* zero lsp -> create list to store fragments */
483 lsp
->lspu
.frags
= list_new();
485 /* fragment -> set backpointer and add to zero lsps list */
487 lsp
->lspu
.zero_lsp
= lsp0
;
488 listnode_add(lsp0
->lspu
.frags
, lsp
);
492 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
493 struct isis_tlvs
*tlvs
, struct stream
*stream
,
494 struct isis_area
*area
, int level
, bool confusion
)
499 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
500 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
506 lsp_purge(lsp
, level
, NULL
);
508 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
511 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
512 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
513 struct isis_lsp
*lsp0
;
515 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
516 LSP_FRAGMENT(lspid
) = 0;
517 lsp0
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
519 lsp_link_fragment(lsp
, lsp0
);
523 isis_spf_schedule(lsp
->area
, lsp
->level
);
526 /* creation of LSP directly from what we received */
527 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
528 struct isis_tlvs
*tlvs
,
529 struct stream
*stream
, struct isis_lsp
*lsp0
,
530 struct isis_area
*area
, int level
)
532 struct isis_lsp
*lsp
;
534 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
535 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
536 lsp_link_fragment(lsp
, lsp0
);
541 static void lsp_adjust_stream(struct isis_lsp
*lsp
)
544 if (STREAM_SIZE(lsp
->pdu
) == LLC_LEN
+ lsp
->area
->lsp_mtu
)
546 stream_free(lsp
->pdu
);
549 lsp
->pdu
= stream_new(LLC_LEN
+ lsp
->area
->lsp_mtu
);
552 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
553 uint16_t rem_lifetime
, uint32_t seqno
,
554 uint8_t lsp_bits
, uint16_t checksum
,
555 struct isis_lsp
*lsp0
, int level
)
557 struct isis_lsp
*lsp
;
559 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
562 lsp_adjust_stream(lsp
);
564 /* Minimal LSP PDU size */
565 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
566 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
567 lsp
->hdr
.checksum
= checksum
;
568 lsp
->hdr
.seqno
= seqno
;
569 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
570 lsp
->hdr
.lsp_bits
= lsp_bits
;
572 lsp
->age_out
= ZERO_AGE_LIFETIME
;
573 lsp_link_fragment(lsp
, lsp0
);
574 put_lsp_hdr(lsp
, NULL
, false);
576 if (isis
->debugs
& DEBUG_EVENTS
)
577 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
578 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
579 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
585 void lsp_insert(struct isis_lsp
*lsp
, dict_t
*lspdb
)
587 dict_alloc_insert(lspdb
, lsp
->hdr
.lsp_id
, lsp
);
589 isis_spf_schedule(lsp
->area
, lsp
->level
);
593 * Build a list of LSPs with non-zero ht bounded by start and stop ids
595 void lsp_build_list_nonzero_ht(uint8_t *start_id
, uint8_t *stop_id
,
596 struct list
*list
, dict_t
*lspdb
)
598 for (dnode_t
*curr
= dict_lower_bound(lspdb
, start_id
);
599 curr
; curr
= dict_next(lspdb
, curr
)) {
600 struct isis_lsp
*lsp
= curr
->dict_data
;
602 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
,
603 ISIS_SYS_ID_LEN
+ 2) > 0)
606 if (lsp
->hdr
.rem_lifetime
)
607 listnode_add(list
, lsp
);
611 static void lsp_set_time(struct isis_lsp
*lsp
)
615 if (lsp
->hdr
.rem_lifetime
== 0) {
616 if (lsp
->age_out
> 0)
621 lsp
->hdr
.rem_lifetime
--;
622 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
623 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
626 void lspid_print(uint8_t *lsp_id
, char *dest
, char dynhost
, char frag
)
628 struct isis_dynhn
*dyn
= NULL
;
629 uint8_t id
[SYSID_STRLEN
];
632 dyn
= dynhn_find_by_id(lsp_id
);
637 sprintf((char *)id
, "%.14s", dyn
->hostname
);
638 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
639 sprintf((char *)id
, "%.14s", cmd_hostname_get());
641 memcpy(id
, sysid_print(lsp_id
), 15);
643 sprintf(dest
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
644 LSP_FRAGMENT(lsp_id
));
646 sprintf(dest
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
649 /* Convert the lsp attribute bits to attribute string */
650 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
657 if (buf_size
< 2 * 3)
660 /* we only focus on the default metric */
661 pos
+= sprintf(pos
, "%d/",
662 ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits
) ? 1 : 0);
664 pos
+= sprintf(pos
, "%d/",
665 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
667 sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
672 /* this function prints the lsp on show isis database */
673 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
679 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, dynhost
, 1);
680 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
681 vty_out(vty
, "%5" PRIu16
" ", lsp
->hdr
.pdu_len
);
682 vty_out(vty
, "0x%08" PRIx32
" ", lsp
->hdr
.seqno
);
683 vty_out(vty
, "0x%04" PRIx16
" ", lsp
->hdr
.checksum
);
684 if (lsp
->hdr
.rem_lifetime
== 0) {
685 snprintf(age_out
, 8, "(%d)", lsp
->age_out
);
687 vty_out(vty
, "%7s ", age_out
);
689 vty_out(vty
, " %5" PRIu16
" ", lsp
->hdr
.rem_lifetime
);
690 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
693 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
695 lsp_print(lsp
, vty
, dynhost
);
697 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
701 /* print all the lsps info in the local lspdb */
702 int lsp_print_all(struct vty
*vty
, dict_t
*lspdb
, char detail
, char dynhost
)
705 dnode_t
*node
= dict_first(lspdb
), *next
;
708 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
709 while (node
!= NULL
) {
710 /* I think it is unnecessary, so I comment it out */
711 /* dict_contains (lspdb, node); */
712 next
= dict_next(lspdb
, node
);
713 lsp_print(dnode_get(node
), vty
, dynhost
);
717 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
718 while (node
!= NULL
) {
719 next
= dict_next(lspdb
, node
);
720 lsp_print_detail(dnode_get(node
), vty
, dynhost
);
729 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
731 uint16_t rem_lifetime
;
733 /* Add jitter to configured LSP lifetime */
735 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
737 /* No jitter if the max refresh will be less than configure gen interval
739 /* N.B. this calucation is acceptable since rem_lifetime is in
742 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
743 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
748 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
750 struct isis_area
*area
= lsp
->area
;
751 int level
= lsp
->level
;
752 uint16_t refresh_time
;
754 /* Add jitter to LSP refresh time */
756 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
758 /* RFC 4444 : make sure the refresh time is at least less than 300
759 * of the remaining lifetime and more than gen interval */
760 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
761 || refresh_time
> (rem_lifetime
- 300))
762 refresh_time
= rem_lifetime
- 300;
764 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
765 * we accept this violation to satisfy refresh_time <= rem_lifetime -
771 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
772 struct isis_area
*area
)
774 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
778 for (struct route_node
*rn
= route_top(er_table
); rn
;
779 rn
= route_next(rn
)) {
783 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
784 struct isis_ext_info
*info
= rn
->info
;
786 uint32_t metric
= info
->metric
;
787 if (metric
> MAX_WIDE_PATH_METRIC
)
788 metric
= MAX_WIDE_PATH_METRIC
;
789 if (area
->oldmetric
&& metric
> 0x3f)
793 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
796 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
,
801 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
802 struct isis_area
*area
)
804 struct route_table
*er_table
=
805 get_ext_reach(area
, AF_INET6
, lsp
->level
);
809 for (struct route_node
*rn
= route_top(er_table
); rn
;
810 rn
= srcdest_route_next(rn
)) {
813 struct isis_ext_info
*info
= rn
->info
;
815 struct prefix_ipv6
*p
, *src_p
;
816 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
817 (const struct prefix
**)&src_p
);
819 uint32_t metric
= info
->metric
;
820 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
821 metric
= MAX_WIDE_PATH_METRIC
;
823 if (!src_p
|| !src_p
->prefixlen
) {
824 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
825 isis_area_ipv6_topology(area
),
827 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
828 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
835 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
837 lsp_build_ext_reach_ipv4(lsp
, area
);
838 lsp_build_ext_reach_ipv6(lsp
, area
);
841 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
842 struct isis_area
*area
, int level
)
844 struct isis_lsp
*lsp
;
845 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
847 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
848 LSP_FRAGMENT(frag_id
) = frag_num
;
850 lsp
= lsp_search(frag_id
, area
->lspdb
[level
- 1]);
853 if (!lsp
->lspu
.zero_lsp
)
854 lsp_link_fragment(lsp
, lsp0
);
858 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
859 lsp_bits_generate(level
, area
->overload_bit
,
863 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
868 * Builds the LSP data part. This func creates a new frag whenever
869 * area->lsp_frag_threshold is exceeded.
871 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
873 int level
= lsp
->level
;
874 char buf
[PREFIX2STR_BUFFER
];
875 struct listnode
*node
;
876 struct isis_lsp
*frag
;
879 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
880 lsp_clear_data(frag
);
882 lsp
->tlvs
= isis_alloc_tlvs();
883 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
884 area
->area_tag
, level
);
886 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
891 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
893 /* Protocols Supported */
894 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
895 struct nlpids nlpids
= {.count
= 0};
896 if (area
->ip_circuits
> 0) {
898 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
900 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
903 if (area
->ipv6_circuits
> 0) {
905 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
907 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
910 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
913 if (area_is_mt(area
)) {
914 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
916 struct isis_area_mt_setting
**mt_settings
;
917 unsigned int mt_count
;
919 mt_settings
= area_mt_settings(area
, &mt_count
);
920 for (unsigned int i
= 0; i
< mt_count
; i
++) {
921 isis_tlvs_add_mt_router_info(
922 lsp
->tlvs
, mt_settings
[i
]->mtid
,
923 mt_settings
[i
]->overload
, false);
924 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
925 isis_mtid2str(mt_settings
[i
]->mtid
));
928 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
931 /* Dynamic Hostname */
932 if (area
->dynhostname
) {
933 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
934 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
935 area
->area_tag
, cmd_hostname_get());
937 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
941 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
942 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
944 * LSP and this address is same as router id. */
945 if (isis
->router_id
!= 0) {
946 struct in_addr id
= {.s_addr
= isis
->router_id
};
947 inet_ntop(AF_INET
, &id
, buf
, sizeof(buf
));
948 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
949 area
->area_tag
, buf
);
950 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
952 /* Exactly same data is put into TE router ID TLV, but only if
954 * TLV's are in use. */
955 if (area
->newmetric
) {
958 "ISIS (%s): Adding router ID also as TE router ID tlv.",
960 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
963 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
967 lsp_debug("ISIS (%s): Adding circuit specific information.",
972 "ISIS (%s): Adding tier %" PRIu8
" spine-leaf-extension tlv.",
973 area
->area_tag
, fabricd_tier(area
));
974 isis_tlvs_add_spine_leaf(lsp
->tlvs
, fabricd_tier(area
), true,
975 false, false, false);
978 struct isis_circuit
*circuit
;
979 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
980 if (!circuit
->interface
)
982 "ISIS (%s): Processing %s circuit %p with unknown interface",
984 circuit_type2string(circuit
->circ_type
),
987 lsp_debug("ISIS (%s): Processing %s circuit %s",
989 circuit_type2string(circuit
->circ_type
),
990 circuit
->interface
->name
);
992 if (circuit
->state
!= C_STATE_UP
) {
993 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
998 uint32_t metric
= area
->oldmetric
999 ? circuit
->metric
[level
- 1]
1000 : circuit
->te_metric
[level
- 1];
1002 if (circuit
->ip_router
&& circuit
->ip_addrs
1003 && circuit
->ip_addrs
->count
> 0) {
1005 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1007 struct listnode
*ipnode
;
1008 struct prefix_ipv4
*ipv4
;
1009 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
1011 if (area
->oldmetric
) {
1013 "ISIS (%s): Adding old-style IP reachability for %s",
1015 prefix2str(ipv4
, buf
,
1017 isis_tlvs_add_oldstyle_ip_reach(
1018 lsp
->tlvs
, ipv4
, metric
);
1021 if (area
->newmetric
) {
1023 "ISIS (%s): Adding te-style IP reachability for %s",
1025 prefix2str(ipv4
, buf
,
1027 isis_tlvs_add_extended_ip_reach(
1028 lsp
->tlvs
, ipv4
, metric
);
1033 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1034 && circuit
->ipv6_non_link
->count
> 0) {
1035 struct listnode
*ipnode
;
1036 struct prefix_ipv6
*ipv6
;
1037 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1040 "ISIS (%s): Adding IPv6 reachability for %s",
1042 prefix2str(ipv6
, buf
, sizeof(buf
)));
1043 isis_tlvs_add_ipv6_reach(
1045 isis_area_ipv6_topology(area
), ipv6
,
1050 switch (circuit
->circ_type
) {
1051 case CIRCUIT_T_BROADCAST
:
1052 if (level
& circuit
->is_type
) {
1054 (level
== IS_LEVEL_1
)
1055 ? circuit
->u
.bc
.l1_desig_is
1056 : circuit
->u
.bc
.l2_desig_is
;
1058 if (LSP_PSEUDO_ID(ne_id
)) {
1059 if (area
->oldmetric
) {
1061 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1064 LSP_PSEUDO_ID(ne_id
));
1065 isis_tlvs_add_oldstyle_reach(
1069 if (area
->newmetric
) {
1070 uint8_t subtlvs
[256];
1073 if (IS_MPLS_TE(area
->mta
)
1074 && circuit
->interface
1076 circuit
->interface
))
1077 subtlv_len
= add_te_subtlvs(
1085 level
, ne_id
, metric
,
1086 subtlvs
, subtlv_len
);
1091 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1095 case CIRCUIT_T_P2P
: {
1096 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1097 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1098 && (level
& nei
->circuit_t
)) {
1100 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1101 LSP_PSEUDO_ID(ne_id
) = 0;
1103 if (area
->oldmetric
) {
1105 "ISIS (%s): Adding old-style is reach for %s",
1107 sysid_print(ne_id
));
1108 isis_tlvs_add_oldstyle_reach(
1109 lsp
->tlvs
, ne_id
, metric
);
1111 if (area
->newmetric
) {
1112 uint8_t subtlvs
[256];
1115 if (IS_MPLS_TE(area
->mta
)
1116 && circuit
->interface
!= NULL
1118 circuit
->interface
))
1119 /* Update Local and Remote IP
1120 * address for MPLS TE circuit
1122 /* NOTE sure that it is the
1123 * pertinent place for that
1125 /* Local IP address could be
1126 * updated in isis_circuit.c -
1127 * isis_circuit_add_addr() */
1128 /* But, where update remote IP
1129 * address ? in isis_pdu.c -
1130 * process_p2p_hello() ? */
1132 /* Add SubTLVs & Adjust real
1133 * size of SubTLVs */
1134 subtlv_len
= add_te_subtlvs(
1135 subtlvs
, circuit
->mtc
);
1137 /* Or keep only TE metric with
1138 * no SubTLVs if MPLS_TE is off
1142 uint32_t neighbor_metric
;
1143 if (fabricd_tier(area
) == 0) {
1144 neighbor_metric
= 0xffe;
1146 neighbor_metric
= metric
;
1149 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1150 ne_id
, neighbor_metric
,
1151 subtlvs
, subtlv_len
);
1155 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1159 case CIRCUIT_T_LOOPBACK
:
1162 zlog_warn("lsp_area_create: unknown circuit type");
1166 lsp_build_ext_reach(lsp
, area
);
1168 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1171 lsp_adjust_stream(lsp
);
1173 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1174 lsp_clear_data(lsp
);
1176 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1178 zlog_warn("BUG: could not fragment own LSP:");
1179 log_multiline(LOG_WARNING
, " ", "%s",
1180 isis_format_tlvs(tlvs
));
1181 isis_free_tlvs(tlvs
);
1184 isis_free_tlvs(tlvs
);
1186 bool fragment_overflow
= false;
1188 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1189 if (node
!= listhead(fragments
)) {
1190 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1191 if (!fragment_overflow
) {
1192 fragment_overflow
= true;
1194 "ISIS (%s): Too much information for 256 fragments",
1197 isis_free_tlvs(tlvs
);
1201 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1203 lsp_adjust_stream(frag
);
1208 list_delete(&fragments
);
1209 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1215 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1217 int lsp_generate(struct isis_area
*area
, int level
)
1219 struct isis_lsp
*oldlsp
, *newlsp
;
1220 uint32_t seq_num
= 0;
1221 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1222 uint16_t rem_lifetime
, refresh_time
;
1224 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1227 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1228 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1230 /* only builds the lsp if the area shares the level */
1231 oldlsp
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
1233 /* FIXME: we should actually initiate a purge */
1234 seq_num
= oldlsp
->hdr
.seqno
;
1235 lsp_search_and_destroy(oldlsp
->hdr
.lsp_id
,
1236 area
->lspdb
[level
- 1]);
1238 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1240 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1241 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1243 newlsp
->area
= area
;
1244 newlsp
->own_lsp
= 1;
1246 lsp_insert(newlsp
, area
->lspdb
[level
- 1]);
1247 /* build_lsp_data (newlsp, area); */
1248 lsp_build(newlsp
, area
);
1249 /* time to calculate our checksum */
1250 lsp_seqno_update(newlsp
);
1251 newlsp
->last_generated
= time(NULL
);
1252 lsp_flood(newlsp
, NULL
);
1253 area
->lsp_gen_count
[level
- 1]++;
1255 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1257 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
1258 area
->lsp_regenerate_pending
[level
- 1] = 0;
1259 thread_add_timer(master
, lsp_refresh
,
1260 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1261 &area
->t_lsp_refresh
[level
- 1]);
1263 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1264 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1265 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1266 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1267 area
->area_tag
, level
,
1268 rawlspid_print(newlsp
->hdr
.lsp_id
),
1269 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1270 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1274 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1275 area
->area_tag
, level
);
1278 /* send northbound notification */
1279 isis_notif_lsp_gen(area
, rawlspid_print(newlsp
->hdr
.lsp_id
),
1280 newlsp
->hdr
.seqno
, newlsp
->last_generated
);
1281 #endif /* ifndef FABRICD */
1287 * Search own LSPs, update holding time and flood
1289 static int lsp_regenerate(struct isis_area
*area
, int level
)
1292 struct isis_lsp
*lsp
, *frag
;
1293 struct listnode
*node
;
1294 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1295 uint16_t rem_lifetime
, refresh_time
;
1297 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1300 lspdb
= area
->lspdb
[level
- 1];
1302 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1303 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1305 lsp
= lsp_search(lspid
, lspdb
);
1308 flog_err(EC_LIB_DEVELOPMENT
,
1309 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1310 area
->area_tag
, level
);
1314 lsp_clear_data(lsp
);
1315 lsp_build(lsp
, area
);
1316 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1317 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1318 lsp
->last_generated
= time(NULL
);
1319 lsp_flood(lsp
, NULL
);
1320 area
->lsp_gen_count
[level
- 1]++;
1321 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1323 /* Updating and flooding should only affect fragments
1329 frag
->hdr
.lsp_bits
= lsp_bits_generate(
1330 level
, area
->overload_bit
, area
->attached_bit
);
1331 /* Set the lifetime values of all the fragments to the same
1333 * so that no fragment expires before the lsp is refreshed.
1335 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1336 frag
->age_out
= ZERO_AGE_LIFETIME
;
1337 lsp_flood(frag
, NULL
);
1339 lsp_seqno_update(lsp
);
1341 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1342 thread_add_timer(master
, lsp_refresh
,
1343 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1344 &area
->t_lsp_refresh
[level
- 1]);
1345 area
->lsp_regenerate_pending
[level
- 1] = 0;
1347 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1349 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1350 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1351 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1352 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1353 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1354 lsp
->hdr
.rem_lifetime
, refresh_time
);
1357 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1358 area
->area_tag
, level
);
1364 * Something has changed or periodic refresh -> regenerate LSP
1366 static int lsp_refresh(struct thread
*thread
)
1368 struct lsp_refresh_arg
*arg
= THREAD_ARG(thread
);
1372 struct isis_area
*area
= arg
->area
;
1376 int level
= arg
->level
;
1378 area
->t_lsp_refresh
[level
- 1] = NULL
;
1379 area
->lsp_regenerate_pending
[level
- 1] = 0;
1381 if ((area
->is_type
& level
) == 0)
1384 if (monotime_since(&area
->last_lsp_refresh_event
[level
- 1], NULL
) < 100000L) {
1385 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1386 area
->area_tag
, level
);
1387 _lsp_regenerate_schedule(area
, level
, 0, false,
1388 __func__
, __FILE__
, __LINE__
);
1393 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1394 area
->area_tag
, level
);
1395 return lsp_regenerate(area
, level
);
1398 int _lsp_regenerate_schedule(struct isis_area
*area
, int level
,
1399 int all_pseudo
, bool postpone
,
1400 const char *func
, const char *file
,
1403 struct isis_lsp
*lsp
;
1404 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1407 struct listnode
*cnode
;
1408 struct isis_circuit
*circuit
;
1415 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs"
1416 " Caller: %s %s:%d",
1417 area
->area_tag
, circuit_t2string(level
),
1418 all_pseudo
? "" : "not ",
1421 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1422 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1425 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1426 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1430 monotime(&area
->last_lsp_refresh_event
[lvl
- 1]);
1434 "ISIS (%s): Checking whether L%d needs to be scheduled",
1435 area
->area_tag
, lvl
);
1437 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
1438 struct timeval remain
= thread_timer_remain(
1439 area
->t_lsp_refresh
[lvl
- 1]);
1441 "ISIS (%s): Regeneration is already pending, nothing todo."
1442 " (Due in %lld.%03lld seconds)",
1443 area
->area_tag
, (long long)remain
.tv_sec
,
1444 (long long)remain
.tv_usec
/ 1000);
1448 lsp
= lsp_search(id
, area
->lspdb
[lvl
- 1]);
1451 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1457 * Throttle avoidance
1460 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1461 area
->area_tag
, (long long)lsp
->last_generated
,
1463 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1464 diff
= now
- lsp
->last_generated
;
1465 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
1467 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1469 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1470 area
->area_tag
, timeout
);
1473 * lsps are not regenerated if lsp_regenerate function
1475 * directly. However if the lsp_regenerate call is
1477 * later execution it works.
1481 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1482 " Scheduling for execution in %ld ms.",
1483 area
->area_tag
, timeout
);
1486 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1487 thread_add_timer_msec(master
, lsp_refresh
,
1488 &area
->lsp_refresh_arg
[lvl
- 1],
1490 &area
->t_lsp_refresh
[lvl
- 1]);
1494 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1495 lsp_regenerate_schedule_pseudo(circuit
, level
);
1502 * Funcs for pseudonode LSPs
1506 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1508 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1511 struct isis_adjacency
*adj
;
1512 struct list
*adj_list
;
1513 struct listnode
*node
;
1514 struct isis_area
*area
= circuit
->area
;
1516 lsp_clear_data(lsp
);
1517 lsp
->tlvs
= isis_alloc_tlvs();
1519 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1520 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1521 circuit
->interface
->name
, level
);
1524 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1526 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
1529 * add self to IS neighbours
1531 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1533 memcpy(ne_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1534 LSP_PSEUDO_ID(ne_id
) = 0;
1536 if (circuit
->area
->oldmetric
) {
1537 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1539 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1540 area
->area_tag
, sysid_print(ne_id
),
1541 LSP_PSEUDO_ID(ne_id
));
1543 if (circuit
->area
->newmetric
) {
1544 isis_tlvs_add_extended_reach(lsp
->tlvs
, ISIS_MT_IPV4_UNICAST
,
1547 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1548 area
->area_tag
, sysid_print(ne_id
),
1549 LSP_PSEUDO_ID(ne_id
));
1552 adj_list
= list_new();
1553 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1555 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1556 if (!(adj
->level
& level
)) {
1558 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1559 area
->area_tag
, sysid_print(adj
->sysid
));
1563 if (!(level
== IS_LEVEL_1
1564 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1565 && !(level
== IS_LEVEL_1
1566 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1567 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1568 && !(level
== IS_LEVEL_2
1569 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1571 "ISIS (%s): Ignoring neighbor %s, level does not match",
1572 area
->area_tag
, sysid_print(adj
->sysid
));
1576 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1577 if (circuit
->area
->oldmetric
) {
1578 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1580 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1581 area
->area_tag
, sysid_print(ne_id
),
1582 LSP_PSEUDO_ID(ne_id
));
1584 if (circuit
->area
->newmetric
) {
1585 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1586 ISIS_MT_IPV4_UNICAST
,
1589 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1590 area
->area_tag
, sysid_print(ne_id
),
1591 LSP_PSEUDO_ID(ne_id
));
1594 list_delete(&adj_list
);
1598 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1600 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1601 struct isis_lsp
*lsp
;
1602 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1603 uint16_t rem_lifetime
, refresh_time
;
1605 if ((circuit
->is_type
& level
) != level
1606 || (circuit
->state
!= C_STATE_UP
)
1607 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1608 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1611 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1612 LSP_FRAGMENT(lsp_id
) = 0;
1613 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1616 * If for some reason have a pseudo LSP in the db already -> regenerate
1618 if (lsp_search(lsp_id
, lspdb
))
1619 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1621 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1622 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1623 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1624 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
1626 lsp
->area
= circuit
->area
;
1628 lsp_build_pseudo(lsp
, circuit
, level
);
1631 lsp_insert(lsp
, lspdb
);
1632 lsp_flood(lsp
, NULL
);
1634 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1635 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1636 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1637 if (level
== IS_LEVEL_1
)
1639 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1640 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1641 else if (level
== IS_LEVEL_2
)
1643 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1644 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1646 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1648 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1649 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1650 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1651 circuit
->area
->area_tag
, level
,
1652 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1653 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1654 lsp
->hdr
.rem_lifetime
, refresh_time
);
1660 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1662 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1663 struct isis_lsp
*lsp
;
1664 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1665 uint16_t rem_lifetime
, refresh_time
;
1667 if ((circuit
->is_type
& level
) != level
1668 || (circuit
->state
!= C_STATE_UP
)
1669 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1670 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1673 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1674 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1675 LSP_FRAGMENT(lsp_id
) = 0;
1677 lsp
= lsp_search(lsp_id
, lspdb
);
1680 flog_err(EC_LIB_DEVELOPMENT
,
1681 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1682 rawlspid_print(lsp_id
));
1686 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1687 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1688 lsp_build_pseudo(lsp
, circuit
, level
);
1689 lsp_inc_seqno(lsp
, 0);
1690 lsp
->last_generated
= time(NULL
);
1691 lsp_flood(lsp
, NULL
);
1693 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1694 if (level
== IS_LEVEL_1
)
1696 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1697 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1698 else if (level
== IS_LEVEL_2
)
1700 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1701 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1703 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1705 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1706 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1707 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1708 circuit
->area
->area_tag
, level
,
1709 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1710 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1711 lsp
->hdr
.rem_lifetime
, refresh_time
);
1718 * Something has changed or periodic refresh -> regenerate pseudo LSP
1720 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1722 struct isis_circuit
*circuit
;
1723 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1725 circuit
= THREAD_ARG(thread
);
1727 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1728 circuit
->lsp_regenerate_pending
[0] = 0;
1730 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1731 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1732 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1733 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1734 LSP_FRAGMENT(id
) = 0;
1735 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1739 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1742 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1744 struct isis_circuit
*circuit
;
1745 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1747 circuit
= THREAD_ARG(thread
);
1749 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1750 circuit
->lsp_regenerate_pending
[1] = 0;
1752 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1753 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1754 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1755 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1756 LSP_FRAGMENT(id
) = 0;
1757 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1761 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1764 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1766 struct isis_lsp
*lsp
;
1767 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1771 struct isis_area
*area
= circuit
->area
;
1773 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1774 || circuit
->state
!= C_STATE_UP
)
1778 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1779 area
->area_tag
, circuit_t2string(level
),
1780 circuit
->interface
->name
);
1782 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1783 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1784 LSP_FRAGMENT(lsp_id
) = 0;
1787 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1789 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1790 area
->area_tag
, lvl
);
1792 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1793 sched_debug("ISIS (%s): Level is not active on circuit",
1798 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1800 "ISIS (%s): This IS is not DR, nothing to do.",
1805 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1806 struct timeval remain
= thread_timer_remain(
1807 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1809 "ISIS (%s): Regenerate is already pending, nothing todo."
1810 " (Due in %lld.%03lld seconds)",
1811 area
->area_tag
, (long long)remain
.tv_sec
,
1812 (long long)remain
.tv_usec
/ 1000);
1816 lsp
= lsp_search(lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
1819 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1825 * Throttle avoidance
1828 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1829 area
->area_tag
, (long long)lsp
->last_generated
,
1831 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1832 diff
= now
- lsp
->last_generated
;
1833 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1835 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1838 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1839 area
->area_tag
, timeout
);
1843 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1844 " Scheduling for execution in %ld ms.",
1845 area
->area_tag
, timeout
);
1848 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1850 if (lvl
== IS_LEVEL_1
) {
1851 thread_add_timer_msec(
1852 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1853 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1854 } else if (lvl
== IS_LEVEL_2
) {
1855 thread_add_timer_msec(
1856 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1857 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1865 * Walk through LSPs for an area
1866 * - set remaining lifetime
1868 int lsp_tick(struct thread
*thread
)
1870 struct isis_area
*area
;
1871 struct isis_lsp
*lsp
;
1872 dnode_t
*dnode
, *dnode_next
;
1874 uint16_t rem_lifetime
;
1875 bool fabricd_sync_incomplete
= false;
1877 area
= THREAD_ARG(thread
);
1879 area
->t_tick
= NULL
;
1880 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1882 struct isis_circuit
*fabricd_init_c
= fabricd_initial_sync_circuit(area
);
1885 * Remove LSPs which have aged out
1887 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1888 if (area
->lspdb
[level
] && dict_count(area
->lspdb
[level
]) > 0) {
1889 for (dnode
= dict_first(area
->lspdb
[level
]);
1890 dnode
!= NULL
; dnode
= dnode_next
) {
1892 dict_next(area
->lspdb
[level
], dnode
);
1893 lsp
= dnode_get(dnode
);
1896 * The lsp rem_lifetime is kept at 0 for MaxAge
1898 * ZeroAgeLifetime depending on explicit purge
1900 * natural age out. So schedule spf only once
1902 * the first time rem_lifetime becomes 0.
1904 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1908 * Schedule may run spf which should be done
1910 * the lsp rem_lifetime becomes 0 for the first
1912 * ISO 10589 - 7.3.16.4 first paragraph.
1914 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
1915 /* 7.3.16.4 a) set SRM flags on all */
1916 /* 7.3.16.4 b) retain only the header */
1917 if (lsp
->area
->purge_originator
)
1918 lsp_purge(lsp
, lsp
->level
, NULL
);
1920 lsp_flood(lsp
, NULL
);
1921 /* 7.3.16.4 c) record the time to purge
1923 isis_spf_schedule(lsp
->area
, lsp
->level
);
1926 if (lsp
->age_out
== 0) {
1928 "ISIS-Upd (%s): L%u LSP %s seq "
1929 "0x%08" PRIx32
" aged out",
1930 area
->area_tag
, lsp
->level
,
1931 rawlspid_print(lsp
->hdr
.lsp_id
),
1934 /* if we're aging out fragment 0,
1935 * lsp_destroy() below will delete all
1936 * other fragments too, so we need to
1939 while (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)
1941 struct isis_lsp
*nextlsp
;
1943 nextlsp
= dnode_get(dnode_next
);
1944 if (memcmp(nextlsp
->hdr
.lsp_id
,
1946 ISIS_SYS_ID_LEN
+ 1))
1949 dnode_next
= dict_next(
1956 dict_delete_free(area
->lspdb
[level
],
1960 if (fabricd_init_c
&& lsp
) {
1961 fabricd_sync_incomplete
|=
1962 ISIS_CHECK_FLAG(lsp
->SSNflags
,
1970 && !fabricd_sync_incomplete
1971 && !isis_tx_queue_len(fabricd_init_c
->tx_queue
)) {
1972 fabricd_initial_sync_finish(area
);
1978 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
1980 struct isis_lsp
*lsp
;
1982 lsp
= lsp_search(id
, circuit
->area
->lspdb
[level
- 1]);
1986 lsp_purge(lsp
, level
, NULL
);
1990 * Purge own LSP that is received and we don't have.
1991 * -> Do as in 7.3.16.4
1993 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
1994 struct isis_area
*area
)
1996 struct isis_lsp
*lsp
;
1999 * We need to create the LSP to be purged
2001 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
2004 lsp_adjust_stream(lsp
);
2005 lsp
->age_out
= ZERO_AGE_LIFETIME
;
2006 lsp
->area
->lsp_purge_count
[level
- 1]++;
2008 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
2009 lsp
->hdr
.rem_lifetime
= 0;
2011 lsp_purge_add_poi(lsp
, NULL
);
2015 lsp_insert(lsp
, area
->lspdb
[lsp
->level
- 1]);
2016 lsp_flood(lsp
, NULL
);
2021 void lsp_set_all_srmflags(struct isis_lsp
*lsp
, bool set
)
2023 struct listnode
*node
;
2024 struct isis_circuit
*circuit
;
2031 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2032 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
2034 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
2037 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2042 void _lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2043 const char *func
, const char *file
, int line
)
2045 if (isis
->debugs
& DEBUG_FLOODING
) {
2046 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2047 rawlspid_print(lsp
->hdr
.lsp_id
),
2048 circuit
? " except on " : "",
2049 circuit
? circuit
->interface
->name
: "",
2054 lsp_set_all_srmflags(lsp
, true);
2056 fabricd_lsp_flood(lsp
, circuit
);
2059 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
2062 static int lsp_handle_adj_state_change(struct isis_adjacency
*adj
)
2064 lsp_regenerate_schedule(adj
->circuit
->area
, IS_LEVEL_1
| IS_LEVEL_2
, 0);
2070 hook_register(isis_adj_state_change_hook
,
2071 lsp_handle_adj_state_change
);