]>
git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
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"
60 static int lsp_l1_refresh(struct thread
*thread
);
61 static int lsp_l2_refresh(struct thread
*thread
);
62 static int lsp_l1_refresh_pseudo(struct thread
*thread
);
63 static int lsp_l2_refresh_pseudo(struct thread
*thread
);
65 int lsp_id_cmp(uint8_t *id1
, uint8_t *id2
)
67 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
70 dict_t
*lsp_db_init(void)
74 dict
= dict_create(DICTCOUNT_T_MAX
, (dict_comp_t
)lsp_id_cmp
);
79 struct isis_lsp
*lsp_search(uint8_t *id
, dict_t
*lspdb
)
86 zlog_debug("searching db");
87 for (dn
= dict_first(lspdb
); dn
; dn
= dict_next(lspdb
, dn
)) {
89 rawlspid_print((uint8_t *)dnode_getkey(dn
)),
92 #endif /* EXTREME DEBUG */
94 node
= dict_lookup(lspdb
, id
);
97 return (struct isis_lsp
*)dnode_get(node
);
102 static void lsp_clear_data(struct isis_lsp
*lsp
)
107 isis_free_tlvs(lsp
->tlvs
);
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_circuit_cancel_queued_lsp(circuit
, lsp
);
122 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
123 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
127 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0 && lsp
->lspu
.frags
) {
128 list_delete_and_null(&lsp
->lspu
.frags
);
129 lsp
->lspu
.frags
= NULL
;
132 isis_spf_schedule(lsp
->area
, lsp
->level
);
135 stream_free(lsp
->pdu
);
136 XFREE(MTYPE_ISIS_LSP
, lsp
);
139 void lsp_db_destroy(dict_t
*lspdb
)
141 dnode_t
*dnode
, *next
;
142 struct isis_lsp
*lsp
;
144 dnode
= dict_first(lspdb
);
146 next
= dict_next(lspdb
, dnode
);
147 lsp
= dnode_get(dnode
);
149 dict_delete_free(lspdb
, dnode
);
159 * Remove all the frags belonging to the given lsp
161 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
)
164 struct listnode
*lnode
, *lnnode
;
165 struct isis_lsp
*lsp
;
167 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
168 dnode
= dict_lookup(lspdb
, lsp
->hdr
.lsp_id
);
170 dnode_destroy(dict_delete(lspdb
, dnode
));
173 list_delete_all_node(frags
);
178 void lsp_search_and_destroy(uint8_t *id
, dict_t
*lspdb
)
181 struct isis_lsp
*lsp
;
183 node
= dict_lookup(lspdb
, id
);
185 node
= dict_delete(lspdb
, node
);
186 lsp
= dnode_get(node
);
188 * If this is a zero lsp, remove all the frags now
190 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
192 lsp_remove_frags(lsp
->lspu
.frags
, lspdb
);
195 * else just remove this frag, from the zero lsps' frag
198 if (lsp
->lspu
.zero_lsp
199 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
200 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
209 * Compares a LSP to given values
210 * Params are given in net order
212 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
213 uint16_t checksum
, uint16_t rem_lifetime
)
215 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
216 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
217 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
218 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
220 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
221 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
223 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
224 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
225 lsp
->hdr
.rem_lifetime
);
227 "ISIS-Snp (%s): is equal to ours seq 0x%08" PRIx32
228 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
230 areatag
, seqno
, checksum
, rem_lifetime
);
236 * LSPs with identical checksums should only be treated as newer if:
237 * a) The current LSP has a remaining lifetime != 0 and the other LSP
239 * remaining lifetime == 0. In this case, we should participate in
241 * and should not treat the current LSP with remaining lifetime == 0
243 * b) The LSP has an incorrect checksum. In this case, we need to react
247 if (seqno
> lsp
->hdr
.seqno
248 || (seqno
== lsp
->hdr
.seqno
249 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
250 || lsp
->hdr
.checksum
!= checksum
))) {
251 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
253 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
254 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
256 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
257 checksum
, rem_lifetime
);
259 "ISIS-Snp (%s): is newer than ours seq 0x%08" PRIx32
260 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
262 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
263 lsp
->hdr
.rem_lifetime
);
267 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
268 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
269 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
270 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
271 checksum
, rem_lifetime
);
273 "ISIS-Snp (%s): is older than ours seq 0x%08" PRIx32
274 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
275 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
276 lsp
->hdr
.rem_lifetime
);
282 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
, bool keep
)
285 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
286 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
287 struct stream
*stream
= lsp
->pdu
;
288 size_t orig_getp
= 0, orig_endp
= 0;
291 orig_getp
= stream_get_getp(lsp
->pdu
);
292 orig_endp
= stream_get_endp(lsp
->pdu
);
295 stream_set_getp(lsp
->pdu
, 0);
296 stream_set_endp(lsp
->pdu
, 0);
298 fill_fixed_hdr(pdu_type
, stream
);
301 *len_pointer
= stream_get_endp(stream
);
302 stream_putw(stream
, hdr
->pdu_len
);
303 stream_putw(stream
, hdr
->rem_lifetime
);
304 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
305 stream_putl(stream
, hdr
->seqno
);
306 stream_putw(stream
, hdr
->checksum
);
307 stream_putc(stream
, hdr
->lsp_bits
);
310 stream_set_endp(lsp
->pdu
, orig_endp
);
311 stream_set_getp(lsp
->pdu
, orig_getp
);
315 static void lsp_add_auth(struct isis_lsp
*lsp
)
317 struct isis_passwd
*passwd
;
318 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
319 : &lsp
->area
->domain_passwd
;
320 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
323 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
326 lsp
->tlvs
= isis_alloc_tlvs();
331 put_lsp_hdr(lsp
, &len_pointer
, false);
332 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
334 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
336 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
337 stream_get_endp(lsp
->pdu
) - 12, 12));
340 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
344 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
345 newseq
= lsp
->hdr
.seqno
+ 1;
349 lsp
->hdr
.seqno
= newseq
;
352 isis_spf_schedule(lsp
->area
, lsp
->level
);
355 static void lsp_purge(struct isis_lsp
*lsp
, int level
)
359 stream_reset(lsp
->pdu
);
362 lsp
->hdr
.checksum
= 0;
363 lsp
->hdr
.rem_lifetime
= 0;
365 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
368 lsp_set_all_srmflags(lsp
);
372 * Generates checksum for LSP and its frags
374 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
376 struct isis_lsp
*lsp
;
377 struct listnode
*node
;
379 lsp_inc_seqno(lsp0
, 0);
381 if (!lsp0
->lspu
.frags
)
384 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
386 lsp_inc_seqno(lsp
, 0);
388 lsp_purge(lsp
, lsp0
->level
);
394 static uint8_t lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
396 uint8_t lsp_bits
= 0;
397 if (level
== IS_LEVEL_1
)
398 lsp_bits
= IS_LEVEL_1
;
400 lsp_bits
= IS_LEVEL_1_AND_2
;
402 lsp_bits
|= overload_bit
;
404 lsp_bits
|= attached_bit
;
408 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
409 struct isis_tlvs
*tlvs
, struct stream
*stream
,
410 struct isis_area
*area
, int level
)
412 /* free the old lsp data */
415 /* copying only the relevant part of our stream */
416 if (lsp
->pdu
!= NULL
)
417 stream_free(lsp
->pdu
);
418 lsp
->pdu
= stream_dup(stream
);
420 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
423 lsp
->age_out
= ZERO_AGE_LIFETIME
;
424 lsp
->installed
= time(NULL
);
428 if (area
->dynhostname
&& lsp
->tlvs
->hostname
) {
429 isis_dynhn_insert(lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
430 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
)
439 static void lsp_link_fragment(struct isis_lsp
*lsp
, struct isis_lsp
*lsp0
)
441 if (!LSP_FRAGMENT(lsp
->hdr
.lsp_id
)) {
442 /* zero lsp -> create list to store fragments */
443 lsp
->lspu
.frags
= list_new();
445 /* fragment -> set backpointer and add to zero lsps list */
447 lsp
->lspu
.zero_lsp
= lsp0
;
448 listnode_add(lsp0
->lspu
.frags
, lsp
);
452 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
453 struct isis_tlvs
*tlvs
, struct stream
*stream
,
454 struct isis_area
*area
, int level
, bool confusion
)
459 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
460 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
465 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
467 lsp
->hdr
.rem_lifetime
= hdr
->rem_lifetime
= 0;
468 put_lsp_hdr(lsp
, NULL
, true);
471 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) && !lsp
->lspu
.zero_lsp
) {
472 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
473 struct isis_lsp
*lsp0
;
475 memcpy(lspid
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
476 LSP_FRAGMENT(lspid
) = 0;
477 lsp0
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
479 lsp_link_fragment(lsp
, lsp0
);
483 isis_spf_schedule(lsp
->area
, lsp
->level
);
486 /* creation of LSP directly from what we received */
487 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
488 struct isis_tlvs
*tlvs
,
489 struct stream
*stream
, struct isis_lsp
*lsp0
,
490 struct isis_area
*area
, int level
)
492 struct isis_lsp
*lsp
;
494 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
495 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
496 lsp_link_fragment(lsp
, lsp0
);
501 struct isis_lsp
*lsp_new(struct isis_area
*area
, uint8_t *lsp_id
,
502 uint16_t rem_lifetime
, uint32_t seqno
,
503 uint8_t lsp_bits
, uint16_t checksum
,
504 struct isis_lsp
*lsp0
, int level
)
506 struct isis_lsp
*lsp
;
508 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
511 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
513 /* Minimal LSP PDU size */
514 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
515 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
516 lsp
->hdr
.checksum
= checksum
;
517 lsp
->hdr
.seqno
= seqno
;
518 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
519 lsp
->hdr
.lsp_bits
= lsp_bits
;
521 lsp
->age_out
= ZERO_AGE_LIFETIME
;
522 lsp_link_fragment(lsp
, lsp0
);
523 put_lsp_hdr(lsp
, NULL
, false);
525 if (isis
->debugs
& DEBUG_EVENTS
)
526 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
527 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
528 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
534 void lsp_insert(struct isis_lsp
*lsp
, dict_t
*lspdb
)
536 dict_alloc_insert(lspdb
, lsp
->hdr
.lsp_id
, lsp
);
538 isis_spf_schedule(lsp
->area
, lsp
->level
);
542 * Build a list of LSPs with non-zero ht bounded by start and stop ids
544 void lsp_build_list_nonzero_ht(uint8_t *start_id
, uint8_t *stop_id
,
545 struct list
*list
, dict_t
*lspdb
)
547 dnode_t
*first
, *last
, *curr
;
549 first
= dict_lower_bound(lspdb
, start_id
);
553 last
= dict_upper_bound(lspdb
, stop_id
);
557 if (((struct isis_lsp
*)(curr
->dict_data
))->hdr
.rem_lifetime
)
558 listnode_add(list
, first
->dict_data
);
561 curr
= dict_next(lspdb
, curr
);
563 && ((struct isis_lsp
*)(curr
->dict_data
))->hdr
.rem_lifetime
)
564 listnode_add(list
, curr
->dict_data
);
572 static void lsp_set_time(struct isis_lsp
*lsp
)
576 if (lsp
->hdr
.rem_lifetime
== 0) {
577 if (lsp
->age_out
> 0)
582 lsp
->hdr
.rem_lifetime
--;
583 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
584 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
587 static void lspid_print(uint8_t *lsp_id
, uint8_t *trg
, char dynhost
, char frag
)
589 struct isis_dynhn
*dyn
= NULL
;
590 uint8_t id
[SYSID_STRLEN
];
593 dyn
= dynhn_find_by_id(lsp_id
);
598 sprintf((char *)id
, "%.14s", dyn
->hostname
);
599 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
600 sprintf((char *)id
, "%.14s", cmd_hostname_get());
602 memcpy(id
, sysid_print(lsp_id
), 15);
604 sprintf((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
605 LSP_FRAGMENT(lsp_id
));
607 sprintf((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
610 /* Convert the lsp attribute bits to attribute string */
611 static const char *lsp_bits2string(uint8_t lsp_bits
, char *buf
, size_t buf_size
)
618 if (buf_size
< 2 * 3)
621 /* we only focus on the default metric */
622 pos
+= sprintf(pos
, "%d/",
623 ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits
) ? 1 : 0);
625 pos
+= sprintf(pos
, "%d/",
626 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
628 sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
633 /* this function prints the lsp on show isis database */
634 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
640 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, dynhost
, 1);
641 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
642 vty_out(vty
, "%5" PRIu16
" ", lsp
->hdr
.pdu_len
);
643 vty_out(vty
, "0x%08" PRIx32
" ", lsp
->hdr
.seqno
);
644 vty_out(vty
, "0x%04" PRIx16
" ", lsp
->hdr
.checksum
);
645 if (lsp
->hdr
.rem_lifetime
== 0) {
646 snprintf(age_out
, 8, "(%d)", lsp
->age_out
);
648 vty_out(vty
, "%7s ", age_out
);
650 vty_out(vty
, " %5" PRIu16
" ", lsp
->hdr
.rem_lifetime
);
651 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
, b
, sizeof(b
)));
654 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
656 lsp_print(lsp
, vty
, dynhost
);
658 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
662 /* print all the lsps info in the local lspdb */
663 int lsp_print_all(struct vty
*vty
, dict_t
*lspdb
, char detail
, char dynhost
)
666 dnode_t
*node
= dict_first(lspdb
), *next
;
669 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
670 while (node
!= NULL
) {
671 /* I think it is unnecessary, so I comment it out */
672 /* dict_contains (lspdb, node); */
673 next
= dict_next(lspdb
, node
);
674 lsp_print(dnode_get(node
), vty
, dynhost
);
678 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
679 while (node
!= NULL
) {
680 next
= dict_next(lspdb
, node
);
681 lsp_print_detail(dnode_get(node
), vty
, dynhost
);
690 static uint16_t lsp_rem_lifetime(struct isis_area
*area
, int level
)
692 uint16_t rem_lifetime
;
694 /* Add jitter to configured LSP lifetime */
696 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
698 /* No jitter if the max refresh will be less than configure gen interval
700 /* N.B. this calucation is acceptable since rem_lifetime is in
703 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
704 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
709 static uint16_t lsp_refresh_time(struct isis_lsp
*lsp
, uint16_t rem_lifetime
)
711 struct isis_area
*area
= lsp
->area
;
712 int level
= lsp
->level
;
713 uint16_t refresh_time
;
715 /* Add jitter to LSP refresh time */
717 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
719 /* RFC 4444 : make sure the refresh time is at least less than 300
720 * of the remaining lifetime and more than gen interval */
721 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
722 || refresh_time
> (rem_lifetime
- 300))
723 refresh_time
= rem_lifetime
- 300;
725 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
726 * we accept this violation to satisfy refresh_time <= rem_lifetime -
732 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
733 struct isis_area
*area
)
735 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
739 for (struct route_node
*rn
= route_top(er_table
); rn
;
740 rn
= route_next(rn
)) {
744 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
745 struct isis_ext_info
*info
= rn
->info
;
747 uint32_t metric
= info
->metric
;
748 if (metric
> MAX_WIDE_PATH_METRIC
)
749 metric
= MAX_WIDE_PATH_METRIC
;
750 if (area
->oldmetric
&& metric
> 0x3f)
754 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
757 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
,
762 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
763 struct isis_area
*area
)
765 struct route_table
*er_table
=
766 get_ext_reach(area
, AF_INET6
, lsp
->level
);
770 for (struct route_node
*rn
= route_top(er_table
); rn
;
771 rn
= srcdest_route_next(rn
)) {
774 struct isis_ext_info
*info
= rn
->info
;
776 struct prefix_ipv6
*p
, *src_p
;
777 srcdest_rnode_prefixes(rn
, (const struct prefix
**)&p
,
778 (const struct prefix
**)&src_p
);
780 uint32_t metric
= info
->metric
;
781 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
782 metric
= MAX_WIDE_PATH_METRIC
;
784 if (!src_p
|| !src_p
->prefixlen
) {
785 isis_tlvs_add_ipv6_reach(lsp
->tlvs
,
786 isis_area_ipv6_topology(area
),
788 } else if (isis_area_ipv6_dstsrc_enabled(area
)) {
789 isis_tlvs_add_ipv6_dstsrc_reach(lsp
->tlvs
,
796 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
798 lsp_build_ext_reach_ipv4(lsp
, area
);
799 lsp_build_ext_reach_ipv6(lsp
, area
);
802 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
803 struct isis_area
*area
, int level
)
805 struct isis_lsp
*lsp
;
806 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
808 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
809 LSP_FRAGMENT(frag_id
) = frag_num
;
811 lsp
= lsp_search(frag_id
, area
->lspdb
[level
- 1]);
814 if (!lsp
->lspu
.zero_lsp
)
815 lsp_link_fragment(lsp
, lsp0
);
819 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
820 lsp_bits_generate(level
, area
->overload_bit
,
824 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
829 * Builds the LSP data part. This func creates a new frag whenever
830 * area->lsp_frag_threshold is exceeded.
832 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
834 int level
= lsp
->level
;
835 char buf
[PREFIX2STR_BUFFER
];
836 struct listnode
*node
;
837 struct isis_lsp
*frag
;
840 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
841 lsp_clear_data(frag
);
843 lsp
->tlvs
= isis_alloc_tlvs();
844 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
845 area
->area_tag
, level
);
847 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
852 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
854 /* Protocols Supported */
855 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
856 struct nlpids nlpids
= {.count
= 0};
857 if (area
->ip_circuits
> 0) {
859 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
861 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
864 if (area
->ipv6_circuits
> 0) {
866 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
868 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
871 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
874 if (area_is_mt(area
)) {
875 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
877 struct isis_area_mt_setting
**mt_settings
;
878 unsigned int mt_count
;
880 mt_settings
= area_mt_settings(area
, &mt_count
);
881 for (unsigned int i
= 0; i
< mt_count
; i
++) {
882 isis_tlvs_add_mt_router_info(
883 lsp
->tlvs
, mt_settings
[i
]->mtid
,
884 mt_settings
[i
]->overload
, false);
885 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
886 isis_mtid2str(mt_settings
[i
]->mtid
));
889 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
892 /* Dynamic Hostname */
893 if (area
->dynhostname
) {
894 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, cmd_hostname_get());
895 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
896 area
->area_tag
, cmd_hostname_get());
898 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
902 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
903 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
905 * LSP and this address is same as router id. */
906 if (isis
->router_id
!= 0) {
907 struct in_addr id
= {.s_addr
= isis
->router_id
};
908 inet_ntop(AF_INET
, &id
, buf
, sizeof(buf
));
909 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
910 area
->area_tag
, buf
);
911 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
913 /* Exactly same data is put into TE router ID TLV, but only if
915 * TLV's are in use. */
916 if (area
->newmetric
) {
919 "ISIS (%s): Adding router ID also as TE router ID tlv.",
921 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
924 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
928 lsp_debug("ISIS (%s): Adding circuit specific information.",
931 struct isis_circuit
*circuit
;
932 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
933 if (!circuit
->interface
)
935 "ISIS (%s): Processing %s circuit %p with unknown interface",
937 circuit_type2string(circuit
->circ_type
),
940 lsp_debug("ISIS (%s): Processing %s circuit %s",
942 circuit_type2string(circuit
->circ_type
),
943 circuit
->interface
->name
);
945 if (circuit
->state
!= C_STATE_UP
) {
946 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
951 uint32_t metric
= area
->oldmetric
952 ? circuit
->metric
[level
- 1]
953 : circuit
->te_metric
[level
- 1];
955 if (circuit
->ip_router
&& circuit
->ip_addrs
956 && circuit
->ip_addrs
->count
> 0) {
958 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
960 struct listnode
*ipnode
;
961 struct prefix_ipv4
*ipv4
;
962 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
964 if (area
->oldmetric
) {
966 "ISIS (%s): Adding old-style IP reachability for %s",
968 prefix2str(ipv4
, buf
,
970 isis_tlvs_add_oldstyle_ip_reach(
971 lsp
->tlvs
, ipv4
, metric
);
974 if (area
->newmetric
) {
976 "ISIS (%s): Adding te-style IP reachability for %s",
978 prefix2str(ipv4
, buf
,
980 isis_tlvs_add_extended_ip_reach(
981 lsp
->tlvs
, ipv4
, metric
);
986 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
987 && circuit
->ipv6_non_link
->count
> 0) {
988 struct listnode
*ipnode
;
989 struct prefix_ipv6
*ipv6
;
990 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
993 "ISIS (%s): Adding IPv6 reachability for %s",
995 prefix2str(ipv6
, buf
, sizeof(buf
)));
996 isis_tlvs_add_ipv6_reach(
998 isis_area_ipv6_topology(area
), ipv6
,
1003 switch (circuit
->circ_type
) {
1004 case CIRCUIT_T_BROADCAST
:
1005 if (level
& circuit
->is_type
) {
1007 (level
== IS_LEVEL_1
)
1008 ? circuit
->u
.bc
.l1_desig_is
1009 : circuit
->u
.bc
.l2_desig_is
;
1011 if (LSP_PSEUDO_ID(ne_id
)) {
1012 if (area
->oldmetric
) {
1014 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1017 LSP_PSEUDO_ID(ne_id
));
1018 isis_tlvs_add_oldstyle_reach(
1022 if (area
->newmetric
) {
1023 uint8_t subtlvs
[256];
1026 if (IS_MPLS_TE(isisMplsTE
)
1028 circuit
->interface
))
1029 subtlv_len
= add_te_subtlvs(
1037 level
, ne_id
, metric
,
1038 subtlvs
, subtlv_len
);
1043 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1047 case CIRCUIT_T_P2P
: {
1048 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1049 if (nei
&& nei
->adj_state
== ISIS_ADJ_UP
1050 && (level
& nei
->circuit_t
)) {
1052 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1053 LSP_PSEUDO_ID(ne_id
) = 0;
1055 if (area
->oldmetric
) {
1057 "ISIS (%s): Adding old-style is reach for %s",
1059 sysid_print(ne_id
));
1060 isis_tlvs_add_oldstyle_reach(
1061 lsp
->tlvs
, ne_id
, metric
);
1063 if (area
->newmetric
) {
1064 uint8_t subtlvs
[256];
1067 if (IS_MPLS_TE(isisMplsTE
)
1068 && circuit
->interface
!= NULL
1070 circuit
->interface
))
1071 /* Update Local and Remote IP
1072 * address for MPLS TE circuit
1074 /* NOTE sure that it is the
1075 * pertinent place for that
1077 /* Local IP address could be
1078 * updated in isis_circuit.c -
1079 * isis_circuit_add_addr() */
1080 /* But, where update remote IP
1081 * address ? in isis_pdu.c -
1082 * process_p2p_hello() ? */
1084 /* Add SubTLVs & Adjust real
1085 * size of SubTLVs */
1086 subtlv_len
= add_te_subtlvs(
1087 subtlvs
, circuit
->mtc
);
1089 /* Or keep only TE metric with
1090 * no SubTLVs if MPLS_TE is off
1094 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1095 ne_id
, metric
, subtlvs
,
1100 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1104 case CIRCUIT_T_LOOPBACK
:
1107 zlog_warn("lsp_area_create: unknown circuit type");
1111 lsp_build_ext_reach(lsp
, area
);
1113 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1117 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1118 lsp_clear_data(lsp
);
1120 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1122 zlog_warn("BUG: could not fragment own LSP:");
1123 log_multiline(LOG_WARNING
, " ", "%s",
1124 isis_format_tlvs(tlvs
));
1125 isis_free_tlvs(tlvs
);
1128 isis_free_tlvs(tlvs
);
1130 bool fragment_overflow
= false;
1132 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1133 if (node
!= listhead(fragments
)) {
1134 if (LSP_FRAGMENT(frag
->hdr
.lsp_id
) == 255) {
1135 if (!fragment_overflow
) {
1136 fragment_overflow
= true;
1138 "ISIS (%s): Too much information for 256 fragments",
1141 isis_free_tlvs(tlvs
);
1145 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1151 list_delete_and_null(&fragments
);
1152 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1158 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1160 int lsp_generate(struct isis_area
*area
, int level
)
1162 struct isis_lsp
*oldlsp
, *newlsp
;
1163 uint32_t seq_num
= 0;
1164 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1165 uint16_t rem_lifetime
, refresh_time
;
1167 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1170 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1171 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1173 /* only builds the lsp if the area shares the level */
1174 oldlsp
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
1176 /* FIXME: we should actually initiate a purge */
1177 seq_num
= oldlsp
->hdr
.seqno
;
1178 lsp_search_and_destroy(oldlsp
->hdr
.lsp_id
,
1179 area
->lspdb
[level
- 1]);
1181 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1183 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1184 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1186 newlsp
->area
= area
;
1187 newlsp
->own_lsp
= 1;
1189 lsp_insert(newlsp
, area
->lspdb
[level
- 1]);
1190 /* build_lsp_data (newlsp, area); */
1191 lsp_build(newlsp
, area
);
1192 /* time to calculate our checksum */
1193 lsp_seqno_update(newlsp
);
1194 newlsp
->last_generated
= time(NULL
);
1195 lsp_set_all_srmflags(newlsp
);
1197 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1199 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
1200 area
->lsp_regenerate_pending
[level
- 1] = 0;
1201 if (level
== IS_LEVEL_1
)
1202 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
1203 &area
->t_lsp_refresh
[level
- 1]);
1204 else if (level
== IS_LEVEL_2
)
1205 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
1206 &area
->t_lsp_refresh
[level
- 1]);
1208 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1209 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1210 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1211 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1212 area
->area_tag
, level
,
1213 rawlspid_print(newlsp
->hdr
.lsp_id
),
1214 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1215 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1219 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1220 area
->area_tag
, level
);
1226 * Search own LSPs, update holding time and set SRM
1228 static int lsp_regenerate(struct isis_area
*area
, int level
)
1231 struct isis_lsp
*lsp
, *frag
;
1232 struct listnode
*node
;
1233 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1234 uint16_t rem_lifetime
, refresh_time
;
1236 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1239 lspdb
= area
->lspdb
[level
- 1];
1241 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1242 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1244 lsp
= lsp_search(lspid
, lspdb
);
1247 flog_err(LIB_ERR_DEVELOPMENT
,
1248 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1249 area
->area_tag
, level
);
1253 lsp_clear_data(lsp
);
1254 lsp_build(lsp
, area
);
1255 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1256 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1257 lsp
->last_generated
= time(NULL
);
1258 lsp_set_all_srmflags(lsp
);
1259 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1260 frag
->hdr
.lsp_bits
= lsp_bits_generate(
1261 level
, area
->overload_bit
, area
->attached_bit
);
1262 /* Set the lifetime values of all the fragments to the same
1264 * so that no fragment expires before the lsp is refreshed.
1266 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1267 frag
->age_out
= ZERO_AGE_LIFETIME
;
1268 lsp_set_all_srmflags(frag
);
1270 lsp_seqno_update(lsp
);
1272 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1273 if (level
== IS_LEVEL_1
)
1274 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
1275 &area
->t_lsp_refresh
[level
- 1]);
1276 else if (level
== IS_LEVEL_2
)
1277 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
1278 &area
->t_lsp_refresh
[level
- 1]);
1279 area
->lsp_regenerate_pending
[level
- 1] = 0;
1281 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1283 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1284 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1285 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1286 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1287 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1288 lsp
->hdr
.rem_lifetime
, refresh_time
);
1291 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1292 area
->area_tag
, level
);
1298 * Something has changed or periodic refresh -> regenerate LSP
1300 static int lsp_l1_refresh(struct thread
*thread
)
1302 struct isis_area
*area
;
1304 area
= THREAD_ARG(thread
);
1307 area
->t_lsp_refresh
[0] = NULL
;
1308 area
->lsp_regenerate_pending
[0] = 0;
1310 if ((area
->is_type
& IS_LEVEL_1
) == 0)
1314 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
1316 return lsp_regenerate(area
, IS_LEVEL_1
);
1319 static int lsp_l2_refresh(struct thread
*thread
)
1321 struct isis_area
*area
;
1323 area
= THREAD_ARG(thread
);
1326 area
->t_lsp_refresh
[1] = NULL
;
1327 area
->lsp_regenerate_pending
[1] = 0;
1329 if ((area
->is_type
& IS_LEVEL_2
) == 0)
1333 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
1335 return lsp_regenerate(area
, IS_LEVEL_2
);
1338 int lsp_regenerate_schedule(struct isis_area
*area
, int level
, int all_pseudo
)
1340 struct isis_lsp
*lsp
;
1341 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1344 struct listnode
*cnode
;
1345 struct isis_circuit
*circuit
;
1352 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
1353 area
->area_tag
, circuit_t2string(level
),
1354 all_pseudo
? "" : "not ");
1356 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1357 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1360 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1361 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1365 "ISIS (%s): Checking whether L%d needs to be scheduled",
1366 area
->area_tag
, lvl
);
1368 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
1369 struct timeval remain
= thread_timer_remain(
1370 area
->t_lsp_refresh
[lvl
- 1]);
1372 "ISIS (%s): Regeneration is already pending, nothing todo."
1373 " (Due in %lld.%03lld seconds)",
1374 area
->area_tag
, (long long)remain
.tv_sec
,
1375 (long long)remain
.tv_usec
/ 1000);
1379 lsp
= lsp_search(id
, area
->lspdb
[lvl
- 1]);
1382 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1388 * Throttle avoidance
1391 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1392 area
->area_tag
, (long long)lsp
->last_generated
,
1394 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1395 diff
= now
- lsp
->last_generated
;
1396 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
1398 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1400 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1401 area
->area_tag
, timeout
);
1404 * lsps are not regenerated if lsp_regenerate function
1406 * directly. However if the lsp_regenerate call is
1408 * later execution it works.
1412 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1413 " Scheduling for execution in %ld ms.",
1414 area
->area_tag
, timeout
);
1417 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1418 if (lvl
== IS_LEVEL_1
) {
1419 thread_add_timer_msec(master
, lsp_l1_refresh
, area
,
1421 &area
->t_lsp_refresh
[lvl
- 1]);
1422 } else if (lvl
== IS_LEVEL_2
) {
1423 thread_add_timer_msec(master
, lsp_l2_refresh
, area
,
1425 &area
->t_lsp_refresh
[lvl
- 1]);
1430 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1431 lsp_regenerate_schedule_pseudo(circuit
, level
);
1438 * Funcs for pseudonode LSPs
1442 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1444 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1447 struct isis_adjacency
*adj
;
1448 struct list
*adj_list
;
1449 struct listnode
*node
;
1450 struct isis_area
*area
= circuit
->area
;
1452 lsp_clear_data(lsp
);
1453 lsp
->tlvs
= isis_alloc_tlvs();
1455 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1456 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1457 circuit
->interface
->name
, level
);
1460 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1462 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
1465 * add self to IS neighbours
1467 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1469 memcpy(ne_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1470 LSP_PSEUDO_ID(ne_id
) = 0;
1472 if (circuit
->area
->oldmetric
) {
1473 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1475 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1476 area
->area_tag
, sysid_print(ne_id
),
1477 LSP_PSEUDO_ID(ne_id
));
1479 if (circuit
->area
->newmetric
) {
1480 isis_tlvs_add_extended_reach(lsp
->tlvs
, ISIS_MT_IPV4_UNICAST
,
1483 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1484 area
->area_tag
, sysid_print(ne_id
),
1485 LSP_PSEUDO_ID(ne_id
));
1488 adj_list
= list_new();
1489 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1491 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1492 if (!(adj
->level
& level
)) {
1494 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1495 area
->area_tag
, sysid_print(adj
->sysid
));
1499 if (!(level
== IS_LEVEL_1
1500 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1501 && !(level
== IS_LEVEL_1
1502 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1503 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1504 && !(level
== IS_LEVEL_2
1505 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1507 "ISIS (%s): Ignoring neighbor %s, level does not match",
1508 area
->area_tag
, sysid_print(adj
->sysid
));
1512 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1513 if (circuit
->area
->oldmetric
) {
1514 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1516 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1517 area
->area_tag
, sysid_print(ne_id
),
1518 LSP_PSEUDO_ID(ne_id
));
1520 if (circuit
->area
->newmetric
) {
1521 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1522 ISIS_MT_IPV4_UNICAST
,
1525 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1526 area
->area_tag
, sysid_print(ne_id
),
1527 LSP_PSEUDO_ID(ne_id
));
1530 list_delete_and_null(&adj_list
);
1534 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1536 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1537 struct isis_lsp
*lsp
;
1538 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1539 uint16_t rem_lifetime
, refresh_time
;
1541 if ((circuit
->is_type
& level
) != level
1542 || (circuit
->state
!= C_STATE_UP
)
1543 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1544 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1547 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1548 LSP_FRAGMENT(lsp_id
) = 0;
1549 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1552 * If for some reason have a pseudo LSP in the db already -> regenerate
1554 if (lsp_search(lsp_id
, lspdb
))
1555 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1557 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1558 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1559 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1560 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
1562 lsp
->area
= circuit
->area
;
1564 lsp_build_pseudo(lsp
, circuit
, level
);
1567 lsp_insert(lsp
, lspdb
);
1568 lsp_set_all_srmflags(lsp
);
1570 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1571 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1572 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1573 if (level
== IS_LEVEL_1
)
1575 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1576 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1577 else if (level
== IS_LEVEL_2
)
1579 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1580 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1582 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1584 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1585 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1586 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1587 circuit
->area
->area_tag
, level
,
1588 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1589 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1590 lsp
->hdr
.rem_lifetime
, refresh_time
);
1596 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1598 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1599 struct isis_lsp
*lsp
;
1600 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1601 uint16_t rem_lifetime
, refresh_time
;
1603 if ((circuit
->is_type
& level
) != level
1604 || (circuit
->state
!= C_STATE_UP
)
1605 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1606 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1609 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1610 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1611 LSP_FRAGMENT(lsp_id
) = 0;
1613 lsp
= lsp_search(lsp_id
, lspdb
);
1616 flog_err(LIB_ERR_DEVELOPMENT
,
1617 "lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1618 rawlspid_print(lsp_id
));
1622 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1623 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1624 lsp_build_pseudo(lsp
, circuit
, level
);
1625 lsp_inc_seqno(lsp
, 0);
1626 lsp
->last_generated
= time(NULL
);
1627 lsp_set_all_srmflags(lsp
);
1629 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1630 if (level
== IS_LEVEL_1
)
1632 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1633 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1634 else if (level
== IS_LEVEL_2
)
1636 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1637 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1639 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1641 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1642 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1643 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1644 circuit
->area
->area_tag
, level
,
1645 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1646 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1647 lsp
->hdr
.rem_lifetime
, refresh_time
);
1654 * Something has changed or periodic refresh -> regenerate pseudo LSP
1656 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1658 struct isis_circuit
*circuit
;
1659 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1661 circuit
= THREAD_ARG(thread
);
1663 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1664 circuit
->lsp_regenerate_pending
[0] = 0;
1666 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1667 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1668 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1669 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1670 LSP_FRAGMENT(id
) = 0;
1671 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1675 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1678 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1680 struct isis_circuit
*circuit
;
1681 uint8_t id
[ISIS_SYS_ID_LEN
+ 2];
1683 circuit
= THREAD_ARG(thread
);
1685 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1686 circuit
->lsp_regenerate_pending
[1] = 0;
1688 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1689 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1690 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1691 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1692 LSP_FRAGMENT(id
) = 0;
1693 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1697 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1700 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1702 struct isis_lsp
*lsp
;
1703 uint8_t lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1707 struct isis_area
*area
= circuit
->area
;
1709 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1710 || circuit
->state
!= C_STATE_UP
)
1714 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1715 area
->area_tag
, circuit_t2string(level
),
1716 circuit
->interface
->name
);
1718 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1719 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1720 LSP_FRAGMENT(lsp_id
) = 0;
1723 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1725 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1726 area
->area_tag
, lvl
);
1728 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1729 sched_debug("ISIS (%s): Level is not active on circuit",
1734 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1736 "ISIS (%s): This IS is not DR, nothing to do.",
1741 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1742 struct timeval remain
= thread_timer_remain(
1743 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1745 "ISIS (%s): Regenerate is already pending, nothing todo."
1746 " (Due in %lld.%03lld seconds)",
1747 area
->area_tag
, (long long)remain
.tv_sec
,
1748 (long long)remain
.tv_usec
/ 1000);
1752 lsp
= lsp_search(lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
1755 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1761 * Throttle avoidance
1764 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1765 area
->area_tag
, (long long)lsp
->last_generated
,
1767 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1768 diff
= now
- lsp
->last_generated
;
1769 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1771 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1774 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1775 area
->area_tag
, timeout
);
1779 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1780 " Scheduling for execution in %ld ms.",
1781 area
->area_tag
, timeout
);
1784 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1786 if (lvl
== IS_LEVEL_1
) {
1787 thread_add_timer_msec(
1788 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1789 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1790 } else if (lvl
== IS_LEVEL_2
) {
1791 thread_add_timer_msec(
1792 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1793 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1801 * Walk through LSPs for an area
1802 * - set remaining lifetime
1803 * - set LSPs with SRMflag set for sending
1805 int lsp_tick(struct thread
*thread
)
1807 struct isis_area
*area
;
1808 struct isis_circuit
*circuit
;
1809 struct isis_lsp
*lsp
;
1810 struct list
*lsp_list
;
1811 struct listnode
*lspnode
, *cnode
;
1812 dnode_t
*dnode
, *dnode_next
;
1814 uint16_t rem_lifetime
;
1815 time_t now
= monotime(NULL
);
1817 lsp_list
= list_new();
1819 area
= THREAD_ARG(thread
);
1821 area
->t_tick
= NULL
;
1822 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1825 * Build a list of LSPs with (any) SRMflag set
1826 * and removed the ones that have aged out
1828 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1829 if (area
->lspdb
[level
] && dict_count(area
->lspdb
[level
]) > 0) {
1830 for (dnode
= dict_first(area
->lspdb
[level
]);
1831 dnode
!= NULL
; dnode
= dnode_next
) {
1833 dict_next(area
->lspdb
[level
], dnode
);
1834 lsp
= dnode_get(dnode
);
1837 * The lsp rem_lifetime is kept at 0 for MaxAge
1839 * ZeroAgeLifetime depending on explicit purge
1841 * natural age out. So schedule spf only once
1843 * the first time rem_lifetime becomes 0.
1845 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1849 * Schedule may run spf which should be done
1851 * the lsp rem_lifetime becomes 0 for the first
1853 * ISO 10589 - 7.3.16.4 first paragraph.
1855 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
1856 /* 7.3.16.4 a) set SRM flags on all */
1857 lsp_set_all_srmflags(lsp
);
1858 /* 7.3.16.4 b) retain only the header
1860 /* 7.3.16.4 c) record the time to purge
1862 /* run/schedule spf */
1863 /* isis_spf_schedule is called inside
1864 * lsp_destroy() below;
1865 * so it is not needed here. */
1866 /* isis_spf_schedule (lsp->area,
1870 if (lsp
->age_out
== 0) {
1872 "ISIS-Upd (%s): L%u LSP %s seq "
1873 "0x%08" PRIx32
" aged out",
1874 area
->area_tag
, lsp
->level
,
1875 rawlspid_print(lsp
->hdr
.lsp_id
),
1879 dict_delete_free(area
->lspdb
[level
],
1881 } else if (flags_any_set(lsp
->SRMflags
))
1882 listnode_add(lsp_list
, lsp
);
1886 * Send LSPs on circuits indicated by the SRMflags
1888 if (listcount(lsp_list
) > 0) {
1889 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
1891 if (!circuit
->lsp_queue
)
1894 if (now
- circuit
->lsp_queue_last_push
[level
]
1895 < MIN_LSP_RETRANS_INTERVAL
) {
1899 circuit
->lsp_queue_last_push
[level
] = now
;
1901 for (ALL_LIST_ELEMENTS_RO(
1902 lsp_list
, lspnode
, lsp
)) {
1903 if (circuit
->upadjcount
1908 isis_circuit_queue_lsp(
1913 list_delete_all_node(lsp_list
);
1918 list_delete_and_null(&lsp_list
);
1923 void lsp_purge_pseudo(uint8_t *id
, struct isis_circuit
*circuit
, int level
)
1925 struct isis_lsp
*lsp
;
1927 lsp
= lsp_search(id
, circuit
->area
->lspdb
[level
- 1]);
1931 lsp_purge(lsp
, level
);
1935 * Purge own LSP that is received and we don't have.
1936 * -> Do as in 7.3.16.4
1938 void lsp_purge_non_exist(int level
, struct isis_lsp_hdr
*hdr
,
1939 struct isis_area
*area
)
1941 struct isis_lsp
*lsp
;
1944 * We need to create the LSP to be purged
1946 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
1949 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
1950 lsp
->age_out
= ZERO_AGE_LIFETIME
;
1952 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
1953 lsp
->hdr
.rem_lifetime
= 0;
1957 lsp_insert(lsp
, area
->lspdb
[lsp
->level
- 1]);
1958 lsp_set_all_srmflags(lsp
);
1963 void lsp_set_all_srmflags(struct isis_lsp
*lsp
)
1965 struct listnode
*node
;
1966 struct isis_circuit
*circuit
;
1970 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
1973 struct list
*circuit_list
= lsp
->area
->circuit_list
;
1974 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
1975 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);