]>
git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
400e4b5fe402972ae5eba572739054b26cda0d39
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
41 #include "isisd/dict.h"
42 #include "isisd/isis_constants.h"
43 #include "isisd/isis_common.h"
44 #include "isisd/isis_flags.h"
45 #include "isisd/isis_circuit.h"
46 #include "isisd/isisd.h"
47 #include "isisd/isis_lsp.h"
48 #include "isisd/isis_pdu.h"
49 #include "isisd/isis_dynhn.h"
50 #include "isisd/isis_misc.h"
51 #include "isisd/isis_csm.h"
52 #include "isisd/isis_adjacency.h"
53 #include "isisd/isis_spf.h"
54 #include "isisd/isis_te.h"
55 #include "isisd/isis_mt.h"
56 #include "isisd/isis_tlvs.h"
58 /* staticly assigned vars for printing purposes */
59 char lsp_bits_string
[200]; /* FIXME: enough ? */
61 static int lsp_l1_refresh(struct thread
*thread
);
62 static int lsp_l2_refresh(struct thread
*thread
);
63 static int lsp_l1_refresh_pseudo(struct thread
*thread
);
64 static int lsp_l2_refresh_pseudo(struct thread
*thread
);
66 int lsp_id_cmp(u_char
*id1
, u_char
*id2
)
68 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
71 dict_t
*lsp_db_init(void)
75 dict
= dict_create(DICTCOUNT_T_MAX
, (dict_comp_t
)lsp_id_cmp
);
80 struct isis_lsp
*lsp_search(u_char
*id
, dict_t
*lspdb
)
87 zlog_debug("searching db");
88 for (dn
= dict_first(lspdb
); dn
; dn
= dict_next(lspdb
, dn
)) {
90 rawlspid_print((u_char
*)dnode_getkey(dn
)),
93 #endif /* EXTREME DEBUG */
95 node
= dict_lookup(lspdb
, id
);
98 return (struct isis_lsp
*)dnode_get(node
);
103 static void lsp_clear_data(struct isis_lsp
*lsp
)
108 isis_free_tlvs(lsp
->tlvs
);
112 static void lsp_destroy(struct isis_lsp
*lsp
)
114 struct listnode
*cnode
, *lnode
, *lnnode
;
115 struct isis_lsp
*lsp_in_list
;
116 struct isis_circuit
*circuit
;
121 if (lsp
->area
->circuit_list
) {
122 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
,
124 if (circuit
->lsp_queue
== NULL
)
126 for (ALL_LIST_ELEMENTS(circuit
->lsp_queue
, lnode
,
127 lnnode
, lsp_in_list
))
128 if (lsp_in_list
== lsp
)
129 list_delete_node(circuit
->lsp_queue
,
133 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
134 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
138 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0 && lsp
->lspu
.frags
) {
139 list_delete(lsp
->lspu
.frags
);
140 lsp
->lspu
.frags
= NULL
;
143 isis_spf_schedule(lsp
->area
, lsp
->level
);
146 stream_free(lsp
->pdu
);
147 XFREE(MTYPE_ISIS_LSP
, lsp
);
150 void lsp_db_destroy(dict_t
*lspdb
)
152 dnode_t
*dnode
, *next
;
153 struct isis_lsp
*lsp
;
155 dnode
= dict_first(lspdb
);
157 next
= dict_next(lspdb
, dnode
);
158 lsp
= dnode_get(dnode
);
160 dict_delete_free(lspdb
, dnode
);
170 * Remove all the frags belonging to the given lsp
172 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
)
175 struct listnode
*lnode
, *lnnode
;
176 struct isis_lsp
*lsp
;
178 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
179 dnode
= dict_lookup(lspdb
, lsp
->hdr
.lsp_id
);
181 dnode_destroy(dict_delete(lspdb
, dnode
));
184 list_delete_all_node(frags
);
189 void lsp_search_and_destroy(u_char
*id
, dict_t
*lspdb
)
192 struct isis_lsp
*lsp
;
194 node
= dict_lookup(lspdb
, id
);
196 node
= dict_delete(lspdb
, node
);
197 lsp
= dnode_get(node
);
199 * If this is a zero lsp, remove all the frags now
201 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
) == 0) {
203 lsp_remove_frags(lsp
->lspu
.frags
, lspdb
);
206 * else just remove this frag, from the zero lsps' frag
209 if (lsp
->lspu
.zero_lsp
210 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
211 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
220 * Compares a LSP to given values
221 * Params are given in net order
223 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, uint32_t seqno
,
224 uint16_t checksum
, uint16_t rem_lifetime
)
226 if (lsp
->hdr
.seqno
== seqno
&& lsp
->hdr
.checksum
== checksum
227 && ((lsp
->hdr
.rem_lifetime
== 0 && rem_lifetime
== 0)
228 || (lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
229 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
231 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
232 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
234 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
),
235 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
236 lsp
->hdr
.rem_lifetime
);
238 "ISIS-Snp (%s): is equal to ours seq 0x%08" PRIx32
239 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
241 areatag
, seqno
, checksum
, rem_lifetime
);
247 * LSPs with identical checksums should only be treated as newer if:
248 * a) The current LSP has a remaining lifetime != 0 and the other LSP
250 * remaining lifetime == 0. In this case, we should participate in
252 * and should not treat the current LSP with remaining lifetime == 0
254 * b) The LSP has an incorrect checksum. In this case, we need to react
258 if (seqno
> lsp
->hdr
.seqno
259 || (seqno
== lsp
->hdr
.seqno
260 && ((lsp
->hdr
.rem_lifetime
!= 0 && rem_lifetime
== 0)
261 || lsp
->hdr
.checksum
!= checksum
))) {
262 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
264 "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
265 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
267 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
268 checksum
, rem_lifetime
);
270 "ISIS-Snp (%s): is newer than ours seq 0x%08" PRIx32
271 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
273 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
274 lsp
->hdr
.rem_lifetime
);
278 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
279 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
280 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
281 areatag
, rawlspid_print(lsp
->hdr
.lsp_id
), seqno
,
282 checksum
, rem_lifetime
);
284 "ISIS-Snp (%s): is older than ours seq 0x%08" PRIx32
285 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s",
286 areatag
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
287 lsp
->hdr
.rem_lifetime
);
293 static void put_lsp_hdr(struct isis_lsp
*lsp
, size_t *len_pointer
)
296 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
297 struct isis_lsp_hdr
*hdr
= &lsp
->hdr
;
298 struct stream
*stream
= lsp
->pdu
;
300 fill_fixed_hdr(pdu_type
, stream
);
303 *len_pointer
= stream_get_endp(stream
);
304 stream_putw(stream
, hdr
->pdu_len
);
305 stream_putw(stream
, hdr
->rem_lifetime
);
306 stream_put(stream
, hdr
->lsp_id
, sizeof(hdr
->lsp_id
));
307 stream_putl(stream
, hdr
->seqno
);
308 stream_putw(stream
, hdr
->checksum
);
309 stream_putc(stream
, hdr
->lsp_bits
);
312 static void lsp_add_auth(struct isis_lsp
*lsp
)
314 struct isis_passwd
*passwd
;
315 passwd
= (lsp
->level
== IS_LEVEL_1
) ? &lsp
->area
->area_passwd
316 : &lsp
->area
->domain_passwd
;
317 isis_tlvs_add_auth(lsp
->tlvs
, passwd
);
320 static void lsp_pack_pdu(struct isis_lsp
*lsp
)
323 lsp
->tlvs
= isis_alloc_tlvs();
328 stream_reset(lsp
->pdu
);
329 put_lsp_hdr(lsp
, &len_pointer
);
330 isis_pack_tlvs(lsp
->tlvs
, lsp
->pdu
, len_pointer
, false, true);
332 lsp
->hdr
.pdu_len
= stream_get_endp(lsp
->pdu
);
334 ntohs(fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
335 stream_get_endp(lsp
->pdu
) - 12, 12));
338 void lsp_inc_seqno(struct isis_lsp
*lsp
, uint32_t seqno
)
342 if (seqno
== 0 || lsp
->hdr
.seqno
> seqno
)
343 newseq
= lsp
->hdr
.seqno
+ 1;
347 lsp
->hdr
.seqno
= newseq
;
350 isis_spf_schedule(lsp
->area
, lsp
->level
);
353 static void lsp_purge(struct isis_lsp
*lsp
, int level
)
357 stream_reset(lsp
->pdu
);
360 lsp
->hdr
.checksum
= 0;
361 lsp
->hdr
.rem_lifetime
= 0;
363 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
366 lsp_set_all_srmflags(lsp
);
370 * Generates checksum for LSP and its frags
372 static void lsp_seqno_update(struct isis_lsp
*lsp0
)
374 struct isis_lsp
*lsp
;
375 struct listnode
*node
;
377 lsp_inc_seqno(lsp0
, 0);
379 if (!lsp0
->lspu
.frags
)
382 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
)) {
384 lsp_inc_seqno(lsp
, 0);
386 lsp_purge(lsp
, lsp0
->level
);
392 static u_int8_t
lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
394 u_int8_t lsp_bits
= 0;
395 if (level
== IS_LEVEL_1
)
396 lsp_bits
= IS_LEVEL_1
;
398 lsp_bits
= IS_LEVEL_1_AND_2
;
400 lsp_bits
|= overload_bit
;
402 lsp_bits
|= attached_bit
;
406 static void lsp_update_data(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
407 struct isis_tlvs
*tlvs
, struct stream
*stream
,
408 struct isis_area
*area
, int level
)
410 /* free the old lsp data */
413 /* copying only the relevant part of our stream */
414 if (lsp
->pdu
!= NULL
)
415 stream_free(lsp
->pdu
);
416 lsp
->pdu
= stream_dup(stream
);
418 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
421 lsp
->age_out
= ZERO_AGE_LIFETIME
;
422 lsp
->installed
= time(NULL
);
426 if (area
->dynhostname
&& lsp
->tlvs
->hostname
) {
427 isis_dynhn_insert(lsp
->hdr
.lsp_id
, lsp
->tlvs
->hostname
,
428 (lsp
->hdr
.lsp_bits
& LSPBIT_IST
)
437 void lsp_update(struct isis_lsp
*lsp
, struct isis_lsp_hdr
*hdr
,
438 struct isis_tlvs
*tlvs
, struct stream
*stream
,
439 struct isis_area
*area
, int level
)
441 dnode_t
*dnode
= NULL
;
443 /* Remove old LSP from database. This is required since the
444 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
445 * and will update it with the new data in the stream. */
446 dnode
= dict_lookup(area
->lspdb
[level
- 1], lsp
->hdr
.lsp_id
);
448 dnode_destroy(dict_delete(area
->lspdb
[level
- 1], dnode
));
452 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
453 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
));
458 /* rebuild the lsp data */
459 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
461 /* insert the lsp back into the database */
462 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
465 /* creation of LSP directly from what we received */
466 struct isis_lsp
*lsp_new_from_recv(struct isis_lsp_hdr
*hdr
,
467 struct isis_tlvs
*tlvs
,
468 struct stream
*stream
, struct isis_lsp
*lsp0
,
469 struct isis_area
*area
, int level
)
471 struct isis_lsp
*lsp
;
473 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
474 lsp_update_data(lsp
, hdr
, tlvs
, stream
, area
, level
);
478 * zero lsp -> create the list for fragments
480 lsp
->lspu
.frags
= list_new();
483 * a fragment -> set the backpointer and add this to zero lsps
486 lsp
->lspu
.zero_lsp
= lsp0
;
487 listnode_add(lsp0
->lspu
.frags
, lsp
);
493 struct isis_lsp
*lsp_new(struct isis_area
*area
, u_char
*lsp_id
,
494 uint16_t rem_lifetime
, uint32_t seqno
,
495 uint8_t lsp_bits
, uint16_t checksum
, int level
)
497 struct isis_lsp
*lsp
;
499 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
502 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
503 if (LSP_FRAGMENT(lsp_id
) == 0)
504 lsp
->lspu
.frags
= list_new();
506 /* Minimal LSP PDU size */
507 lsp
->hdr
.pdu_len
= ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
;
508 memcpy(lsp
->hdr
.lsp_id
, lsp_id
, sizeof(lsp
->hdr
.lsp_id
));
509 lsp
->hdr
.checksum
= checksum
;
510 lsp
->hdr
.seqno
= seqno
;
511 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
512 lsp
->hdr
.lsp_bits
= lsp_bits
;
514 lsp
->age_out
= ZERO_AGE_LIFETIME
;
515 put_lsp_hdr(lsp
, NULL
);
517 if (isis
->debugs
& DEBUG_EVENTS
)
518 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
519 sysid_print(lsp_id
), LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
),
520 LSP_FRAGMENT(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
526 void lsp_insert(struct isis_lsp
*lsp
, dict_t
*lspdb
)
528 dict_alloc_insert(lspdb
, lsp
->hdr
.lsp_id
, lsp
);
530 isis_spf_schedule(lsp
->area
, lsp
->level
);
534 * Build a list of LSPs with non-zero ht bounded by start and stop ids
536 void lsp_build_list_nonzero_ht(u_char
*start_id
, u_char
*stop_id
,
537 struct list
*list
, dict_t
*lspdb
)
539 dnode_t
*first
, *last
, *curr
;
541 first
= dict_lower_bound(lspdb
, start_id
);
545 last
= dict_upper_bound(lspdb
, stop_id
);
549 if (((struct isis_lsp
*)(curr
->dict_data
))->hdr
.rem_lifetime
)
550 listnode_add(list
, first
->dict_data
);
553 curr
= dict_next(lspdb
, curr
);
555 && ((struct isis_lsp
*)(curr
->dict_data
))->hdr
.rem_lifetime
)
556 listnode_add(list
, curr
->dict_data
);
564 static void lsp_set_time(struct isis_lsp
*lsp
)
568 if (lsp
->hdr
.rem_lifetime
== 0) {
569 if (lsp
->age_out
> 0)
574 lsp
->hdr
.rem_lifetime
--;
575 if (lsp
->pdu
&& stream_get_endp(lsp
->pdu
) >= 12)
576 stream_putw_at(lsp
->pdu
, 10, lsp
->hdr
.rem_lifetime
);
579 static void lspid_print(u_char
*lsp_id
, u_char
*trg
, char dynhost
, char frag
)
581 struct isis_dynhn
*dyn
= NULL
;
582 u_char id
[SYSID_STRLEN
];
585 dyn
= dynhn_find_by_id(lsp_id
);
590 sprintf((char *)id
, "%.14s", dyn
->hostname
);
591 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
592 sprintf((char *)id
, "%.14s", unix_hostname());
594 memcpy(id
, sysid_print(lsp_id
), 15);
596 sprintf((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
597 LSP_FRAGMENT(lsp_id
));
599 sprintf((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
602 /* Convert the lsp attribute bits to attribute string */
603 static const char *lsp_bits2string(uint8_t lsp_bits
)
605 char *pos
= lsp_bits_string
;
610 /* we only focus on the default metric */
611 pos
+= sprintf(pos
, "%d/",
612 ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits
) ? 1 : 0);
614 pos
+= sprintf(pos
, "%d/",
615 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits
) ? 1 : 0);
617 pos
+= sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits
) ? 1 : 0);
621 return lsp_bits_string
;
624 /* this function prints the lsp on show isis database */
625 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
630 lspid_print(lsp
->hdr
.lsp_id
, LSPid
, dynhost
, 1);
631 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
632 vty_out(vty
, "%5" PRIu16
" ", lsp
->hdr
.pdu_len
);
633 vty_out(vty
, "0x%08" PRIx32
" ", lsp
->hdr
.seqno
);
634 vty_out(vty
, "0x%04" PRIx16
" ", lsp
->hdr
.checksum
);
635 if (lsp
->hdr
.rem_lifetime
== 0) {
636 snprintf(age_out
, 8, "(%d)", lsp
->age_out
);
638 vty_out(vty
, "%7s ", age_out
);
640 vty_out(vty
, " %5" PRIu16
" ", lsp
->hdr
.rem_lifetime
);
641 vty_out(vty
, "%s\n", lsp_bits2string(lsp
->hdr
.lsp_bits
));
644 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
646 lsp_print(lsp
, vty
, dynhost
);
648 vty_multiline(vty
, " ", "%s", isis_format_tlvs(lsp
->tlvs
));
652 /* print all the lsps info in the local lspdb */
653 int lsp_print_all(struct vty
*vty
, dict_t
*lspdb
, char detail
, char dynhost
)
656 dnode_t
*node
= dict_first(lspdb
), *next
;
659 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
660 while (node
!= NULL
) {
661 /* I think it is unnecessary, so I comment it out */
662 /* dict_contains (lspdb, node); */
663 next
= dict_next(lspdb
, node
);
664 lsp_print(dnode_get(node
), vty
, dynhost
);
668 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
669 while (node
!= NULL
) {
670 next
= dict_next(lspdb
, node
);
671 lsp_print_detail(dnode_get(node
), vty
, dynhost
);
680 static u_int16_t
lsp_rem_lifetime(struct isis_area
*area
, int level
)
682 u_int16_t rem_lifetime
;
684 /* Add jitter to configured LSP lifetime */
686 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
688 /* No jitter if the max refresh will be less than configure gen interval
690 /* N.B. this calucation is acceptable since rem_lifetime is in
693 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
694 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
699 static u_int16_t
lsp_refresh_time(struct isis_lsp
*lsp
, u_int16_t rem_lifetime
)
701 struct isis_area
*area
= lsp
->area
;
702 int level
= lsp
->level
;
703 u_int16_t refresh_time
;
705 /* Add jitter to LSP refresh time */
707 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
709 /* RFC 4444 : make sure the refresh time is at least less than 300
710 * of the remaining lifetime and more than gen interval */
711 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
712 || refresh_time
> (rem_lifetime
- 300))
713 refresh_time
= rem_lifetime
- 300;
715 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
716 * we accept this violation to satisfy refresh_time <= rem_lifetime -
722 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
723 struct isis_area
*area
)
725 struct route_table
*er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
729 for (struct route_node
*rn
= route_top(er_table
); rn
;
730 rn
= route_next(rn
)) {
734 struct prefix_ipv4
*ipv4
= (struct prefix_ipv4
*)&rn
->p
;
735 struct isis_ext_info
*info
= rn
->info
;
737 uint32_t metric
= info
->metric
;
738 if (metric
> MAX_WIDE_PATH_METRIC
)
739 metric
= MAX_WIDE_PATH_METRIC
;
740 if (area
->oldmetric
&& metric
> 0x3f)
744 isis_tlvs_add_oldstyle_ip_reach(lsp
->tlvs
, ipv4
,
747 isis_tlvs_add_extended_ip_reach(lsp
->tlvs
, ipv4
,
752 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
753 struct isis_area
*area
)
755 struct route_table
*er_table
=
756 get_ext_reach(area
, AF_INET6
, lsp
->level
);
760 for (struct route_node
*rn
= route_top(er_table
); rn
;
761 rn
= route_next(rn
)) {
765 struct prefix_ipv6
*ipv6
= (struct prefix_ipv6
*)&rn
->p
;
766 struct isis_ext_info
*info
= rn
->info
;
768 uint32_t metric
= info
->metric
;
769 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
770 metric
= MAX_WIDE_PATH_METRIC
;
771 isis_tlvs_add_ipv6_reach(
772 lsp
->tlvs
, isis_area_ipv6_topology(area
), ipv6
, metric
);
776 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
)
778 lsp_build_ext_reach_ipv4(lsp
, area
);
779 lsp_build_ext_reach_ipv6(lsp
, area
);
782 static struct isis_lsp
*lsp_next_frag(uint8_t frag_num
, struct isis_lsp
*lsp0
,
783 struct isis_area
*area
, int level
)
785 struct isis_lsp
*lsp
;
786 uint8_t frag_id
[ISIS_SYS_ID_LEN
+ 2];
788 memcpy(frag_id
, lsp0
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 1);
789 LSP_FRAGMENT(frag_id
) = frag_num
;
791 lsp
= lsp_search(frag_id
, area
->lspdb
[level
- 1]);
797 lsp
= lsp_new(area
, frag_id
, lsp0
->hdr
.rem_lifetime
, 0,
798 lsp_bits_generate(level
, area
->overload_bit
,
802 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
803 listnode_add(lsp0
->lspu
.frags
, lsp
);
804 lsp
->lspu
.zero_lsp
= lsp0
;
809 * Builds the LSP data part. This func creates a new frag whenever
810 * area->lsp_frag_threshold is exceeded.
812 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
814 int level
= lsp
->level
;
815 char buf
[PREFIX2STR_BUFFER
];
816 struct listnode
*node
;
817 struct isis_lsp
*frag
;
820 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
821 lsp_clear_data(frag
);
823 lsp
->tlvs
= isis_alloc_tlvs();
824 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
825 area
->area_tag
, level
);
827 lsp
->hdr
.lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
832 isis_tlvs_add_area_addresses(lsp
->tlvs
, area
->area_addrs
);
834 /* Protocols Supported */
835 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
836 struct nlpids nlpids
= {.count
= 0};
837 if (area
->ip_circuits
> 0) {
839 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
841 nlpids
.nlpids
[nlpids
.count
] = NLPID_IP
;
844 if (area
->ipv6_circuits
> 0) {
846 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
848 nlpids
.nlpids
[nlpids
.count
] = NLPID_IPV6
;
851 isis_tlvs_set_protocols_supported(lsp
->tlvs
, &nlpids
);
854 if (area_is_mt(area
)) {
855 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
857 struct isis_area_mt_setting
**mt_settings
;
858 unsigned int mt_count
;
860 mt_settings
= area_mt_settings(area
, &mt_count
);
861 for (unsigned int i
= 0; i
< mt_count
; i
++) {
862 isis_tlvs_add_mt_router_info(
863 lsp
->tlvs
, mt_settings
[i
]->mtid
,
864 mt_settings
[i
]->overload
, false);
865 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
866 isis_mtid2str(mt_settings
[i
]->mtid
));
869 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
872 /* Dynamic Hostname */
873 if (area
->dynhostname
) {
874 isis_tlvs_set_dynamic_hostname(lsp
->tlvs
, unix_hostname());
875 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
876 area
->area_tag
, unix_hostname());
878 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
882 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
883 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
885 * LSP and this address is same as router id. */
886 if (isis
->router_id
!= 0) {
887 struct in_addr id
= {.s_addr
= isis
->router_id
};
888 inet_ntop(AF_INET
, &id
, buf
, sizeof(buf
));
889 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
890 area
->area_tag
, buf
);
891 isis_tlvs_add_ipv4_address(lsp
->tlvs
, &id
);
893 /* Exactly same data is put into TE router ID TLV, but only if
895 * TLV's are in use. */
896 if (area
->newmetric
) {
899 "ISIS (%s): Adding router ID also as TE router ID tlv.",
901 isis_tlvs_set_te_router_id(lsp
->tlvs
, &id
);
904 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
908 lsp_debug("ISIS (%s): Adding circuit specific information.",
911 struct isis_circuit
*circuit
;
912 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
913 if (!circuit
->interface
)
915 "ISIS (%s): Processing %s circuit %p with unknown interface",
917 circuit_type2string(circuit
->circ_type
),
920 lsp_debug("ISIS (%s): Processing %s circuit %s",
922 circuit_type2string(circuit
->circ_type
),
923 circuit
->interface
->name
);
925 if (circuit
->state
!= C_STATE_UP
) {
926 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
931 uint32_t metric
= area
->oldmetric
932 ? circuit
->metric
[level
- 1]
933 : circuit
->te_metric
[level
- 1];
935 if (circuit
->ip_router
&& circuit
->ip_addrs
936 && circuit
->ip_addrs
->count
> 0) {
938 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
940 struct listnode
*ipnode
;
941 struct prefix_ipv4
*ipv4
;
942 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, ipnode
,
944 if (area
->oldmetric
) {
946 "ISIS (%s): Adding old-style IP reachability for %s",
948 prefix2str(ipv4
, buf
,
950 isis_tlvs_add_oldstyle_ip_reach(
951 lsp
->tlvs
, ipv4
, metric
);
954 if (area
->newmetric
) {
956 "ISIS (%s): Adding te-style IP reachability for %s",
958 prefix2str(ipv4
, buf
,
960 isis_tlvs_add_extended_ip_reach(
961 lsp
->tlvs
, ipv4
, metric
);
966 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
967 && circuit
->ipv6_non_link
->count
> 0) {
968 struct listnode
*ipnode
;
969 struct prefix_ipv6
*ipv6
;
970 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
973 "ISIS (%s): Adding IPv6 reachability for %s",
975 prefix2str(ipv6
, buf
, sizeof(buf
)));
976 isis_tlvs_add_ipv6_reach(
978 isis_area_ipv6_topology(area
), ipv6
,
983 switch (circuit
->circ_type
) {
984 case CIRCUIT_T_BROADCAST
:
985 if (level
& circuit
->is_type
) {
987 (level
== IS_LEVEL_1
)
988 ? circuit
->u
.bc
.l1_desig_is
989 : circuit
->u
.bc
.l2_desig_is
;
991 if (LSP_PSEUDO_ID(ne_id
)) {
992 if (area
->oldmetric
) {
994 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
997 LSP_PSEUDO_ID(ne_id
));
998 isis_tlvs_add_oldstyle_reach(
1002 if (area
->newmetric
) {
1003 uint8_t subtlvs
[256];
1006 if (IS_MPLS_TE(isisMplsTE
)
1008 circuit
->interface
))
1009 subtlv_len
= add_te_subtlvs(
1017 level
, ne_id
, metric
,
1018 subtlvs
, subtlv_len
);
1023 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1027 case CIRCUIT_T_P2P
: {
1028 struct isis_adjacency
*nei
= circuit
->u
.p2p
.neighbor
;
1029 if (nei
&& (level
& nei
->circuit_t
)) {
1031 memcpy(ne_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1032 LSP_PSEUDO_ID(ne_id
) = 0;
1034 if (area
->oldmetric
) {
1036 "ISIS (%s): Adding old-style is reach for %s",
1038 sysid_print(ne_id
));
1039 isis_tlvs_add_oldstyle_reach(
1040 lsp
->tlvs
, ne_id
, metric
);
1042 if (area
->newmetric
) {
1043 uint8_t subtlvs
[256];
1046 if (IS_MPLS_TE(isisMplsTE
)
1048 circuit
->interface
))
1049 /* Update Local and Remote IP
1050 * address for MPLS TE circuit
1052 /* NOTE sure that it is the
1053 * pertinent place for that
1055 /* Local IP address could be
1056 * updated in isis_circuit.c -
1057 * isis_circuit_add_addr() */
1058 /* But, where update remote IP
1059 * address ? in isis_pdu.c -
1060 * process_p2p_hello() ? */
1062 /* Add SubTLVs & Adjust real
1063 * size of SubTLVs */
1064 subtlv_len
= add_te_subtlvs(
1065 subtlvs
, circuit
->mtc
);
1067 /* Or keep only TE metric with
1068 * no SubTLVs if MPLS_TE is off
1072 tlvs_add_mt_p2p(lsp
->tlvs
, circuit
,
1073 ne_id
, metric
, subtlvs
,
1078 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1082 case CIRCUIT_T_LOOPBACK
:
1085 zlog_warn("lsp_area_create: unknown circuit type");
1089 lsp_build_ext_reach(lsp
, area
);
1091 struct isis_tlvs
*tlvs
= lsp
->tlvs
;
1095 size_t tlv_space
= STREAM_WRITEABLE(lsp
->pdu
) - LLC_LEN
;
1096 lsp_clear_data(lsp
);
1098 struct list
*fragments
= isis_fragment_tlvs(tlvs
, tlv_space
);
1100 zlog_warn("BUG: could not fragment own LSP:");
1101 log_multiline(LOG_WARNING
, " ", "%s", isis_format_tlvs(tlvs
));
1102 isis_free_tlvs(tlvs
);
1105 isis_free_tlvs(tlvs
);
1108 for (ALL_LIST_ELEMENTS_RO(fragments
, node
, tlvs
)) {
1109 if (node
!= listhead(fragments
)) {
1110 frag
= lsp_next_frag(LSP_FRAGMENT(frag
->hdr
.lsp_id
) + 1,
1116 list_delete(fragments
);
1117 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1123 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1125 int lsp_generate(struct isis_area
*area
, int level
)
1127 struct isis_lsp
*oldlsp
, *newlsp
;
1128 u_int32_t seq_num
= 0;
1129 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1130 u_int16_t rem_lifetime
, refresh_time
;
1132 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1135 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1136 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1138 /* only builds the lsp if the area shares the level */
1139 oldlsp
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
1141 /* FIXME: we should actually initiate a purge */
1142 seq_num
= oldlsp
->hdr
.seqno
;
1143 lsp_search_and_destroy(oldlsp
->hdr
.lsp_id
,
1144 area
->lspdb
[level
- 1]);
1146 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1148 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
1149 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
1151 newlsp
->area
= area
;
1152 newlsp
->own_lsp
= 1;
1154 lsp_insert(newlsp
, area
->lspdb
[level
- 1]);
1155 /* build_lsp_data (newlsp, area); */
1156 lsp_build(newlsp
, area
);
1157 /* time to calculate our checksum */
1158 lsp_seqno_update(newlsp
);
1159 newlsp
->last_generated
= time(NULL
);
1160 lsp_set_all_srmflags(newlsp
);
1162 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
1164 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
1165 area
->lsp_regenerate_pending
[level
- 1] = 0;
1166 if (level
== IS_LEVEL_1
)
1167 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
1168 &area
->t_lsp_refresh
[level
- 1]);
1169 else if (level
== IS_LEVEL_2
)
1170 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
1171 &area
->t_lsp_refresh
[level
- 1]);
1173 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1174 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1175 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1176 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1177 area
->area_tag
, level
,
1178 rawlspid_print(newlsp
->hdr
.lsp_id
),
1179 newlsp
->hdr
.pdu_len
, newlsp
->hdr
.seqno
,
1180 newlsp
->hdr
.checksum
, newlsp
->hdr
.rem_lifetime
,
1184 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1185 area
->area_tag
, level
);
1191 * Search own LSPs, update holding time and set SRM
1193 static int lsp_regenerate(struct isis_area
*area
, int level
)
1196 struct isis_lsp
*lsp
, *frag
;
1197 struct listnode
*node
;
1198 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1199 u_int16_t rem_lifetime
, refresh_time
;
1201 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
1204 lspdb
= area
->lspdb
[level
- 1];
1206 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1207 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1209 lsp
= lsp_search(lspid
, lspdb
);
1212 zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1213 area
->area_tag
, level
);
1217 lsp_clear_data(lsp
);
1218 lsp_build(lsp
, area
);
1219 rem_lifetime
= lsp_rem_lifetime(area
, level
);
1220 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1221 lsp
->last_generated
= time(NULL
);
1222 lsp_set_all_srmflags(lsp
);
1223 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1224 frag
->hdr
.lsp_bits
= lsp_bits_generate(
1225 level
, area
->overload_bit
, area
->attached_bit
);
1226 /* Set the lifetime values of all the fragments to the same
1228 * so that no fragment expires before the lsp is refreshed.
1230 frag
->hdr
.rem_lifetime
= rem_lifetime
;
1231 lsp_set_all_srmflags(frag
);
1233 lsp_seqno_update(lsp
);
1235 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1236 if (level
== IS_LEVEL_1
)
1237 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
1238 &area
->t_lsp_refresh
[level
- 1]);
1239 else if (level
== IS_LEVEL_2
)
1240 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
1241 &area
->t_lsp_refresh
[level
- 1]);
1242 area
->lsp_regenerate_pending
[level
- 1] = 0;
1244 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1246 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1247 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1248 ", lifetime %" PRIu16
"s refresh %" PRIu16
"s",
1249 area
->area_tag
, level
, rawlspid_print(lsp
->hdr
.lsp_id
),
1250 lsp
->hdr
.pdu_len
, lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1251 lsp
->hdr
.rem_lifetime
, refresh_time
);
1254 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1255 area
->area_tag
, level
);
1261 * Something has changed or periodic refresh -> regenerate LSP
1263 static int lsp_l1_refresh(struct thread
*thread
)
1265 struct isis_area
*area
;
1267 area
= THREAD_ARG(thread
);
1270 area
->t_lsp_refresh
[0] = NULL
;
1271 area
->lsp_regenerate_pending
[0] = 0;
1273 if ((area
->is_type
& IS_LEVEL_1
) == 0)
1277 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
1279 return lsp_regenerate(area
, IS_LEVEL_1
);
1282 static int lsp_l2_refresh(struct thread
*thread
)
1284 struct isis_area
*area
;
1286 area
= THREAD_ARG(thread
);
1289 area
->t_lsp_refresh
[1] = NULL
;
1290 area
->lsp_regenerate_pending
[1] = 0;
1292 if ((area
->is_type
& IS_LEVEL_2
) == 0)
1296 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
1298 return lsp_regenerate(area
, IS_LEVEL_2
);
1301 int lsp_regenerate_schedule(struct isis_area
*area
, int level
, int all_pseudo
)
1303 struct isis_lsp
*lsp
;
1304 u_char id
[ISIS_SYS_ID_LEN
+ 2];
1307 struct listnode
*cnode
;
1308 struct isis_circuit
*circuit
;
1315 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
1316 area
->area_tag
, circuit_t2string(level
),
1317 all_pseudo
? "" : "not ");
1319 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1320 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
1323 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1324 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
1328 "ISIS (%s): Checking whether L%d needs to be scheduled",
1329 area
->area_tag
, lvl
);
1331 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
1332 struct timeval remain
= thread_timer_remain(
1333 area
->t_lsp_refresh
[lvl
- 1]);
1335 "ISIS (%s): Regeneration is already pending, nothing todo."
1336 " (Due in %lld.%03lld seconds)",
1337 area
->area_tag
, (long long)remain
.tv_sec
,
1338 (long long)remain
.tv_usec
/ 1000);
1342 lsp
= lsp_search(id
, area
->lspdb
[lvl
- 1]);
1345 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1351 * Throttle avoidance
1354 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1355 area
->area_tag
, (long long)lsp
->last_generated
,
1357 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
1358 diff
= now
- lsp
->last_generated
;
1359 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
1361 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
1363 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1364 area
->area_tag
, timeout
);
1367 * lsps are not regenerated if lsp_regenerate function
1369 * directly. However if the lsp_regenerate call is
1371 * later execution it works.
1375 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1376 " Scheduling for execution in %ld ms.",
1377 area
->area_tag
, timeout
);
1380 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
1381 if (lvl
== IS_LEVEL_1
) {
1382 thread_add_timer_msec(master
, lsp_l1_refresh
, area
,
1384 &area
->t_lsp_refresh
[lvl
- 1]);
1385 } else if (lvl
== IS_LEVEL_2
) {
1386 thread_add_timer_msec(master
, lsp_l2_refresh
, area
,
1388 &area
->t_lsp_refresh
[lvl
- 1]);
1393 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
1394 lsp_regenerate_schedule_pseudo(circuit
, level
);
1401 * Funcs for pseudonode LSPs
1405 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1407 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1410 struct isis_adjacency
*adj
;
1411 struct list
*adj_list
;
1412 struct listnode
*node
;
1413 struct isis_area
*area
= circuit
->area
;
1415 lsp_clear_data(lsp
);
1416 lsp
->tlvs
= isis_alloc_tlvs();
1418 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1419 area
->area_tag
, rawlspid_print(lsp
->hdr
.lsp_id
),
1420 circuit
->interface
->name
, level
);
1423 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1425 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
1428 * add self to IS neighbours
1430 uint8_t ne_id
[ISIS_SYS_ID_LEN
+ 1];
1432 memcpy(ne_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1433 LSP_PSEUDO_ID(ne_id
) = 0;
1435 if (circuit
->area
->oldmetric
) {
1436 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1438 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1439 area
->area_tag
, sysid_print(ne_id
),
1440 LSP_PSEUDO_ID(ne_id
));
1442 if (circuit
->area
->newmetric
) {
1443 isis_tlvs_add_extended_reach(lsp
->tlvs
, ISIS_MT_IPV4_UNICAST
,
1446 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1447 area
->area_tag
, sysid_print(ne_id
),
1448 LSP_PSEUDO_ID(ne_id
));
1451 adj_list
= list_new();
1452 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1454 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1455 if (!(adj
->level
& level
)) {
1457 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1458 area
->area_tag
, sysid_print(adj
->sysid
));
1462 if (!(level
== IS_LEVEL_1
1463 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
1464 && !(level
== IS_LEVEL_1
1465 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
1466 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
1467 && !(level
== IS_LEVEL_2
1468 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
1470 "ISIS (%s): Ignoring neighbor %s, level does not match",
1471 area
->area_tag
, sysid_print(adj
->sysid
));
1475 memcpy(ne_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1476 if (circuit
->area
->oldmetric
) {
1477 isis_tlvs_add_oldstyle_reach(lsp
->tlvs
, ne_id
, 0);
1479 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1480 area
->area_tag
, sysid_print(ne_id
),
1481 LSP_PSEUDO_ID(ne_id
));
1483 if (circuit
->area
->newmetric
) {
1484 isis_tlvs_add_extended_reach(lsp
->tlvs
,
1485 ISIS_MT_IPV4_UNICAST
,
1488 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1489 area
->area_tag
, sysid_print(ne_id
),
1490 LSP_PSEUDO_ID(ne_id
));
1493 list_delete(adj_list
);
1497 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
1499 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1500 struct isis_lsp
*lsp
;
1501 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1502 u_int16_t rem_lifetime
, refresh_time
;
1504 if ((circuit
->is_type
& level
) != level
1505 || (circuit
->state
!= C_STATE_UP
)
1506 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1507 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1510 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1511 LSP_FRAGMENT(lsp_id
) = 0;
1512 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1515 * If for some reason have a pseudo LSP in the db already -> regenerate
1517 if (lsp_search(lsp_id
, lspdb
))
1518 return lsp_regenerate_schedule_pseudo(circuit
, level
);
1520 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1521 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1522 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
1523 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
1525 lsp
->area
= circuit
->area
;
1527 lsp_build_pseudo(lsp
, circuit
, level
);
1530 lsp_insert(lsp
, lspdb
);
1531 lsp_set_all_srmflags(lsp
);
1533 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1534 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1535 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
1536 if (level
== IS_LEVEL_1
)
1538 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1539 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1540 else if (level
== IS_LEVEL_2
)
1542 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1543 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1545 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1547 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1548 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1549 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1550 circuit
->area
->area_tag
, level
,
1551 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1552 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1553 lsp
->hdr
.rem_lifetime
, refresh_time
);
1559 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
1561 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1562 struct isis_lsp
*lsp
;
1563 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1564 u_int16_t rem_lifetime
, refresh_time
;
1566 if ((circuit
->is_type
& level
) != level
1567 || (circuit
->state
!= C_STATE_UP
)
1568 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1569 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
1572 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1573 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1574 LSP_FRAGMENT(lsp_id
) = 0;
1576 lsp
= lsp_search(lsp_id
, lspdb
);
1579 zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
1580 rawlspid_print(lsp_id
));
1584 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
1585 lsp
->hdr
.rem_lifetime
= rem_lifetime
;
1586 lsp_build_pseudo(lsp
, circuit
, level
);
1587 lsp_inc_seqno(lsp
, 0);
1588 lsp
->last_generated
= time(NULL
);
1589 lsp_set_all_srmflags(lsp
);
1591 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
1592 if (level
== IS_LEVEL_1
)
1594 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
1595 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1596 else if (level
== IS_LEVEL_2
)
1598 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
1599 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
1601 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
1603 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1604 ", seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1605 ", lifetime %" PRIu16
"s, refresh %" PRIu16
"s",
1606 circuit
->area
->area_tag
, level
,
1607 rawlspid_print(lsp
->hdr
.lsp_id
), lsp
->hdr
.pdu_len
,
1608 lsp
->hdr
.seqno
, lsp
->hdr
.checksum
,
1609 lsp
->hdr
.rem_lifetime
, refresh_time
);
1616 * Something has changed or periodic refresh -> regenerate pseudo LSP
1618 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
1620 struct isis_circuit
*circuit
;
1621 u_char id
[ISIS_SYS_ID_LEN
+ 2];
1623 circuit
= THREAD_ARG(thread
);
1625 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1626 circuit
->lsp_regenerate_pending
[0] = 0;
1628 if ((circuit
->u
.bc
.is_dr
[0] == 0)
1629 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
1630 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1631 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1632 LSP_FRAGMENT(id
) = 0;
1633 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
1637 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
1640 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
1642 struct isis_circuit
*circuit
;
1643 u_char id
[ISIS_SYS_ID_LEN
+ 2];
1645 circuit
= THREAD_ARG(thread
);
1647 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
1648 circuit
->lsp_regenerate_pending
[1] = 0;
1650 if ((circuit
->u
.bc
.is_dr
[1] == 0)
1651 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
1652 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1653 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
1654 LSP_FRAGMENT(id
) = 0;
1655 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
1659 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
1662 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
1664 struct isis_lsp
*lsp
;
1665 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1669 struct isis_area
*area
= circuit
->area
;
1671 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
1672 || circuit
->state
!= C_STATE_UP
)
1676 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1677 area
->area_tag
, circuit_t2string(level
),
1678 circuit
->interface
->name
);
1680 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1681 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
1682 LSP_FRAGMENT(lsp_id
) = 0;
1685 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
1687 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1688 area
->area_tag
, lvl
);
1690 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
1691 sched_debug("ISIS (%s): Level is not active on circuit",
1696 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
1698 "ISIS (%s): This IS is not DR, nothing to do.",
1703 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
1704 struct timeval remain
= thread_timer_remain(
1705 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1707 "ISIS (%s): Regenerate is already pending, nothing todo."
1708 " (Due in %lld.%03lld seconds)",
1709 area
->area_tag
, (long long)remain
.tv_sec
,
1710 (long long)remain
.tv_usec
/ 1000);
1714 lsp
= lsp_search(lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
1717 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1723 * Throttle avoidance
1726 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1727 area
->area_tag
, (long long)lsp
->last_generated
,
1729 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1730 diff
= now
- lsp
->last_generated
;
1731 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
1733 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
1736 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1737 area
->area_tag
, timeout
);
1741 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1742 " Scheduling for execution in %ld ms.",
1743 area
->area_tag
, timeout
);
1746 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
1748 if (lvl
== IS_LEVEL_1
) {
1749 thread_add_timer_msec(
1750 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
1751 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1752 } else if (lvl
== IS_LEVEL_2
) {
1753 thread_add_timer_msec(
1754 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
1755 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
1763 * Walk through LSPs for an area
1764 * - set remaining lifetime
1765 * - set LSPs with SRMflag set for sending
1767 int lsp_tick(struct thread
*thread
)
1769 struct isis_area
*area
;
1770 struct isis_circuit
*circuit
;
1771 struct isis_lsp
*lsp
;
1772 struct list
*lsp_list
;
1773 struct listnode
*lspnode
, *cnode
;
1774 dnode_t
*dnode
, *dnode_next
;
1776 u_int16_t rem_lifetime
;
1778 lsp_list
= list_new();
1780 area
= THREAD_ARG(thread
);
1782 area
->t_tick
= NULL
;
1783 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
1786 * Build a list of LSPs with (any) SRMflag set
1787 * and removed the ones that have aged out
1789 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
1790 if (area
->lspdb
[level
] && dict_count(area
->lspdb
[level
]) > 0) {
1791 for (dnode
= dict_first(area
->lspdb
[level
]);
1792 dnode
!= NULL
; dnode
= dnode_next
) {
1794 dict_next(area
->lspdb
[level
], dnode
);
1795 lsp
= dnode_get(dnode
);
1798 * The lsp rem_lifetime is kept at 0 for MaxAge
1800 * ZeroAgeLifetime depending on explicit purge
1802 * natural age out. So schedule spf only once
1804 * the first time rem_lifetime becomes 0.
1806 rem_lifetime
= lsp
->hdr
.rem_lifetime
;
1810 * Schedule may run spf which should be done
1812 * the lsp rem_lifetime becomes 0 for the first
1814 * ISO 10589 - 7.3.16.4 first paragraph.
1816 if (rem_lifetime
== 1 && lsp
->hdr
.seqno
!= 0) {
1817 /* 7.3.16.4 a) set SRM flags on all */
1818 lsp_set_all_srmflags(lsp
);
1819 /* 7.3.16.4 b) retain only the header
1821 /* 7.3.16.4 c) record the time to purge
1823 /* run/schedule spf */
1824 /* isis_spf_schedule is called inside
1825 * lsp_destroy() below;
1826 * so it is not needed here. */
1827 /* isis_spf_schedule (lsp->area,
1831 if (lsp
->age_out
== 0) {
1833 "ISIS-Upd (%s): L%u LSP %s seq "
1834 "0x%08" PRIx32
" aged out",
1835 area
->area_tag
, lsp
->level
,
1836 rawlspid_print(lsp
->hdr
.lsp_id
),
1840 dict_delete_free(area
->lspdb
[level
],
1842 } else if (flags_any_set(lsp
->SRMflags
))
1843 listnode_add(lsp_list
, lsp
);
1847 * Send LSPs on circuits indicated by the SRMflags
1849 if (listcount(lsp_list
) > 0) {
1850 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
1854 - circuit
->lsp_queue_last_cleared
;
1855 if (circuit
->lsp_queue
== NULL
1856 || diff
< MIN_LSP_TRANS_INTERVAL
)
1858 for (ALL_LIST_ELEMENTS_RO(
1859 lsp_list
, lspnode
, lsp
)) {
1860 if (circuit
->upadjcount
1865 /* Add the lsp only if
1866 * it is not already in
1869 if (!listnode_lookup(
1885 list_delete_all_node(lsp_list
);
1890 list_delete(lsp_list
);
1895 void lsp_purge_pseudo(u_char
*id
, struct isis_circuit
*circuit
, int level
)
1897 struct isis_lsp
*lsp
;
1899 lsp
= lsp_search(id
, circuit
->area
->lspdb
[level
- 1]);
1903 lsp_purge(lsp
, level
);
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
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
1922 lsp
->age_out
= ZERO_AGE_LIFETIME
;
1924 memcpy(&lsp
->hdr
, hdr
, sizeof(lsp
->hdr
));
1925 lsp
->hdr
.rem_lifetime
= 0;
1929 lsp_insert(lsp
, area
->lspdb
[lsp
->level
- 1]);
1930 lsp_set_all_srmflags(lsp
);
1935 void lsp_set_all_srmflags(struct isis_lsp
*lsp
)
1937 struct listnode
*node
;
1938 struct isis_circuit
*circuit
;
1942 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
1945 struct list
*circuit_list
= lsp
->area
->circuit_list
;
1946 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
1947 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);