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/fabricd.h"
59 #include "isisd/isis_tx_queue.h"
60 #include "isisd/isis_nb.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 static void lsp_destroy(struct isis_lsp
*lsp
);
68 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
70 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
73 int lspdb_compare(const struct isis_lsp
*a
, const struct isis_lsp
*b
)
75 return memcmp(a
->hdr
.lsp_id
, b
->hdr
.lsp_id
, sizeof(a
->hdr
.lsp_id
));
78 void lsp_db_init(struct lspdb_head
*head
)
83 void lsp_db_fini(struct lspdb_head
*head
)
87 while ((lsp
= lspdb_pop(head
)))
92 struct isis_lsp
*lsp_search(struct lspdb_head
*head
, const uint8_t *id
)
94 struct isis_lsp searchfor
;
95 memcpy(searchfor
.hdr
.lsp_id
, id
, sizeof(searchfor
.hdr
.lsp_id
));
97 return lspdb_find(head
, &searchfor
);
100 static void lsp_clear_data(struct isis_lsp
*lsp
)
105 isis_free_tlvs(lsp
->tlvs
);
109 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
);
111 static void lsp_destroy(struct isis_lsp
*lsp
)
113 struct listnode
*cnode
;
114 struct isis_circuit
*circuit
;
119 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
, circuit
))
120 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
122 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
126 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
127 if (lsp
->lspu
.frags
) {
128 lsp_remove_frags(&lsp
->area
->lspdb
[lsp
->level
- 1],
130 list_delete(&lsp
->lspu
.frags
);
133 if (lsp
->lspu
.zero_lsp
134 && lsp
->lspu
.zero_lsp
->lspu
.frags
) {
135 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
139 isis_spf_schedule(lsp
->area
, lsp
->level
);
142 stream_free(lsp
->pdu
);
144 fabricd_lsp_free(lsp
);
145 XFREE(MTYPE_ISIS_LSP
, lsp
);
149 * Remove all the frags belonging to the given lsp
151 static void lsp_remove_frags(struct lspdb_head
*head
, struct list
*frags
)
153 struct listnode
*lnode
, *lnnode
;
154 struct isis_lsp
*lsp
;
156 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
157 lsp
= lsp_search(head
, lsp
->hdr
.lsp_id
);
158 lspdb_del(head
, lsp
);
163 void lsp_search_and_destroy(struct lspdb_head
*head
, const uint8_t *id
)
165 struct isis_lsp
*lsp
;
167 lsp
= lsp_search(head
, id
);
169 lspdb_del(head
, lsp
);
171 * If this is a zero lsp, remove all the frags now
173 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
175 lsp_remove_frags(head
, lsp
->lspu
.frags
);
178 * else just remove this frag, from the zero lsps' frag
181 if (lsp
->lspu
.zero_lsp
182 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
183 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
191 * Compares a LSP to given values
192 * Params are given in net order
194 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
195 uint16_t checksum
, uint16_t rem_lifetime
)
197 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
198 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
199 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
200 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
202 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
203 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
205 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
206 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
207 lsp
->hdr
.rem_lifetime
);
209 "ISIS-Snp (%s): is equal to ours seq 0x%08" PRIx32
210 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
212 areatag
, seqno
, checksum
, rem_lifetime
);
218 * LSPs with identical checksums should only be treated as newer if:
219 * a) The current LSP has a remaining lifetime != 0 and the other LSP
221 * remaining lifetime == 0. In this case, we should participate in
223 * and should not treat the current LSP with remaining lifetime == 0
225 * b) The LSP has an incorrect checksum. In this case, we need to react
229 if (seqno
> lsp
->hdr
.seqno
230 || (seqno
== lsp
->hdr
.seqno
231 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
232 || (lsp
->hdr
.checksum
!= checksum
233 && lsp
->hdr
.rem_lifetime
)))) {
234 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
236 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
237 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
239 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
240 checksum
, rem_lifetime
);
242 "ISIS-Snp (%s): is newer than ours seq 0x%08" PRIx32
243 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
245 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
246 lsp
->hdr
.rem_lifetime
);
250 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
251 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
252 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
253 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
254 checksum
, rem_lifetime
);
256 "ISIS-Snp (%s): is older than ours seq 0x%08" PRIx32
257 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
258 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
259 lsp
->hdr
.rem_lifetime
);
265 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
268 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
269 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
270 struct stream
*stream
= lsp
->pdu
;
271 size_t orig_getp
= 0, orig_endp
= 0;
274 orig_getp
= stream_get_getp(lsp
->pdu
);
275 orig_endp
= stream_get_endp(lsp
->pdu
);
278 stream_set_getp(lsp
->pdu
, 0);
279 stream_set_endp(lsp
->pdu
, 0);
281 fill_fixed_hdr(pdu_type
, stream
);
284 *len_pointer
= stream_get_endp(stream
);
285 stream_putw(stream
, hdr
->pdu_len
);
286 stream_putw(stream
, hdr
->rem_lifetime
);
287 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
288 stream_putl(stream
, hdr
->seqno
);
289 stream_putw(stream
, hdr
->checksum
);
290 stream_putc(stream
, hdr
->lsp_bits
);
293 stream_set_endp(lsp
->pdu
, orig_endp
);
294 stream_set_getp(lsp
->pdu
, orig_getp
);
298 static void lsp_add_auth(struct isis_lsp
*lsp
)
300 struct isis_passwd
*passwd
;
301 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
302 : &lsp
->area
->domain_passwd
;
303 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
306 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
309 lsp
->tlvs
= isis_alloc_tlvs();
314 put_lsp_hdr(lsp
, &len_pointer
, false);
315 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
317 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
319 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
320 stream_get_endp(lsp
->pdu
) - 12, 12));
323 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
327 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
328 newseq
= lsp
->hdr
.seqno
+ 1;
333 /* check for overflow */
334 if (newseq
< lsp
->hdr
.seqno
) {
335 /* send northbound notification */
336 isis_notif_lsp_exceed_max(lsp
->area
,
337 rawlspid_print(lsp
->hdr
.lsp_id
));
339 #endif /* ifndef FABRICD */
341 lsp
->hdr
.seqno
= newseq
;
344 isis_spf_schedule(lsp
->area
, lsp
->level
);
347 static void lsp_purge_add_poi(struct isis_lsp
*lsp
,
348 const uint8_t *sender
)
350 if (!lsp
->area
->purge_originator
)
353 /* add purge originator identification */
355 lsp
->tlvs
= isis_alloc_tlvs();
356 isis_tlvs_set_purge_originator(lsp
->tlvs
, isis
->sysid
, sender
);
357 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
360 static void lsp_purge(struct isis_lsp
*lsp
, int level
,
361 const uint8_t *sender
)
365 stream_reset(lsp
->pdu
);
368 lsp
->hdr
.checksum
= 0;
369 lsp
->hdr
.rem_lifetime
= 0;
371 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
372 lsp
->area
->lsp_purge_count
[level
- 1]++;
374 lsp_purge_add_poi(lsp
, sender
);
377 lsp_flood(lsp
, NULL
);
381 * Generates checksum for LSP and its frags
383 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
385 struct isis_lsp
*lsp
;
386 struct listnode
*node
;
388 lsp_inc_seqno(lsp0
, 0);
390 if (!lsp0
->lspu
.frags
)
393 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
395 lsp_inc_seqno(lsp
, 0);
396 else if (lsp
->hdr
.rem_lifetime
) {
397 /* Purge should only be applied when the fragment has
398 * non-zero remaining lifetime.
400 lsp_purge(lsp
, lsp0
->level
, NULL
);
407 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
409 uint8_t lsp_bits
= 0;
410 if (level
== IS_LEVEL_1
)
411 lsp_bits
= IS_LEVEL_1
;
413 lsp_bits
= IS_LEVEL_1_AND_2
;
415 lsp_bits
|= overload_bit
;
417 lsp_bits
|= attached_bit
;
421 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
422 struct isis_tlvs
*tlvs
, struct stream
*stream
,
423 struct isis_area
*area
, int level
)
425 /* free the old lsp data */
428 /* copying only the relevant part of our stream */
429 if (lsp
->pdu
!= NULL
)
430 stream_free(lsp
->pdu
);
431 lsp
->pdu
= stream_dup(stream
);
433 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
436 lsp
->age_out
= ZERO_AGE_LIFETIME
;
437 lsp
->installed
= time(NULL
);
441 if (area
->dynhostname
&& lsp
->tlvs
->hostname
442 && lsp
->hdr
.rem_lifetime
) {
443 isis_dynhn_insert(lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
444 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
)
453 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
455 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
456 /* zero lsp -> create list to store fragments */
457 lsp
->lspu
.frags
= list_new();
459 /* fragment -> set backpointer and add to zero lsps list */
461 lsp
->lspu
.zero_lsp
= lsp0
;
462 listnode_add(lsp0
->lspu
.frags
, lsp
);
466 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
467 struct isis_tlvs
*tlvs
, struct stream
*stream
,
468 struct isis_area
*area
, int level
, bool confusion
)
473 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
474 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
480 lsp_purge(lsp
, level
, NULL
);
482 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
485 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
486 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
487 struct isis_lsp
*lsp0
;
489 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
490 LSP_FRAGMENT(lspid
) = 0;
491 lsp0
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
493 lsp_link_fragment(lsp
, lsp0
);
497 isis_spf_schedule(lsp
->area
, lsp
->level
);
500 /* creation of LSP directly from what we received */
501 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
502 struct isis_tlvs
*tlvs
,
503 struct stream
*stream
, struct isis_lsp
*lsp0
,
504 struct isis_area
*area
, int level
)
506 struct isis_lsp
*lsp
;
508 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
509 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
510 lsp_link_fragment(lsp
, lsp0
);
515 static void lsp_adjust_stream(struct isis_lsp
*lsp
)
518 if (STREAM_SIZE(lsp
->pdu
) == LLC_LEN
+ lsp
->area
->lsp_mtu
)
520 stream_free(lsp
->pdu
);
523 lsp
->pdu
= stream_new(LLC_LEN
+ lsp
->area
->lsp_mtu
);
526 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
527 uint16_t rem_lifetime
, uint32_t seqno
,
528 uint8_t lsp_bits
, uint16_t checksum
,
529 struct isis_lsp
*lsp0
, int level
)
531 struct isis_lsp
*lsp
;
533 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
536 lsp_adjust_stream(lsp
);
538 /* Minimal LSP PDU size */
539 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
540 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
541 lsp
->hdr
.checksum
= checksum
;
542 lsp
->hdr
.seqno
= seqno
;
543 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
544 lsp
->hdr
.lsp_bits
= lsp_bits
;
546 lsp
->age_out
= ZERO_AGE_LIFETIME
;
547 lsp_link_fragment(lsp
, lsp0
);
548 put_lsp_hdr(lsp
, NULL
, false);
550 if (isis
->debugs
& DEBUG_EVENTS
)
551 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
552 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
553 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
559 void lsp_insert(struct lspdb_head
*head
, struct isis_lsp
*lsp
)
561 lspdb_add(head
, lsp
);
563 isis_spf_schedule(lsp
->area
, lsp
->level
);
567 * Build a list of LSPs with non-zero ht bounded by start and stop ids
569 void lsp_build_list_nonzero_ht(struct lspdb_head
*head
, const uint8_t *start_id
,
570 const uint8_t *stop_id
, struct list
*list
)
572 struct isis_lsp searchfor
;
573 struct isis_lsp
*lsp
, *start
;
575 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
577 start
= lspdb_find_gteq(head
, &searchfor
);
578 frr_each_from (lspdb
, head
, lsp
, start
) {
579 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
,
580 ISIS_SYS_ID_LEN
+ 2) > 0)
583 if (lsp
->hdr
.rem_lifetime
)
584 listnode_add(list
, lsp
);
588 static void lsp_set_time(struct isis_lsp
*lsp
)
592 if (lsp
->hdr
.rem_lifetime
== 0) {
593 if (lsp
->age_out
> 0)
598 lsp
->hdr
.rem_lifetime
--;
599 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
600 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
603 void lspid_print(uint8_t *lsp_id
, char *dest
, char dynhost
, char frag
)
605 struct isis_dynhn
*dyn
= NULL
;
606 uint8_t id
[SYSID_STRLEN
];
609 dyn
= dynhn_find_by_id(lsp_id
);
614 sprintf((char *)id
, "%.14s", dyn
->hostname
);
615 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
616 sprintf((char *)id
, "%.14s", cmd_hostname_get());
618 memcpy(id
, sysid_print(lsp_id
), 15);
620 sprintf(dest
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
621 LSP_FRAGMENT(lsp_id
));
623 sprintf(dest
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
626 /* Convert the lsp attribute bits to attribute string */
627 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
634 if (buf_size
< 2 * 3)
637 /* we only focus on the default metric */
638 pos
+= sprintf(pos
, "%d/",
639 ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits
) ? 1 : 0);
641 pos
+= sprintf(pos
, "%d/",
642 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
644 sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
649 /* this function prints the lsp on show isis database */
650 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
656 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, dynhost
, 1);
657 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
658 vty_out(vty
, "%5" PRIu16
" ", lsp
->hdr
.pdu_len
);
659 vty_out(vty
, "0x%08" PRIx32
" ", lsp
->hdr
.seqno
);
660 vty_out(vty
, "0x%04" PRIx16
" ", lsp
->hdr
.checksum
);
661 if (lsp
->hdr
.rem_lifetime
== 0) {
662 snprintf(age_out
, 8, "(%d)", lsp
->age_out
);
664 vty_out(vty
, "%7s ", age_out
);
666 vty_out(vty
, " %5" PRIu16
" ", lsp
->hdr
.rem_lifetime
);
667 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
670 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
672 lsp_print(lsp
, vty
, dynhost
);
674 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
678 /* print all the lsps info in the local lspdb */
679 int lsp_print_all(struct vty
*vty
, struct lspdb_head
*head
, char detail
,
682 struct isis_lsp
*lsp
;
685 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
686 frr_each (lspdb
, head
, lsp
) {
687 lsp_print(lsp
, vty
, dynhost
);
690 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
691 frr_each (lspdb
, head
, lsp
) {
692 lsp_print_detail(lsp
, vty
, dynhost
);
700 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
702 uint16_t rem_lifetime
;
704 /* Add jitter to configured LSP lifetime */
706 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
708 /* No jitter if the max refresh will be less than configure gen interval
710 /* N.B. this calucation is acceptable since rem_lifetime is in
713 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
714 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
719 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
721 struct isis_area
*area
= lsp
->area
;
722 int level
= lsp
->level
;
723 uint16_t refresh_time
;
725 /* Add jitter to LSP refresh time */
727 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
729 /* RFC 4444 : make sure the refresh time is at least less than 300
730 * of the remaining lifetime and more than gen interval */
731 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
732 || refresh_time
> (rem_lifetime
- 300))
733 refresh_time
= rem_lifetime
- 300;
735 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
736 * we accept this violation to satisfy refresh_time <= rem_lifetime -
742 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
743 struct isis_area
*area
)
745 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
749 for (struct route_node
*rn
= route_top(er_table
); rn
;
750 rn
= route_next(rn
)) {
754 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
755 struct isis_ext_info
*info
= rn
->info
;
757 uint32_t metric
= info
->metric
;
758 if (metric
> MAX_WIDE_PATH_METRIC
)
759 metric
= MAX_WIDE_PATH_METRIC
;
760 if (area
->oldmetric
&& metric
> 0x3f)
764 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
767 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
,
772 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
773 struct isis_area
*area
)
775 struct route_table
*er_table
=
776 get_ext_reach(area
, AF_INET6
, lsp
->level
);
780 for (struct route_node
*rn
= route_top(er_table
); rn
;
781 rn
= srcdest_route_next(rn
)) {
784 struct isis_ext_info
*info
= rn
->info
;
785 struct prefix_ipv6
*p
, *src_p
;
787 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
788 (const struct prefix
**)&src_p
);
790 uint32_t metric
= info
->metric
;
791 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
792 metric
= MAX_WIDE_PATH_METRIC
;
794 if (!src_p
|| !src_p
->prefixlen
) {
795 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
796 isis_area_ipv6_topology(area
),
798 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
799 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
806 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
808 lsp_build_ext_reach_ipv4(lsp
, area
);
809 lsp_build_ext_reach_ipv6(lsp
, area
);
812 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
813 struct isis_area
*area
, int level
)
815 struct isis_lsp
*lsp
;
816 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
818 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
819 LSP_FRAGMENT(frag_id
) = frag_num
;
821 lsp
= lsp_search(&area
->lspdb
[level
- 1], frag_id
);
824 if (!lsp
->lspu
.zero_lsp
)
825 lsp_link_fragment(lsp
, lsp0
);
829 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
830 lsp_bits_generate(level
, area
->overload_bit
,
834 lsp_insert(&area
->lspdb
[level
- 1], lsp
);
839 * Builds the LSP data part. This func creates a new frag whenever
840 * area->lsp_frag_threshold is exceeded.
842 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
844 int level
= lsp
->level
;
845 char buf
[PREFIX2STR_BUFFER
];
846 struct listnode
*node
;
847 struct isis_lsp
*frag
;
850 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
851 lsp_clear_data(frag
);
853 lsp
->tlvs
= isis_alloc_tlvs();
854 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
855 area
->area_tag
, level
);
857 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
862 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
864 /* Protocols Supported */
865 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
866 struct nlpids nlpids
= {.count
= 0};
868 if (area
->ip_circuits
> 0) {
870 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
872 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
875 if (area
->ipv6_circuits
> 0) {
877 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
879 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
882 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
885 if (area_is_mt(area
)) {
886 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
888 struct isis_area_mt_setting
**mt_settings
;
889 unsigned int mt_count
;
891 mt_settings
= area_mt_settings(area
, &mt_count
);
892 for (unsigned int i
= 0; i
< mt_count
; i
++) {
893 isis_tlvs_add_mt_router_info(
894 lsp
->tlvs
, mt_settings
[i
]->mtid
,
895 mt_settings
[i
]->overload
, false);
896 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
897 isis_mtid2str(mt_settings
[i
]->mtid
));
900 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
903 /* Dynamic Hostname */
904 if (area
->dynhostname
) {
905 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
906 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
907 area
->area_tag
, cmd_hostname_get());
909 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
913 /* IPv4 address and TE router ID TLVs.
914 * In case of the first one we don't follow "C" vendor,
915 * but "J" vendor behavior - one IPv4 address is put
916 * into LSP. TE router ID will be the same if MPLS-TE
917 * is not activate or MPLS-TE router-id not specified
919 if (isis
->router_id
!= 0) {
920 struct in_addr id
= {.s_addr
= isis
->router_id
};
921 inet_ntop(AF_INET
, &id
, buf
, sizeof(buf
));
922 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
923 area
->area_tag
, buf
);
924 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
926 /* If new style TLV's are in use, add TE router ID TLV
927 * Check if MPLS-TE is activate and mpls-te router-id set
928 * otherwise add exactly same data as for IPv4 address
930 if (area
->newmetric
) {
931 if (IS_MPLS_TE(area
->mta
)
932 && area
->mta
->router_id
.s_addr
!= 0)
933 id
.s_addr
= area
->mta
->router_id
.s_addr
;
935 "ISIS (%s): Adding router ID also as TE router ID tlv.",
937 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
940 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
944 lsp_debug("ISIS (%s): Adding circuit specific information.",
949 "ISIS (%s): Adding tier %" PRIu8
" spine-leaf-extension tlv.",
950 area
->area_tag
, fabricd_tier(area
));
951 isis_tlvs_add_spine_leaf(lsp
->tlvs
, fabricd_tier(area
), true,
952 false, false, false);
955 struct isis_circuit
*circuit
;
956 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
957 if (!circuit
->interface
)
959 "ISIS (%s): Processing %s circuit %p with unknown interface",
961 circuit_type2string(circuit
->circ_type
),
964 lsp_debug("ISIS (%s): Processing %s circuit %s",
966 circuit_type2string(circuit
->circ_type
),
967 circuit
->interface
->name
);
969 if (circuit
->state
!= C_STATE_UP
) {
970 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
975 uint32_t metric
= area
->oldmetric
976 ? circuit
->metric
[level
- 1]
977 : circuit
->te_metric
[level
- 1];
979 if (circuit
->ip_router
&& circuit
->ip_addrs
980 && circuit
->ip_addrs
->count
> 0) {
982 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
984 struct listnode
*ipnode
;
985 struct prefix_ipv4
*ipv4
;
986 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
988 if (area
->oldmetric
) {
990 "ISIS (%s): Adding old-style IP reachability for %s",
992 prefix2str(ipv4
, buf
,
994 isis_tlvs_add_oldstyle_ip_reach(
995 lsp
->tlvs
, ipv4
, metric
);
998 if (area
->newmetric
) {
1000 "ISIS (%s): Adding te-style IP reachability for %s",
1002 prefix2str(ipv4
, buf
,
1004 isis_tlvs_add_extended_ip_reach(
1005 lsp
->tlvs
, ipv4
, metric
);
1010 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1011 && circuit
->ipv6_non_link
->count
> 0) {
1012 struct listnode
*ipnode
;
1013 struct prefix_ipv6
*ipv6
;
1015 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1018 "ISIS (%s): Adding IPv6 reachability for %s",
1020 prefix2str(ipv6
, buf
, sizeof(buf
)));
1021 isis_tlvs_add_ipv6_reach(
1023 isis_area_ipv6_topology(area
), ipv6
,
1028 switch (circuit
->circ_type
) {
1029 case CIRCUIT_T_BROADCAST
:
1030 if (level
& circuit
->is_type
) {
1032 (level
== IS_LEVEL_1
)
1033 ? circuit
->u
.bc
.l1_desig_is
1034 : circuit
->u
.bc
.l2_desig_is
;
1036 if (LSP_PSEUDO_ID(ne_id
)) {
1037 if (area
->oldmetric
) {
1039 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1042 LSP_PSEUDO_ID(ne_id
));
1043 isis_tlvs_add_oldstyle_reach(
1047 if (area
->newmetric
)
1050 level
, ne_id
, metric
);
1054 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1058 case CIRCUIT_T_P2P
: {
1059 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1060 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1061 && (level
& nei
->circuit_t
)) {
1063 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1064 LSP_PSEUDO_ID(ne_id
) = 0;
1066 if (area
->oldmetric
) {
1068 "ISIS (%s): Adding old-style is reach for %s",
1070 sysid_print(ne_id
));
1071 isis_tlvs_add_oldstyle_reach(
1072 lsp
->tlvs
, ne_id
, metric
);
1074 if (area
->newmetric
) {
1075 uint32_t neighbor_metric
;
1076 if (fabricd_tier(area
) == 0) {
1077 neighbor_metric
= 0xffe;
1079 neighbor_metric
= metric
;
1082 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1083 ne_id
, neighbor_metric
);
1087 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1091 case CIRCUIT_T_LOOPBACK
:
1094 zlog_warn("lsp_area_create: unknown circuit type");
1098 lsp_build_ext_reach(lsp
, area
);
1100 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1103 lsp_adjust_stream(lsp
);
1105 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1106 lsp_clear_data(lsp
);
1108 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1110 zlog_warn("BUG: could not fragment own LSP:");
1111 log_multiline(LOG_WARNING
, " ", "%s",
1112 isis_format_tlvs(tlvs
));
1113 isis_free_tlvs(tlvs
);
1116 isis_free_tlvs(tlvs
);
1118 bool fragment_overflow
= false;
1120 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1121 if (node
!= listhead(fragments
)) {
1122 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1123 if (!fragment_overflow
) {
1124 fragment_overflow
= true;
1126 "ISIS (%s): Too much information for 256 fragments",
1129 isis_free_tlvs(tlvs
);
1133 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1135 lsp_adjust_stream(frag
);
1140 list_delete(&fragments
);
1141 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1147 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1149 int lsp_generate(struct isis_area
*area
, int level
)
1151 struct isis_lsp
*oldlsp
, *newlsp
;
1152 uint32_t seq_num
= 0;
1153 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1154 uint16_t rem_lifetime
, refresh_time
;
1156 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1159 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1160 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1162 /* only builds the lsp if the area shares the level */
1163 oldlsp
= lsp_search(&area
->lspdb
[level
- 1], lspid
);
1165 /* FIXME: we should actually initiate a purge */
1166 seq_num
= oldlsp
->hdr
.seqno
;
1167 lsp_search_and_destroy(&area
->lspdb
[level
- 1],
1168 oldlsp
->hdr
.lsp_id
);
1170 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1172 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1173 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1175 newlsp
->area
= area
;
1176 newlsp
->own_lsp
= 1;
1178 lsp_insert(&area
->lspdb
[level
- 1], newlsp
);
1179 /* build_lsp_data (newlsp, area); */
1180 lsp_build(newlsp
, area
);
1181 /* time to calculate our checksum */
1182 lsp_seqno_update(newlsp
);
1183 newlsp
->last_generated
= time(NULL
);
1184 lsp_flood(newlsp
, NULL
);
1185 area
->lsp_gen_count
[level
- 1]++;
1187 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1189 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
1190 area
->lsp_regenerate_pending
[level
- 1] = 0;
1191 thread_add_timer(master
, lsp_refresh
,
1192 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1193 &area
->t_lsp_refresh
[level
- 1]);
1195 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1196 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1197 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1198 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1199 area
->area_tag
, level
,
1200 rawlspid_print(newlsp
->hdr
.lsp_id
),
1201 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1202 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1206 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1207 area
->area_tag
, level
);
1210 /* send northbound notification */
1211 isis_notif_lsp_gen(area
, rawlspid_print(newlsp
->hdr
.lsp_id
),
1212 newlsp
->hdr
.seqno
, newlsp
->last_generated
);
1213 #endif /* ifndef FABRICD */
1219 * Search own LSPs, update holding time and flood
1221 static int lsp_regenerate(struct isis_area
*area
, int level
)
1223 struct lspdb_head
*head
;
1224 struct isis_lsp
*lsp
, *frag
;
1225 struct listnode
*node
;
1226 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1227 uint16_t rem_lifetime
, refresh_time
;
1229 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1232 head
= &area
->lspdb
[level
- 1];
1234 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1235 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1237 lsp
= lsp_search(head
, lspid
);
1240 flog_err(EC_LIB_DEVELOPMENT
,
1241 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1242 area
->area_tag
, level
);
1246 lsp_clear_data(lsp
);
1247 lsp_build(lsp
, area
);
1248 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1249 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1250 lsp
->last_generated
= time(NULL
);
1251 lsp_flood(lsp
, NULL
);
1252 area
->lsp_gen_count
[level
- 1]++;
1253 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1255 /* Updating and flooding should only affect fragments
1261 frag
->hdr
.lsp_bits
= lsp_bits_generate(
1262 level
, area
->overload_bit
, area
->attached_bit
);
1263 /* Set the lifetime values of all the fragments to the same
1265 * so that no fragment expires before the lsp is refreshed.
1267 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1268 frag
->age_out
= ZERO_AGE_LIFETIME
;
1269 lsp_flood(frag
, NULL
);
1271 lsp_seqno_update(lsp
);
1273 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1274 thread_add_timer(master
, lsp_refresh
,
1275 &area
->lsp_refresh_arg
[level
- 1], refresh_time
,
1276 &area
->t_lsp_refresh
[level
- 1]);
1277 area
->lsp_regenerate_pending
[level
- 1] = 0;
1279 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1281 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1282 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1283 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1284 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1285 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1286 lsp
->hdr
.rem_lifetime
, refresh_time
);
1289 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1290 area
->area_tag
, level
);
1296 * Something has changed or periodic refresh -> regenerate LSP
1298 static int lsp_refresh(struct thread
*thread
)
1300 struct lsp_refresh_arg
*arg
= THREAD_ARG(thread
);
1304 struct isis_area
*area
= arg
->area
;
1308 int level
= arg
->level
;
1310 area
->t_lsp_refresh
[level
- 1] = NULL
;
1311 area
->lsp_regenerate_pending
[level
- 1] = 0;
1313 if ((area
->is_type
& level
) == 0)
1316 if (monotime_since(&area
->last_lsp_refresh_event
[level
- 1], NULL
) < 100000L) {
1317 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1318 area
->area_tag
, level
);
1319 _lsp_regenerate_schedule(area
, level
, 0, false,
1320 __func__
, __FILE__
, __LINE__
);
1325 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1326 area
->area_tag
, level
);
1327 return lsp_regenerate(area
, level
);
1330 int _lsp_regenerate_schedule(struct isis_area
*area
, int level
,
1331 int all_pseudo
, bool postpone
,
1332 const char *func
, const char *file
,
1335 struct isis_lsp
*lsp
;
1336 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1339 struct listnode
*cnode
;
1340 struct isis_circuit
*circuit
;
1347 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs"
1348 " Caller: %s %s:%d",
1349 area
->area_tag
, circuit_t2string(level
),
1350 all_pseudo
? "" : "not ",
1353 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1354 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1357 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1358 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1362 monotime(&area
->last_lsp_refresh_event
[lvl
- 1]);
1366 "ISIS (%s): Checking whether L%d needs to be scheduled",
1367 area
->area_tag
, lvl
);
1369 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
1370 struct timeval remain
= thread_timer_remain(
1371 area
->t_lsp_refresh
[lvl
- 1]);
1373 "ISIS (%s): Regeneration is already pending, nothing todo."
1374 " (Due in %lld.%03lld seconds)",
1375 area
->area_tag
, (long long)remain
.tv_sec
,
1376 (long long)remain
.tv_usec
/ 1000);
1380 lsp
= lsp_search(&area
->lspdb
[lvl
- 1], id
);
1383 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1389 * Throttle avoidance
1392 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1393 area
->area_tag
, (long long)lsp
->last_generated
,
1395 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1396 diff
= now
- lsp
->last_generated
;
1397 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
1399 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1401 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1402 area
->area_tag
, timeout
);
1405 * lsps are not regenerated if lsp_regenerate function
1407 * directly. However if the lsp_regenerate call is
1409 * later execution it works.
1413 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1414 " Scheduling for execution in %ld ms.",
1415 area
->area_tag
, timeout
);
1418 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1419 thread_add_timer_msec(master
, lsp_refresh
,
1420 &area
->lsp_refresh_arg
[lvl
- 1],
1422 &area
->t_lsp_refresh
[lvl
- 1]);
1426 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1427 lsp_regenerate_schedule_pseudo(circuit
, level
);
1434 * Funcs for pseudonode LSPs
1438 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1440 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1443 struct isis_adjacency
*adj
;
1444 struct list
*adj_list
;
1445 struct listnode
*node
;
1446 struct isis_area
*area
= circuit
->area
;
1448 lsp_clear_data(lsp
);
1449 lsp
->tlvs
= isis_alloc_tlvs();
1451 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1452 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1453 circuit
->interface
->name
, level
);
1456 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1458 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
1461 * add self to IS neighbours
1463 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1465 memcpy(ne_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1466 LSP_PSEUDO_ID(ne_id
) = 0;
1468 if (circuit
->area
->oldmetric
) {
1469 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1471 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1472 area
->area_tag
, sysid_print(ne_id
),
1473 LSP_PSEUDO_ID(ne_id
));
1475 if (circuit
->area
->newmetric
) {
1476 isis_tlvs_add_extended_reach(lsp
->tlvs
, ISIS_MT_IPV4_UNICAST
,
1477 ne_id
, 0, circuit
->ext
);
1479 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1480 area
->area_tag
, sysid_print(ne_id
),
1481 LSP_PSEUDO_ID(ne_id
));
1484 adj_list
= list_new();
1485 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1487 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1488 if (!(adj
->level
& level
)) {
1490 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1491 area
->area_tag
, sysid_print(adj
->sysid
));
1495 if (!(level
== IS_LEVEL_1
1496 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1497 && !(level
== IS_LEVEL_1
1498 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1499 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1500 && !(level
== IS_LEVEL_2
1501 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1503 "ISIS (%s): Ignoring neighbor %s, level does not match",
1504 area
->area_tag
, sysid_print(adj
->sysid
));
1508 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1509 if (circuit
->area
->oldmetric
) {
1510 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1512 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1513 area
->area_tag
, sysid_print(ne_id
),
1514 LSP_PSEUDO_ID(ne_id
));
1516 if (circuit
->area
->newmetric
) {
1517 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1518 ISIS_MT_IPV4_UNICAST
,
1519 ne_id
, 0, circuit
->ext
);
1521 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1522 area
->area_tag
, sysid_print(ne_id
),
1523 LSP_PSEUDO_ID(ne_id
));
1526 list_delete(&adj_list
);
1530 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1532 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1533 struct isis_lsp
*lsp
;
1534 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1535 uint16_t rem_lifetime
, refresh_time
;
1537 if ((circuit
->is_type
& level
) != level
1538 || (circuit
->state
!= C_STATE_UP
)
1539 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1540 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1543 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1544 LSP_FRAGMENT(lsp_id
) = 0;
1545 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1548 * If for some reason have a pseudo LSP in the db already -> regenerate
1550 if (lsp_search(head
, lsp_id
))
1551 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1553 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1554 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1555 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1556 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
1558 lsp
->area
= circuit
->area
;
1560 lsp_build_pseudo(lsp
, circuit
, level
);
1563 lsp_insert(head
, lsp
);
1564 lsp_flood(lsp
, NULL
);
1566 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1567 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1568 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1569 if (level
== IS_LEVEL_1
)
1571 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1572 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1573 else if (level
== IS_LEVEL_2
)
1575 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1576 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1578 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1580 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1581 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1582 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1583 circuit
->area
->area_tag
, level
,
1584 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1585 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1586 lsp
->hdr
.rem_lifetime
, refresh_time
);
1592 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1594 struct lspdb_head
*head
= &circuit
->area
->lspdb
[level
- 1];
1595 struct isis_lsp
*lsp
;
1596 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1597 uint16_t rem_lifetime
, refresh_time
;
1599 if ((circuit
->is_type
& level
) != level
1600 || (circuit
->state
!= C_STATE_UP
)
1601 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1602 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1605 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1606 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1607 LSP_FRAGMENT(lsp_id
) = 0;
1609 lsp
= lsp_search(head
, lsp_id
);
1612 flog_err(EC_LIB_DEVELOPMENT
,
1613 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1614 rawlspid_print(lsp_id
));
1618 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1619 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1620 lsp_build_pseudo(lsp
, circuit
, level
);
1621 lsp_inc_seqno(lsp
, 0);
1622 lsp
->last_generated
= time(NULL
);
1623 lsp_flood(lsp
, NULL
);
1625 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1626 if (level
== IS_LEVEL_1
)
1628 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1629 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1630 else if (level
== IS_LEVEL_2
)
1632 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1633 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1635 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1637 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1638 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1639 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1640 circuit
->area
->area_tag
, level
,
1641 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1642 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1643 lsp
->hdr
.rem_lifetime
, refresh_time
);
1650 * Something has changed or periodic refresh -> regenerate pseudo LSP
1652 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1654 struct isis_circuit
*circuit
;
1655 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1657 circuit
= THREAD_ARG(thread
);
1659 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1660 circuit
->lsp_regenerate_pending
[0] = 0;
1662 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1663 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1664 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1665 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1666 LSP_FRAGMENT(id
) = 0;
1667 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1671 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1674 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1676 struct isis_circuit
*circuit
;
1677 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1679 circuit
= THREAD_ARG(thread
);
1681 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1682 circuit
->lsp_regenerate_pending
[1] = 0;
1684 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1685 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1686 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1687 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1688 LSP_FRAGMENT(id
) = 0;
1689 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1693 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1696 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1698 struct isis_lsp
*lsp
;
1699 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1703 struct isis_area
*area
= circuit
->area
;
1705 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1706 || circuit
->state
!= C_STATE_UP
)
1710 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1711 area
->area_tag
, circuit_t2string(level
),
1712 circuit
->interface
->name
);
1714 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1715 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1716 LSP_FRAGMENT(lsp_id
) = 0;
1719 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1721 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1722 area
->area_tag
, lvl
);
1724 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1725 sched_debug("ISIS (%s): Level is not active on circuit",
1730 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1732 "ISIS (%s): This IS is not DR, nothing to do.",
1737 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1738 struct timeval remain
= thread_timer_remain(
1739 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1741 "ISIS (%s): Regenerate is already pending, nothing todo."
1742 " (Due in %lld.%03lld seconds)",
1743 area
->area_tag
, (long long)remain
.tv_sec
,
1744 (long long)remain
.tv_usec
/ 1000);
1748 lsp
= lsp_search(&circuit
->area
->lspdb
[lvl
- 1], lsp_id
);
1751 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1757 * Throttle avoidance
1760 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1761 area
->area_tag
, (long long)lsp
->last_generated
,
1763 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1764 diff
= now
- lsp
->last_generated
;
1765 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1767 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1770 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1771 area
->area_tag
, timeout
);
1775 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1776 " Scheduling for execution in %ld ms.",
1777 area
->area_tag
, timeout
);
1780 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1782 if (lvl
== IS_LEVEL_1
) {
1783 thread_add_timer_msec(
1784 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1785 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1786 } else if (lvl
== IS_LEVEL_2
) {
1787 thread_add_timer_msec(
1788 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1789 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1797 * Walk through LSPs for an area
1798 * - set remaining lifetime
1800 int lsp_tick(struct thread
*thread
)
1802 struct isis_area
*area
;
1803 struct isis_lsp
*lsp
;
1805 uint16_t rem_lifetime
;
1806 bool fabricd_sync_incomplete
= false;
1808 area
= THREAD_ARG(thread
);
1810 area
->t_tick
= NULL
;
1811 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1813 struct isis_circuit
*fabricd_init_c
= fabricd_initial_sync_circuit(area
);
1816 * Remove LSPs which have aged out
1818 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1819 struct isis_lsp
*next
= lspdb_first(&area
->lspdb
[level
]);
1820 frr_each_from (lspdb
, &area
->lspdb
[level
], lsp
, next
) {
1822 * The lsp rem_lifetime is kept at 0 for MaxAge
1824 * ZeroAgeLifetime depending on explicit purge
1826 * natural age out. So schedule spf only once
1828 * the first time rem_lifetime becomes 0.
1830 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1834 * Schedule may run spf which should be done
1836 * the lsp rem_lifetime becomes 0 for the first
1838 * ISO 10589 - 7.3.16.4 first paragraph.
1840 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
1841 /* 7.3.16.4 a) set SRM flags on all */
1842 /* 7.3.16.4 b) retain only the header */
1843 if (lsp
->area
->purge_originator
)
1844 lsp_purge(lsp
, lsp
->level
, NULL
);
1846 lsp_flood(lsp
, NULL
);
1847 /* 7.3.16.4 c) record the time to purge
1849 isis_spf_schedule(lsp
->area
, lsp
->level
);
1852 if (lsp
->age_out
== 0) {
1854 "ISIS-Upd (%s): L%u LSP %s seq "
1855 "0x%08" PRIx32
" aged out",
1856 area
->area_tag
, lsp
->level
,
1857 rawlspid_print(lsp
->hdr
.lsp_id
),
1860 /* if we're aging out fragment 0, lsp_destroy()
1861 * below will delete all other fragments too,
1862 * so we need to skip over those
1864 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1866 !memcmp(next
->hdr
.lsp_id
,
1868 ISIS_SYS_ID_LEN
+ 1))
1870 &area
->lspdb
[level
],
1873 lspdb_del(&area
->lspdb
[level
], lsp
);
1878 if (fabricd_init_c
&& lsp
) {
1879 fabricd_sync_incomplete
|=
1880 ISIS_CHECK_FLAG(lsp
->SSNflags
,
1887 && !fabricd_sync_incomplete
1888 && !isis_tx_queue_len(fabricd_init_c
->tx_queue
)) {
1889 fabricd_initial_sync_finish(area
);
1895 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
1897 struct isis_lsp
*lsp
;
1899 lsp
= lsp_search(&circuit
->area
->lspdb
[level
- 1], id
);
1903 lsp_purge(lsp
, level
, NULL
);
1907 * Purge own LSP that is received and we don't have.
1908 * -> Do as in 7.3.16.4
1910 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
1911 struct isis_area
*area
)
1913 struct isis_lsp
*lsp
;
1916 * We need to create the LSP to be purged
1918 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
1921 lsp_adjust_stream(lsp
);
1922 lsp
->age_out
= ZERO_AGE_LIFETIME
;
1923 lsp
->area
->lsp_purge_count
[level
- 1]++;
1925 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
1926 lsp
->hdr
.rem_lifetime
= 0;
1928 lsp_purge_add_poi(lsp
, NULL
);
1932 lsp_insert(&area
->lspdb
[lsp
->level
- 1], lsp
);
1933 lsp_flood(lsp
, NULL
);
1938 void lsp_set_all_srmflags(struct isis_lsp
*lsp
, bool set
)
1940 struct listnode
*node
;
1941 struct isis_circuit
*circuit
;
1948 struct list
*circuit_list
= lsp
->area
->circuit_list
;
1949 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
1951 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
1954 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
1959 void _lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1960 const char *func
, const char *file
, int line
)
1962 if (isis
->debugs
& DEBUG_FLOODING
) {
1963 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
1964 rawlspid_print(lsp
->hdr
.lsp_id
),
1965 circuit
? " except on " : "",
1966 circuit
? circuit
->interface
->name
: "",
1971 lsp_set_all_srmflags(lsp
, true);
1973 fabricd_lsp_flood(lsp
, circuit
);
1976 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
1979 static int lsp_handle_adj_state_change(struct isis_adjacency
*adj
)
1981 lsp_regenerate_schedule(adj
->circuit
->area
, IS_LEVEL_1
| IS_LEVEL_2
, 0);
1987 hook_register(isis_adj_state_change_hook
,
1988 lsp_handle_adj_state_change
);