]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
Merge pull request #12819 from isabelladeleon12/isis_load_config_before_lsp_gen
[mirror_frr.git] / isisd / isis_lsp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS Rout(e)ing protocol - isis_lsp.c
4 * LSP processing
5 *
6 * Copyright (C) 2001,2002 Sampo Saaristo
7 * Tampere University of Technology
8 * Institute of Communications Engineering
9 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
10 */
11
12 #include <zebra.h>
13
14 #include "linklist.h"
15 #include "thread.h"
16 #include "vty.h"
17 #include "stream.h"
18 #include "memory.h"
19 #include "log.h"
20 #include "prefix.h"
21 #include "command.h"
22 #include "hash.h"
23 #include "if.h"
24 #include "checksum.h"
25 #include "md5.h"
26 #include "table.h"
27 #include "srcdest_table.h"
28 #include "lib_errors.h"
29
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_common.h"
32 #include "isisd/isis_flags.h"
33 #include "isisd/isis_circuit.h"
34 #include "isisd/isisd.h"
35 #include "isisd/isis_lsp.h"
36 #include "isisd/isis_pdu.h"
37 #include "isisd/isis_dynhn.h"
38 #include "isisd/isis_misc.h"
39 #include "isisd/isis_csm.h"
40 #include "isisd/isis_adjacency.h"
41 #include "isisd/isis_spf.h"
42 #include "isisd/isis_mt.h"
43 #include "isisd/isis_tlvs.h"
44 #include "isisd/isis_te.h"
45 #include "isisd/isis_sr.h"
46 #include "isisd/fabricd.h"
47 #include "isisd/isis_tx_queue.h"
48 #include "isisd/isis_nb.h"
49
50 DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
51
52 static void lsp_refresh(struct thread *thread);
53 static void lsp_l1_refresh_pseudo(struct thread *thread);
54 static void lsp_l2_refresh_pseudo(struct thread *thread);
55
56 static void lsp_destroy(struct isis_lsp *lsp);
57
58 static bool device_startup;
59
60 int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
61 {
62 return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
63 }
64
65 int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b)
66 {
67 return memcmp(a->hdr.lsp_id, b->hdr.lsp_id, sizeof(a->hdr.lsp_id));
68 }
69
70 void lsp_db_init(struct lspdb_head *head)
71 {
72 lspdb_init(head);
73 }
74
75 void lsp_db_fini(struct lspdb_head *head)
76 {
77 struct isis_lsp *lsp;
78
79 while ((lsp = lspdb_pop(head)))
80 lsp_destroy(lsp);
81 lspdb_fini(head);
82 }
83
84 struct isis_lsp *lsp_search(struct lspdb_head *head, const uint8_t *id)
85 {
86 struct isis_lsp searchfor;
87 memcpy(searchfor.hdr.lsp_id, id, sizeof(searchfor.hdr.lsp_id));
88
89 return lspdb_find(head, &searchfor);
90 }
91
92 static void lsp_clear_data(struct isis_lsp *lsp)
93 {
94 if (!lsp)
95 return;
96
97 isis_free_tlvs(lsp->tlvs);
98 lsp->tlvs = NULL;
99 }
100
101 static void lsp_remove_frags(struct lspdb_head *head, struct list *frags);
102
103 static void lsp_destroy(struct isis_lsp *lsp)
104 {
105 struct listnode *cnode;
106 struct isis_circuit *circuit;
107
108 if (!lsp)
109 return;
110
111 for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode, circuit))
112 isis_tx_queue_del(circuit->tx_queue, lsp);
113
114 ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
115
116 isis_te_lsp_event(lsp, LSP_DEL);
117
118 lsp_clear_data(lsp);
119
120 if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
121 if (lsp->lspu.frags) {
122 lsp_remove_frags(&lsp->area->lspdb[lsp->level - 1],
123 lsp->lspu.frags);
124 list_delete(&lsp->lspu.frags);
125 }
126 } else {
127 if (lsp->lspu.zero_lsp
128 && lsp->lspu.zero_lsp->lspu.frags) {
129 listnode_delete(lsp->lspu.zero_lsp->lspu.frags, lsp);
130 }
131 }
132
133 isis_spf_schedule(lsp->area, lsp->level);
134
135 if (lsp->pdu)
136 stream_free(lsp->pdu);
137
138 fabricd_lsp_free(lsp);
139 XFREE(MTYPE_ISIS_LSP, lsp);
140 }
141
142 /*
143 * Remove all the frags belonging to the given lsp
144 */
145 static void lsp_remove_frags(struct lspdb_head *head, struct list *frags)
146 {
147 struct listnode *lnode, *lnnode;
148 struct isis_lsp *lsp;
149
150 for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
151 lsp = lsp_search(head, lsp->hdr.lsp_id);
152 lspdb_del(head, lsp);
153 lsp_destroy(lsp);
154 }
155 }
156
157 void lsp_search_and_destroy(struct lspdb_head *head, const uint8_t *id)
158 {
159 struct isis_lsp *lsp;
160
161 lsp = lsp_search(head, id);
162 if (lsp) {
163 lspdb_del(head, lsp);
164 /*
165 * If this is a zero lsp, remove all the frags now
166 */
167 if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) {
168 if (lsp->lspu.frags)
169 lsp_remove_frags(head, lsp->lspu.frags);
170 } else {
171 /*
172 * else just remove this frag, from the zero lsps' frag
173 * list
174 */
175 if (lsp->lspu.zero_lsp
176 && lsp->lspu.zero_lsp->lspu.frags)
177 listnode_delete(lsp->lspu.zero_lsp->lspu.frags,
178 lsp);
179 }
180 lsp_destroy(lsp);
181 }
182 }
183
184 /*
185 * Compares a LSP to given values
186 * Params are given in net order
187 */
188 int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
189 uint16_t checksum, uint16_t rem_lifetime)
190 {
191 if (lsp->hdr.seqno == seqno && lsp->hdr.checksum == checksum
192 && ((lsp->hdr.rem_lifetime == 0 && rem_lifetime == 0)
193 || (lsp->hdr.rem_lifetime != 0 && rem_lifetime != 0))) {
194 if (IS_DEBUG_SNP_PACKETS) {
195 zlog_debug(
196 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
197 areatag, rawlspid_print(lsp->hdr.lsp_id),
198 lsp->hdr.seqno, lsp->hdr.checksum,
199 lsp->hdr.rem_lifetime);
200 zlog_debug(
201 "ISIS-Snp (%s): is equal to ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
202 areatag, seqno, checksum, rem_lifetime);
203 }
204 return LSP_EQUAL;
205 }
206
207 /*
208 * LSPs with identical checksums should only be treated as newer if:
209 * a) The current LSP has a remaining lifetime != 0 and the other LSP
210 * has a
211 * remaining lifetime == 0. In this case, we should participate in
212 * the purge
213 * and should not treat the current LSP with remaining lifetime == 0
214 * as older.
215 * b) The LSP has an incorrect checksum. In this case, we need to react
216 * as given
217 * in 7.3.16.2.
218 */
219 if (seqno > lsp->hdr.seqno
220 || (seqno == lsp->hdr.seqno
221 && ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
222 || (lsp->hdr.checksum != checksum
223 && lsp->hdr.rem_lifetime)))) {
224 if (IS_DEBUG_SNP_PACKETS) {
225 zlog_debug(
226 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
227 areatag, rawlspid_print(lsp->hdr.lsp_id), seqno,
228 checksum, rem_lifetime);
229 zlog_debug(
230 "ISIS-Snp (%s): is newer than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
231 areatag, lsp->hdr.seqno, lsp->hdr.checksum,
232 lsp->hdr.rem_lifetime);
233 }
234 return LSP_NEWER;
235 }
236 if (IS_DEBUG_SNP_PACKETS) {
237 zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04hx, lifetime %hus",
238 areatag, rawlspid_print(lsp->hdr.lsp_id), seqno,
239 checksum, rem_lifetime);
240 zlog_debug(
241 "ISIS-Snp (%s): is older than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
242 areatag, lsp->hdr.seqno, lsp->hdr.checksum,
243 lsp->hdr.rem_lifetime);
244 }
245
246 return LSP_OLDER;
247 }
248
249 static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer, bool keep)
250 {
251 uint8_t pdu_type =
252 (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
253 struct isis_lsp_hdr *hdr = &lsp->hdr;
254 struct stream *stream = lsp->pdu;
255 size_t orig_getp = 0, orig_endp = 0;
256
257 if (keep) {
258 orig_getp = stream_get_getp(lsp->pdu);
259 orig_endp = stream_get_endp(lsp->pdu);
260 }
261
262 stream_set_getp(lsp->pdu, 0);
263 stream_set_endp(lsp->pdu, 0);
264
265 fill_fixed_hdr(pdu_type, stream);
266
267 if (len_pointer)
268 *len_pointer = stream_get_endp(stream);
269 stream_putw(stream, hdr->pdu_len);
270 stream_putw(stream, hdr->rem_lifetime);
271 stream_put(stream, hdr->lsp_id, sizeof(hdr->lsp_id));
272 stream_putl(stream, hdr->seqno);
273 stream_putw(stream, hdr->checksum);
274 stream_putc(stream, hdr->lsp_bits);
275
276 if (keep) {
277 stream_set_endp(lsp->pdu, orig_endp);
278 stream_set_getp(lsp->pdu, orig_getp);
279 }
280 }
281
282 static void lsp_add_auth(struct isis_lsp *lsp)
283 {
284 struct isis_passwd *passwd;
285 passwd = (lsp->level == IS_LEVEL_1) ? &lsp->area->area_passwd
286 : &lsp->area->domain_passwd;
287 isis_tlvs_add_auth(lsp->tlvs, passwd);
288 }
289
290 static void lsp_pack_pdu(struct isis_lsp *lsp)
291 {
292 if (!lsp->tlvs)
293 lsp->tlvs = isis_alloc_tlvs();
294
295 lsp_add_auth(lsp);
296
297 size_t len_pointer;
298 put_lsp_hdr(lsp, &len_pointer, false);
299 isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true);
300
301 lsp->hdr.pdu_len = stream_get_endp(lsp->pdu);
302 lsp->hdr.checksum =
303 ntohs(fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
304 stream_get_endp(lsp->pdu) - 12, 12));
305 }
306
307 void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
308 {
309 uint32_t newseq;
310
311 if (seqno == 0 || lsp->hdr.seqno > seqno)
312 newseq = lsp->hdr.seqno + 1;
313 else
314 newseq = seqno + 1;
315
316 #ifndef FABRICD
317 /* check for overflow */
318 if (newseq < lsp->hdr.seqno) {
319 /* send northbound notification */
320 lsp->area->lsp_exceeded_max_counter++;
321 isis_notif_lsp_exceed_max(lsp->area, lsp->hdr.lsp_id);
322 }
323 #endif /* ifndef FABRICD */
324
325 lsp->hdr.seqno = newseq;
326
327 lsp_pack_pdu(lsp);
328 isis_spf_schedule(lsp->area, lsp->level);
329 isis_te_lsp_event(lsp, LSP_INC);
330 }
331
332 static void lsp_purge_add_poi(struct isis_lsp *lsp,
333 const uint8_t *sender)
334 {
335 if (lsp->area == NULL)
336 return;
337
338 if (!lsp->area->purge_originator)
339 return;
340
341 /* add purge originator identification */
342 if (!lsp->tlvs)
343 lsp->tlvs = isis_alloc_tlvs();
344 isis_tlvs_set_purge_originator(lsp->tlvs, lsp->area->isis->sysid,
345 sender);
346 isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
347 }
348
349 static void lsp_purge(struct isis_lsp *lsp, int level,
350 const uint8_t *sender)
351 {
352 /* reset stream */
353 lsp_clear_data(lsp);
354 stream_reset(lsp->pdu);
355
356 /* update header */
357 lsp->hdr.checksum = 0;
358 lsp->hdr.rem_lifetime = 0;
359 lsp->level = level;
360 lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
361 lsp->area->lsp_purge_count[level - 1]++;
362
363 lsp_purge_add_poi(lsp, sender);
364
365 lsp_pack_pdu(lsp);
366 lsp_flood(lsp, NULL);
367 }
368
369 /*
370 * Generates checksum for LSP and its frags
371 */
372 static void lsp_seqno_update(struct isis_lsp *lsp0)
373 {
374 struct isis_lsp *lsp;
375 struct listnode *node;
376
377 lsp_inc_seqno(lsp0, 0);
378
379 if (!lsp0->lspu.frags)
380 return;
381
382 for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) {
383 if (lsp->tlvs)
384 lsp_inc_seqno(lsp, 0);
385 else if (lsp->hdr.rem_lifetime) {
386 /* Purge should only be applied when the fragment has
387 * non-zero remaining lifetime.
388 */
389 lsp_purge(lsp, lsp0->level, NULL);
390 }
391 }
392
393 return;
394 }
395
396 bool isis_level2_adj_up(struct isis_area *area)
397 {
398 struct listnode *node, *cnode;
399 struct isis_circuit *circuit;
400 struct list *adjdb;
401 struct isis_adjacency *adj;
402
403 if (area->is_type == IS_LEVEL_1)
404 return false;
405
406 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
407 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
408 adjdb = circuit->u.bc.adjdb[1];
409 if (!adjdb || !adjdb->count)
410 continue;
411
412 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
413 if (adj->level != ISIS_ADJ_LEVEL1
414 && adj->adj_state == ISIS_ADJ_UP)
415 return true;
416 }
417 } else if (circuit->circ_type == CIRCUIT_T_P2P
418 && circuit->u.p2p.neighbor) {
419 adj = circuit->u.p2p.neighbor;
420 if (adj->level != ISIS_ADJ_LEVEL1
421 && adj->adj_state == ISIS_ADJ_UP)
422 return true;
423 }
424 }
425
426 return false;
427 }
428
429 /*
430 * Unset the overload bit after the timer expires
431 */
432 void set_overload_on_start_timer(struct thread *thread)
433 {
434 struct isis_area *area = THREAD_ARG(thread);
435 assert(area);
436
437 area->t_overload_on_startup_timer = NULL;
438
439 /* Check if set-overload-bit is not currently configured */
440 if (!area->overload_configured)
441 isis_area_overload_bit_set(area, false);
442 }
443
444 static void isis_reset_attach_bit(struct isis_adjacency *adj)
445 {
446 struct isis_area *area = adj->circuit->area;
447 struct lspdb_head *head;
448 struct isis_lsp *lsp;
449 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
450
451 /*
452 * If an L2 adjacency changed its state in L-1-2 area, we have to:
453 * - set the attached bit in L1 LSPs if it's the first L2 adjacency
454 * - remove the attached bit in L1 LSPs if it's the last L2 adjacency
455 */
456
457 if (area->is_type != IS_LEVEL_1_AND_2 || adj->level == ISIS_ADJ_LEVEL1)
458 return;
459
460 if (!area->attached_bit_send)
461 return;
462
463 head = &area->lspdb[IS_LEVEL_1 - 1];
464 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
465 memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
466
467 lsp = lsp_search(head, lspid);
468 if (!lsp)
469 return;
470
471 if (adj->adj_state == ISIS_ADJ_UP
472 && !(lsp->hdr.lsp_bits & LSPBIT_ATT)) {
473 sched_debug("ISIS (%s): adj going up regenerate lsp-bits",
474 area->area_tag);
475 lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
476 } else if (adj->adj_state == ISIS_ADJ_DOWN
477 && (lsp->hdr.lsp_bits & LSPBIT_ATT)
478 && !isis_level2_adj_up(area)) {
479 sched_debug("ISIS (%s): adj going down regenerate lsp-bits",
480 area->area_tag);
481 lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
482 }
483 }
484
485 static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit,
486 struct isis_area *area)
487 {
488 uint8_t lsp_bits = 0;
489 if (area->is_type == IS_LEVEL_1)
490 lsp_bits = IS_LEVEL_1;
491 else
492 lsp_bits = IS_LEVEL_1_AND_2;
493 if (overload_bit)
494 lsp_bits |= overload_bit;
495
496 /* only set the attach bit if we are a level-1-2 router and this is
497 * a level-1 LSP and we have a level-2 adjacency up from another area
498 */
499 if (area->is_type == IS_LEVEL_1_AND_2 && level == IS_LEVEL_1
500 && attached_bit && isis_level2_adj_up(area))
501 lsp_bits |= LSPBIT_ATT;
502 return lsp_bits;
503 }
504
505 static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
506 struct isis_tlvs *tlvs, struct stream *stream,
507 struct isis_area *area, int level)
508 {
509 /* free the old lsp data */
510 lsp_clear_data(lsp);
511
512 /* copying only the relevant part of our stream */
513 if (lsp->pdu != NULL)
514 stream_free(lsp->pdu);
515 lsp->pdu = stream_dup(stream);
516
517 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
518 lsp->area = area;
519 lsp->level = level;
520 lsp->age_out = ZERO_AGE_LIFETIME;
521 lsp->installed = time(NULL);
522
523 lsp->tlvs = tlvs;
524
525 if (area->dynhostname && lsp->tlvs->hostname
526 && lsp->hdr.rem_lifetime) {
527 isis_dynhn_insert(
528 area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
529 (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
530 ? IS_LEVEL_2
531 : IS_LEVEL_1);
532 }
533
534 return;
535 }
536
537 static void lsp_link_fragment(struct isis_lsp *lsp, struct isis_lsp *lsp0)
538 {
539 if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
540 /* zero lsp -> create list to store fragments */
541 lsp->lspu.frags = list_new();
542 } else {
543 /* fragment -> set backpointer and add to zero lsps list */
544 assert(lsp0);
545 lsp->lspu.zero_lsp = lsp0;
546 listnode_add(lsp0->lspu.frags, lsp);
547 }
548 }
549
550 void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
551 struct isis_tlvs *tlvs, struct stream *stream,
552 struct isis_area *area, int level, bool confusion)
553 {
554 if (lsp->own_lsp) {
555 flog_err(
556 EC_LIB_DEVELOPMENT,
557 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
558 area->area_tag, rawlspid_print(lsp->hdr.lsp_id));
559 lsp_clear_data(lsp);
560 lsp->own_lsp = 0;
561 }
562
563 if (confusion) {
564 lsp_purge(lsp, level, NULL);
565 } else {
566 lsp_update_data(lsp, hdr, tlvs, stream, area, level);
567 }
568
569 if (LSP_FRAGMENT(lsp->hdr.lsp_id) && !lsp->lspu.zero_lsp) {
570 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
571 struct isis_lsp *lsp0;
572
573 memcpy(lspid, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
574 LSP_FRAGMENT(lspid) = 0;
575 lsp0 = lsp_search(&area->lspdb[level - 1], lspid);
576 if (lsp0)
577 lsp_link_fragment(lsp, lsp0);
578 }
579
580 if (lsp->hdr.seqno) {
581 isis_spf_schedule(lsp->area, lsp->level);
582 isis_te_lsp_event(lsp, LSP_UPD);
583 }
584 }
585
586 /* creation of LSP directly from what we received */
587 struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr,
588 struct isis_tlvs *tlvs,
589 struct stream *stream, struct isis_lsp *lsp0,
590 struct isis_area *area, int level)
591 {
592 struct isis_lsp *lsp;
593
594 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
595 lsp_update_data(lsp, hdr, tlvs, stream, area, level);
596 lsp_link_fragment(lsp, lsp0);
597
598 return lsp;
599 }
600
601 static void lsp_adjust_stream(struct isis_lsp *lsp)
602 {
603 if (lsp->pdu) {
604 if (STREAM_SIZE(lsp->pdu) == LLC_LEN + lsp->area->lsp_mtu)
605 return;
606 stream_free(lsp->pdu);
607 }
608
609 lsp->pdu = stream_new(LLC_LEN + lsp->area->lsp_mtu);
610 }
611
612 struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
613 uint16_t rem_lifetime, uint32_t seqno,
614 uint8_t lsp_bits, uint16_t checksum,
615 struct isis_lsp *lsp0, int level)
616 {
617 struct isis_lsp *lsp;
618
619 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
620 lsp->area = area;
621
622 lsp_adjust_stream(lsp);
623
624 /* Minimal LSP PDU size */
625 lsp->hdr.pdu_len = ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN;
626 memcpy(lsp->hdr.lsp_id, lsp_id, sizeof(lsp->hdr.lsp_id));
627 lsp->hdr.checksum = checksum;
628 lsp->hdr.seqno = seqno;
629 lsp->hdr.rem_lifetime = rem_lifetime;
630 lsp->hdr.lsp_bits = lsp_bits;
631 lsp->level = level;
632 lsp->age_out = ZERO_AGE_LIFETIME;
633 lsp_link_fragment(lsp, lsp0);
634 put_lsp_hdr(lsp, NULL, false);
635
636 if (IS_DEBUG_EVENTS)
637 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
638 sysid_print(lsp_id), LSP_PSEUDO_ID(lsp->hdr.lsp_id),
639 LSP_FRAGMENT(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
640 lsp->hdr.seqno);
641
642 return lsp;
643 }
644
645 void lsp_insert(struct lspdb_head *head, struct isis_lsp *lsp)
646 {
647 lspdb_add(head, lsp);
648 if (lsp->hdr.seqno) {
649 isis_spf_schedule(lsp->area, lsp->level);
650 isis_te_lsp_event(lsp, LSP_ADD);
651 }
652 }
653
654 /*
655 * Build a list of LSPs with non-zero ht and seqno bounded by start and stop ids
656 */
657 void lsp_build_list_nonzero_ht(struct lspdb_head *head, const uint8_t *start_id,
658 const uint8_t *stop_id, struct list *list)
659 {
660 struct isis_lsp searchfor;
661 struct isis_lsp *lsp, *start;
662
663 memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
664
665 start = lspdb_find_gteq(head, &searchfor);
666 frr_each_from (lspdb, head, lsp, start) {
667 if (memcmp(lsp->hdr.lsp_id, stop_id,
668 ISIS_SYS_ID_LEN + 2) > 0)
669 break;
670
671 if (lsp->hdr.rem_lifetime && lsp->hdr.seqno)
672 listnode_add(list, lsp);
673 }
674 }
675
676 static void lsp_set_time(struct isis_lsp *lsp)
677 {
678 assert(lsp);
679
680 if (lsp->hdr.rem_lifetime == 0) {
681 if (lsp->age_out > 0)
682 lsp->age_out--;
683 return;
684 }
685
686 lsp->hdr.rem_lifetime--;
687 if (lsp->pdu && stream_get_endp(lsp->pdu) >= 12)
688 stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime);
689 }
690
691 void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
692 char frag, struct isis *isis)
693 {
694 struct isis_dynhn *dyn = NULL;
695 char id[SYSID_STRLEN];
696
697 if (dynhost)
698 dyn = dynhn_find_by_id(isis, lsp_id);
699 else
700 dyn = NULL;
701
702 if (dyn)
703 snprintf(id, sizeof(id), "%.14s", dyn->hostname);
704 else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
705 snprintf(id, sizeof(id), "%.14s", cmd_hostname_get());
706 else
707 memcpy(id, sysid_print(lsp_id), 15);
708
709 if (frag)
710 snprintf(dest, dest_len, "%s.%02x-%02x", id,
711 LSP_PSEUDO_ID(lsp_id), LSP_FRAGMENT(lsp_id));
712 else
713 snprintf(dest, dest_len, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id));
714 }
715
716 /* Convert the lsp attribute bits to attribute string */
717 static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
718 {
719 char *pos = buf;
720
721 if (!lsp_bits)
722 return " none";
723
724 if (buf_size < 2 * 3)
725 return " error";
726
727 /* we only focus on the default metric */
728 pos += snprintf(pos, buf_size, "%d/",
729 ISIS_MASK_LSP_ATT_BITS(lsp_bits) ? 1 : 0);
730
731 pos += snprintf(pos, buf_size, "%d/",
732 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
733
734 snprintf(pos, buf_size, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
735
736 return buf;
737 }
738
739 /* this function prints the lsp on show isis database */
740 void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object *json,
741 char dynhost, struct isis *isis)
742 {
743 if (json) {
744 return lsp_print_json(lsp, json, dynhost, isis);
745 } else {
746 return lsp_print_vty(lsp, vty, dynhost, isis);
747 }
748 }
749
750 void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
751 char dynhost, struct isis *isis)
752 {
753 char LSPid[255];
754 char age_out[8];
755 char b[200];
756 json_object *own_json;
757 char buf[256];
758
759 lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis);
760 own_json = json_object_new_object();
761 json_object_object_add(json, "lsp", own_json);
762 json_object_string_add(own_json, "id", LSPid);
763 json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " ");
764 json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len);
765 snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno);
766 json_object_string_add(json, "seq-number", buf);
767 snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum);
768 json_object_string_add(json, "chksum", buf);
769 if (lsp->hdr.rem_lifetime == 0) {
770 snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out);
771 age_out[7] = '\0';
772 json_object_string_add(json, "holdtime", age_out);
773 } else {
774 json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime);
775 }
776 json_object_string_add(
777 json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
778 }
779
780 void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty,
781 char dynhost, struct isis *isis)
782 {
783 char LSPid[255];
784 char age_out[8];
785 char b[200];
786
787 lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis);
788 vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
789 vty_out(vty, "%5hu ", lsp->hdr.pdu_len);
790 vty_out(vty, "0x%08x ", lsp->hdr.seqno);
791 vty_out(vty, "0x%04hx ", lsp->hdr.checksum);
792 if (lsp->hdr.rem_lifetime == 0) {
793 snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out);
794 age_out[7] = '\0';
795 vty_out(vty, "%7s ", age_out);
796 } else
797 vty_out(vty, " %5hu ", lsp->hdr.rem_lifetime);
798 vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
799 }
800
801 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty,
802 struct json_object *json, char dynhost,
803 struct isis *isis)
804 {
805 if (json) {
806 lsp_print_json(lsp, json, dynhost, isis);
807 if (lsp->tlvs) {
808 isis_format_tlvs(lsp->tlvs, json);
809 }
810 } else {
811 lsp_print_vty(lsp, vty, dynhost, isis);
812 if (lsp->tlvs)
813 vty_multiline(vty, " ", "%s",
814 isis_format_tlvs(lsp->tlvs, NULL));
815 vty_out(vty, "\n");
816 }
817 }
818
819 /* print all the lsps info in the local lspdb */
820 int lsp_print_all(struct vty *vty, struct json_object *json,
821 struct lspdb_head *head, char detail, char dynhost,
822 struct isis *isis)
823 {
824 struct isis_lsp *lsp;
825 int lsp_count = 0;
826
827 if (detail == ISIS_UI_LEVEL_BRIEF) {
828 frr_each (lspdb, head, lsp) {
829 lsp_print_common(lsp, vty, json, dynhost, isis);
830 lsp_count++;
831 }
832 } else if (detail == ISIS_UI_LEVEL_DETAIL) {
833 frr_each (lspdb, head, lsp) {
834 lsp_print_detail(lsp, vty, json, dynhost, isis);
835 lsp_count++;
836 }
837 }
838
839 return lsp_count;
840 }
841
842 static uint16_t lsp_rem_lifetime(struct isis_area *area, int level)
843 {
844 uint16_t rem_lifetime;
845
846 /* Add jitter to configured LSP lifetime */
847 rem_lifetime =
848 isis_jitter(area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER);
849
850 /* No jitter if the max refresh will be less than configure gen interval
851 */
852 /* N.B. this calucation is acceptable since rem_lifetime is in
853 * [332,65535] at
854 * this point */
855 if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
856 rem_lifetime = area->max_lsp_lifetime[level - 1];
857
858 return rem_lifetime;
859 }
860
861 static uint16_t lsp_refresh_time(struct isis_lsp *lsp, uint16_t rem_lifetime)
862 {
863 struct isis_area *area = lsp->area;
864 int level = lsp->level;
865 uint16_t refresh_time;
866
867 /* Add jitter to LSP refresh time */
868 refresh_time =
869 isis_jitter(area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER);
870
871 /* RFC 4444 : make sure the refresh time is at least less than 300
872 * of the remaining lifetime and more than gen interval */
873 if (refresh_time <= area->lsp_gen_interval[level - 1]
874 || refresh_time > (rem_lifetime - 300))
875 refresh_time = rem_lifetime - 300;
876
877 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
878 * we accept this violation to satisfy refresh_time <= rem_lifetime -
879 * 300 */
880
881 return refresh_time;
882 }
883
884 static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
885 struct isis_area *area)
886 {
887 struct route_table *er_table = get_ext_reach(area, AF_INET, lsp->level);
888 if (!er_table)
889 return;
890
891 for (struct route_node *rn = route_top(er_table); rn;
892 rn = route_next(rn)) {
893 if (!rn->info)
894 continue;
895
896 struct prefix_ipv4 *ipv4 = (struct prefix_ipv4 *)&rn->p;
897 struct isis_ext_info *info = rn->info;
898
899 uint32_t metric = info->metric;
900 if (metric > MAX_WIDE_PATH_METRIC)
901 metric = MAX_WIDE_PATH_METRIC;
902 if (area->oldmetric && metric > 0x3f)
903 metric = 0x3f;
904
905 if (area->oldmetric)
906 isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4,
907 metric);
908 if (area->newmetric) {
909 struct sr_prefix_cfg *pcfg = NULL;
910
911 if (area->srdb.enabled)
912 pcfg = isis_sr_cfg_prefix_find(area, ipv4);
913
914 isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric,
915 true, pcfg);
916 }
917 }
918 }
919
920 static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
921 struct isis_area *area)
922 {
923 struct route_table *er_table =
924 get_ext_reach(area, AF_INET6, lsp->level);
925 if (!er_table)
926 return;
927
928 for (struct route_node *rn = route_top(er_table); rn;
929 rn = srcdest_route_next(rn)) {
930 if (!rn->info)
931 continue;
932 struct isis_ext_info *info = rn->info;
933 struct prefix_ipv6 *p, *src_p;
934
935 srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
936 (const struct prefix **)&src_p);
937
938 uint32_t metric = info->metric;
939 if (info->metric > MAX_WIDE_PATH_METRIC)
940 metric = MAX_WIDE_PATH_METRIC;
941
942 if (!src_p || !src_p->prefixlen) {
943 struct sr_prefix_cfg *pcfg = NULL;
944
945 if (area->srdb.enabled)
946 pcfg = isis_sr_cfg_prefix_find(area, p);
947
948 isis_tlvs_add_ipv6_reach(lsp->tlvs,
949 isis_area_ipv6_topology(area),
950 p, metric, true, pcfg);
951 } else if (isis_area_ipv6_dstsrc_enabled(area)) {
952 isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs,
953 ISIS_MT_IPV6_DSTSRC,
954 p, src_p, metric);
955 }
956 }
957 }
958
959 static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area)
960 {
961 lsp_build_ext_reach_ipv4(lsp, area);
962 lsp_build_ext_reach_ipv6(lsp, area);
963 }
964
965 static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
966 struct isis_area *area, int level)
967 {
968 struct isis_lsp *lsp;
969 uint8_t frag_id[ISIS_SYS_ID_LEN + 2];
970
971 memcpy(frag_id, lsp0->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
972 LSP_FRAGMENT(frag_id) = frag_num;
973
974 lsp = lsp_search(&area->lspdb[level - 1], frag_id);
975 if (lsp) {
976 lsp_clear_data(lsp);
977 if (!lsp->lspu.zero_lsp)
978 lsp_link_fragment(lsp, lsp0);
979 return lsp;
980 }
981
982 lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0,
983 lsp_bits_generate(level, area->overload_bit,
984 area->attached_bit_send, area),
985 0, lsp0, level);
986 lsp->own_lsp = 1;
987 lsp_insert(&area->lspdb[level - 1], lsp);
988 return lsp;
989 }
990
991 /*
992 * Builds the LSP data part. This func creates a new frag whenever
993 * area->lsp_frag_threshold is exceeded.
994 */
995 static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
996 {
997 int level = lsp->level;
998 struct listnode *node;
999 struct isis_lsp *frag;
1000
1001 lsp_clear_data(lsp);
1002 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
1003 lsp_clear_data(frag);
1004
1005 lsp->tlvs = isis_alloc_tlvs();
1006 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1007 area->area_tag, level);
1008
1009 lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
1010 area->attached_bit_send, area);
1011
1012 lsp_add_auth(lsp);
1013
1014 isis_tlvs_add_area_addresses(lsp->tlvs, area->area_addrs);
1015
1016 /* Protocols Supported */
1017 if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
1018 struct nlpids nlpids = {.count = 0};
1019
1020 if (area->ip_circuits > 0) {
1021 lsp_debug(
1022 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1023 area->area_tag);
1024 nlpids.nlpids[nlpids.count] = NLPID_IP;
1025 nlpids.count++;
1026 }
1027 if (area->ipv6_circuits > 0) {
1028 lsp_debug(
1029 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1030 area->area_tag);
1031 nlpids.nlpids[nlpids.count] = NLPID_IPV6;
1032 nlpids.count++;
1033 }
1034 isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
1035 }
1036
1037 if (area_is_mt(area)) {
1038 lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
1039
1040 struct isis_area_mt_setting **mt_settings;
1041 unsigned int mt_count;
1042
1043 mt_settings = area_mt_settings(area, &mt_count);
1044 for (unsigned int i = 0; i < mt_count; i++) {
1045 isis_tlvs_add_mt_router_info(
1046 lsp->tlvs, mt_settings[i]->mtid,
1047 mt_settings[i]->overload, false);
1048 lsp_debug("ISIS (%s): MT %s", area->area_tag,
1049 isis_mtid2str(mt_settings[i]->mtid));
1050 }
1051 } else {
1052 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
1053 area->area_tag);
1054 }
1055 /* Dynamic Hostname */
1056 if (area->dynhostname) {
1057 isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
1058 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
1059 area->area_tag, cmd_hostname_get());
1060 } else {
1061 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1062 area->area_tag);
1063 }
1064
1065 /* Add Router Capability TLV. */
1066 if (area->isis->router_id != 0) {
1067 struct isis_router_cap cap = {};
1068
1069 cap.router_id.s_addr = area->isis->router_id;
1070
1071 /* Add SR Sub-TLVs if SR is enabled. */
1072 if (area->srdb.enabled) {
1073 struct isis_sr_db *srdb = &area->srdb;
1074 uint32_t range_size;
1075
1076 /* SRGB first */
1077 range_size = srdb->config.srgb_upper_bound
1078 - srdb->config.srgb_lower_bound + 1;
1079 cap.srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I
1080 | ISIS_SUBTLV_SRGB_FLAG_V;
1081 cap.srgb.range_size = range_size;
1082 cap.srgb.lower_bound = srdb->config.srgb_lower_bound;
1083 /* Then Algorithm */
1084 cap.algo[0] = SR_ALGORITHM_SPF;
1085 cap.algo[1] = SR_ALGORITHM_UNSET;
1086 /* SRLB */
1087 cap.srlb.flags = 0;
1088 range_size = srdb->config.srlb_upper_bound
1089 - srdb->config.srlb_lower_bound + 1;
1090 cap.srlb.range_size = range_size;
1091 cap.srlb.lower_bound = srdb->config.srlb_lower_bound;
1092 /* And finally MSD */
1093 cap.msd = srdb->config.msd;
1094 } else {
1095 /* Disable SR Algorithm */
1096 cap.algo[0] = SR_ALGORITHM_UNSET;
1097 cap.algo[1] = SR_ALGORITHM_UNSET;
1098 }
1099
1100 isis_tlvs_set_router_capability(lsp->tlvs, &cap);
1101 lsp_debug("ISIS (%s): Adding Router Capabilities information",
1102 area->area_tag);
1103 }
1104
1105 /* IPv4 address and TE router ID TLVs.
1106 * In case of the first one we don't follow "C" vendor,
1107 * but "J" vendor behavior - one IPv4 address is put
1108 * into LSP. TE router ID will be the same if MPLS-TE
1109 * is not activate or MPLS-TE router-id not specified
1110 */
1111 if (area->isis->router_id != 0) {
1112 struct in_addr id = {.s_addr = area->isis->router_id};
1113 lsp_debug("ISIS (%s): Adding router ID %pI4 as IPv4 tlv.",
1114 area->area_tag, &id);
1115 isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
1116
1117 /* If new style TLV's are in use, add TE router ID TLV
1118 * Check if MPLS-TE is activate and mpls-te router-id set
1119 * otherwise add exactly same data as for IPv4 address
1120 */
1121 if (area->newmetric) {
1122 if (IS_MPLS_TE(area->mta)
1123 && area->mta->router_id.s_addr != INADDR_ANY)
1124 id.s_addr = area->mta->router_id.s_addr;
1125 lsp_debug(
1126 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1127 area->area_tag);
1128 isis_tlvs_set_te_router_id(lsp->tlvs, &id);
1129 }
1130 } else {
1131 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1132 area->area_tag);
1133 }
1134
1135 if (IS_MPLS_TE(area->mta)
1136 && !IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) {
1137 lsp_debug("ISIS (%s): Adding IPv6 TE Router ID tlv.",
1138 area->area_tag);
1139 isis_tlvs_set_te_router_id_ipv6(lsp->tlvs,
1140 &area->mta->router_id_ipv6);
1141 }
1142
1143 lsp_debug("ISIS (%s): Adding circuit specific information.",
1144 area->area_tag);
1145
1146 if (fabricd) {
1147 lsp_debug(
1148 "ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
1149 area->area_tag, fabricd_tier(area));
1150 isis_tlvs_add_spine_leaf(lsp->tlvs, fabricd_tier(area), true,
1151 false, false, false);
1152 }
1153
1154 struct isis_circuit *circuit;
1155 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
1156 if (!circuit->interface)
1157 lsp_debug(
1158 "ISIS (%s): Processing %s circuit %p with unknown interface",
1159 area->area_tag,
1160 circuit_type2string(circuit->circ_type),
1161 circuit);
1162 else
1163 lsp_debug("ISIS (%s): Processing %s circuit %s",
1164 area->area_tag,
1165 circuit_type2string(circuit->circ_type),
1166 circuit->interface->name);
1167
1168 if (circuit->state != C_STATE_UP) {
1169 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1170 area->area_tag);
1171 continue;
1172 }
1173
1174 uint32_t metric = area->oldmetric
1175 ? circuit->metric[level - 1]
1176 : circuit->te_metric[level - 1];
1177
1178 if (circuit->ip_router && circuit->ip_addrs->count > 0) {
1179 lsp_debug(
1180 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1181 area->area_tag);
1182 struct listnode *ipnode;
1183 struct prefix_ipv4 *ipv4;
1184 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
1185 ipv4)) {
1186 if (area->oldmetric) {
1187 lsp_debug(
1188 "ISIS (%s): Adding old-style IP reachability for %pFX",
1189 area->area_tag, ipv4);
1190 isis_tlvs_add_oldstyle_ip_reach(
1191 lsp->tlvs, ipv4, metric);
1192 }
1193
1194 if (area->newmetric) {
1195 struct sr_prefix_cfg *pcfg = NULL;
1196
1197 lsp_debug(
1198 "ISIS (%s): Adding te-style IP reachability for %pFX",
1199 area->area_tag, ipv4);
1200
1201 if (area->srdb.enabled)
1202 pcfg = isis_sr_cfg_prefix_find(
1203 area, ipv4);
1204
1205 isis_tlvs_add_extended_ip_reach(
1206 lsp->tlvs, ipv4, metric, false,
1207 pcfg);
1208 }
1209 }
1210 }
1211
1212 if (circuit->ipv6_router && circuit->ipv6_non_link->count > 0) {
1213 struct listnode *ipnode;
1214 struct prefix_ipv6 *ipv6;
1215
1216 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1217 ipnode, ipv6)) {
1218 struct sr_prefix_cfg *pcfg = NULL;
1219
1220 lsp_debug(
1221 "ISIS (%s): Adding IPv6 reachability for %pFX",
1222 area->area_tag, ipv6);
1223
1224 if (area->srdb.enabled)
1225 pcfg = isis_sr_cfg_prefix_find(area,
1226 ipv6);
1227
1228 isis_tlvs_add_ipv6_reach(
1229 lsp->tlvs,
1230 isis_area_ipv6_topology(area), ipv6,
1231 metric, false, pcfg);
1232 }
1233 }
1234
1235 switch (circuit->circ_type) {
1236 case CIRCUIT_T_BROADCAST:
1237 if (level & circuit->is_type) {
1238 uint8_t *ne_id =
1239 (level == IS_LEVEL_1)
1240 ? circuit->u.bc.l1_desig_is
1241 : circuit->u.bc.l2_desig_is;
1242
1243 if (LSP_PSEUDO_ID(ne_id)) {
1244 if (area->oldmetric) {
1245 lsp_debug(
1246 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1247 area->area_tag,
1248 sysid_print(ne_id),
1249 LSP_PSEUDO_ID(ne_id));
1250 isis_tlvs_add_oldstyle_reach(
1251 lsp->tlvs, ne_id,
1252 metric);
1253 }
1254 if (area->newmetric)
1255 tlvs_add_mt_bcast(
1256 lsp->tlvs, circuit,
1257 level, ne_id, metric);
1258 }
1259 } else {
1260 lsp_debug(
1261 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1262 area->area_tag);
1263 }
1264 break;
1265 case CIRCUIT_T_P2P: {
1266 struct isis_adjacency *nei = circuit->u.p2p.neighbor;
1267 if (nei && nei->adj_state == ISIS_ADJ_UP
1268 && (level & nei->circuit_t)) {
1269 uint8_t ne_id[7];
1270 memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
1271 LSP_PSEUDO_ID(ne_id) = 0;
1272
1273 if (area->oldmetric) {
1274 lsp_debug(
1275 "ISIS (%s): Adding old-style is reach for %s",
1276 area->area_tag,
1277 sysid_print(ne_id));
1278 isis_tlvs_add_oldstyle_reach(
1279 lsp->tlvs, ne_id, metric);
1280 }
1281 if (area->newmetric) {
1282 uint32_t neighbor_metric;
1283 if (fabricd_tier(area) == 0) {
1284 neighbor_metric = 0xffe;
1285 } else {
1286 neighbor_metric = metric;
1287 }
1288
1289 tlvs_add_mt_p2p(lsp->tlvs, circuit,
1290 ne_id, neighbor_metric);
1291 }
1292 } else {
1293 lsp_debug(
1294 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1295 area->area_tag);
1296 }
1297 } break;
1298 case CIRCUIT_T_LOOPBACK:
1299 break;
1300 default:
1301 zlog_warn("lsp_area_create: unknown circuit type");
1302 }
1303 }
1304
1305 lsp_build_ext_reach(lsp, area);
1306
1307 struct isis_tlvs *tlvs = lsp->tlvs;
1308 lsp->tlvs = NULL;
1309
1310 lsp_adjust_stream(lsp);
1311 lsp_pack_pdu(lsp);
1312 size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
1313 lsp_clear_data(lsp);
1314
1315 struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
1316 if (!fragments) {
1317 zlog_warn("BUG: could not fragment own LSP:");
1318 log_multiline(LOG_WARNING, " ", "%s",
1319 isis_format_tlvs(tlvs, NULL));
1320 isis_free_tlvs(tlvs);
1321 return;
1322 }
1323 isis_free_tlvs(tlvs);
1324
1325 bool fragment_overflow = false;
1326 frag = lsp;
1327 for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
1328 if (node != listhead(fragments)) {
1329 if (LSP_FRAGMENT(frag->hdr.lsp_id) == 255) {
1330 if (!fragment_overflow) {
1331 fragment_overflow = true;
1332 zlog_warn(
1333 "ISIS (%s): Too much information for 256 fragments",
1334 area->area_tag);
1335 }
1336 isis_free_tlvs(tlvs);
1337 continue;
1338 }
1339
1340 frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
1341 lsp, area, level);
1342 lsp_adjust_stream(frag);
1343 }
1344 frag->tlvs = tlvs;
1345 }
1346
1347 list_delete(&fragments);
1348 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1349 area->area_tag);
1350 return;
1351 }
1352
1353 /*
1354 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1355 */
1356 int lsp_generate(struct isis_area *area, int level)
1357 {
1358 struct isis_lsp *oldlsp, *newlsp;
1359 uint32_t seq_num = 0;
1360 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1361 uint16_t rem_lifetime, refresh_time;
1362 uint32_t overload_time;
1363
1364 if ((area == NULL) || (area->is_type & level) != level)
1365 return ISIS_ERROR;
1366
1367 /* Check if config is still being processed */
1368 if (thread_is_scheduled(t_isis_cfg))
1369 return ISIS_OK;
1370
1371 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
1372
1373 memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
1374
1375 /* Check if device should be overloaded on startup */
1376 if (device_startup) {
1377 overload_time = isis_restart_read_overload_time(area);
1378 if (overload_time > 0) {
1379 isis_area_overload_bit_set(area, true);
1380 thread_add_timer(master, set_overload_on_start_timer,
1381 area, overload_time,
1382 &area->t_overload_on_startup_timer);
1383 }
1384 device_startup = false;
1385 }
1386
1387 /* only builds the lsp if the area shares the level */
1388 oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
1389 if (oldlsp) {
1390 /* FIXME: we should actually initiate a purge */
1391 seq_num = oldlsp->hdr.seqno;
1392 lsp_search_and_destroy(&area->lspdb[level - 1],
1393 oldlsp->hdr.lsp_id);
1394 }
1395 rem_lifetime = lsp_rem_lifetime(area, level);
1396 newlsp = lsp_new(area, lspid, rem_lifetime, seq_num,
1397 lsp_bits_generate(area->is_type, area->overload_bit,
1398 area->attached_bit_send, area),
1399 0, NULL, level);
1400 newlsp->area = area;
1401 newlsp->own_lsp = 1;
1402
1403 lsp_insert(&area->lspdb[level - 1], newlsp);
1404 /* build_lsp_data (newlsp, area); */
1405 lsp_build(newlsp, area);
1406 /* time to calculate our checksum */
1407 lsp_seqno_update(newlsp);
1408 newlsp->last_generated = time(NULL);
1409 lsp_flood(newlsp, NULL);
1410 area->lsp_gen_count[level - 1]++;
1411
1412 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
1413
1414 THREAD_OFF(area->t_lsp_refresh[level - 1]);
1415 area->lsp_regenerate_pending[level - 1] = 0;
1416 thread_add_timer(master, lsp_refresh,
1417 &area->lsp_refresh_arg[level - 1], refresh_time,
1418 &area->t_lsp_refresh[level - 1]);
1419
1420 if (IS_DEBUG_UPDATE_PACKETS) {
1421 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1422 area->area_tag, level,
1423 rawlspid_print(newlsp->hdr.lsp_id),
1424 newlsp->hdr.pdu_len, newlsp->hdr.seqno,
1425 newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
1426 refresh_time);
1427 }
1428 sched_debug(
1429 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1430 area->area_tag, level);
1431
1432 #ifndef FABRICD
1433 /* send northbound notification */
1434 isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno,
1435 newlsp->last_generated);
1436 #endif /* ifndef FABRICD */
1437
1438 return ISIS_OK;
1439 }
1440
1441 /*
1442 * Search own LSPs, update holding time and flood
1443 */
1444 static int lsp_regenerate(struct isis_area *area, int level)
1445 {
1446 struct lspdb_head *head;
1447 struct isis_lsp *lsp, *frag;
1448 struct listnode *node;
1449 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1450 uint16_t rem_lifetime, refresh_time;
1451
1452 if ((area == NULL) || (area->is_type & level) != level)
1453 return ISIS_ERROR;
1454
1455 head = &area->lspdb[level - 1];
1456 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
1457 memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
1458
1459 lsp = lsp_search(head, lspid);
1460
1461 if (!lsp) {
1462 flog_err(EC_LIB_DEVELOPMENT,
1463 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1464 area->area_tag, level);
1465 return ISIS_ERROR;
1466 }
1467
1468 lsp_clear_data(lsp);
1469 lsp_build(lsp, area);
1470 rem_lifetime = lsp_rem_lifetime(area, level);
1471 lsp->hdr.rem_lifetime = rem_lifetime;
1472 lsp->last_generated = time(NULL);
1473 lsp_flood(lsp, NULL);
1474 area->lsp_gen_count[level - 1]++;
1475 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
1476 if (!frag->tlvs) {
1477 /* Updating and flooding should only affect fragments
1478 * carrying data
1479 */
1480 continue;
1481 }
1482
1483 frag->hdr.lsp_bits =
1484 lsp_bits_generate(level, area->overload_bit,
1485 area->attached_bit_send, area);
1486 /* Set the lifetime values of all the fragments to the same
1487 * value,
1488 * so that no fragment expires before the lsp is refreshed.
1489 */
1490 frag->hdr.rem_lifetime = rem_lifetime;
1491 frag->age_out = ZERO_AGE_LIFETIME;
1492 lsp_flood(frag, NULL);
1493 }
1494 lsp_seqno_update(lsp);
1495
1496 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1497 thread_add_timer(master, lsp_refresh,
1498 &area->lsp_refresh_arg[level - 1], refresh_time,
1499 &area->t_lsp_refresh[level - 1]);
1500 area->lsp_regenerate_pending[level - 1] = 0;
1501
1502 if (IS_DEBUG_UPDATE_PACKETS) {
1503 zlog_debug(
1504 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1505 area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
1506 lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
1507 lsp->hdr.rem_lifetime, refresh_time);
1508 }
1509 sched_debug(
1510 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1511 area->area_tag, level);
1512
1513 return ISIS_OK;
1514 }
1515
1516 /*
1517 * Something has changed or periodic refresh -> regenerate LSP
1518 */
1519 static void lsp_refresh(struct thread *thread)
1520 {
1521 struct lsp_refresh_arg *arg = THREAD_ARG(thread);
1522
1523 assert(arg);
1524
1525 struct isis_area *area = arg->area;
1526
1527 assert(area);
1528
1529 int level = arg->level;
1530
1531 area->t_lsp_refresh[level - 1] = NULL;
1532 area->lsp_regenerate_pending[level - 1] = 0;
1533
1534 if ((area->is_type & level) == 0)
1535 return;
1536
1537 /*
1538 * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
1539 * message)
1540 */
1541 if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL)
1542 < 100000L
1543 && !(area->bfd_force_spf_refresh)) {
1544 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1545 area->area_tag, level);
1546 _lsp_regenerate_schedule(area, level, 0, false,
1547 __func__, __FILE__, __LINE__);
1548 return;
1549 }
1550
1551 sched_debug(
1552 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1553 area->area_tag, level);
1554 lsp_regenerate(area, level);
1555 }
1556
1557 int _lsp_regenerate_schedule(struct isis_area *area, int level,
1558 int all_pseudo, bool postpone,
1559 const char *func, const char *file,
1560 int line)
1561 {
1562 struct isis_lsp *lsp;
1563 uint8_t id[ISIS_SYS_ID_LEN + 2];
1564 time_t now, diff;
1565 long timeout;
1566 struct listnode *cnode;
1567 struct isis_circuit *circuit;
1568 int lvl;
1569
1570 if (area == NULL)
1571 return ISIS_ERROR;
1572
1573 sched_debug(
1574 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
1575 area->area_tag, circuit_t2string(level),
1576 all_pseudo ? "" : "not ",
1577 func, file, line);
1578
1579 memcpy(id, area->isis->sysid, ISIS_SYS_ID_LEN);
1580 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
1581 now = time(NULL);
1582
1583 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1584 if (!((level & lvl) && (area->is_type & lvl)))
1585 continue;
1586
1587 if (postpone) {
1588 monotime(&area->last_lsp_refresh_event[lvl - 1]);
1589 }
1590
1591 sched_debug(
1592 "ISIS (%s): Checking whether L%d needs to be scheduled",
1593 area->area_tag, lvl);
1594
1595 if (area->lsp_regenerate_pending[lvl - 1]
1596 && !(area->bfd_signalled_down)) {
1597 /*
1598 * Note: in case of a BFD 'down' message the refresh is
1599 * scheduled once again just to be sure
1600 */
1601 struct timeval remain = thread_timer_remain(
1602 area->t_lsp_refresh[lvl - 1]);
1603 sched_debug(
1604 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1605 area->area_tag, (long long)remain.tv_sec,
1606 (long long)remain.tv_usec / 1000);
1607 continue;
1608 }
1609
1610 lsp = lsp_search(&area->lspdb[lvl - 1], id);
1611 if (!lsp) {
1612 sched_debug(
1613 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1614 area->area_tag);
1615 continue;
1616 }
1617
1618 /*
1619 * Throttle avoidance
1620 */
1621 sched_debug(
1622 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1623 area->area_tag, (long long)lsp->last_generated,
1624 (long long)now);
1625 THREAD_OFF(area->t_lsp_refresh[lvl - 1]);
1626 diff = now - lsp->last_generated;
1627 if (diff < area->lsp_gen_interval[lvl - 1]
1628 && !(area->bfd_signalled_down)) {
1629 timeout =
1630 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
1631 sched_debug(
1632 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1633 area->area_tag, timeout);
1634 } else {
1635 /*
1636 * Schedule LSP refresh ASAP
1637 */
1638 if (area->bfd_signalled_down) {
1639 sched_debug(
1640 "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
1641 area->area_tag);
1642 area->bfd_signalled_down = false;
1643 area->bfd_force_spf_refresh = true;
1644 timeout = 0;
1645 } else {
1646 int64_t time_since_last = monotime_since(
1647 &area->last_lsp_refresh_event[lvl - 1],
1648 NULL);
1649 timeout = time_since_last < 100000L
1650 ? (100000L - time_since_last)/1000
1651 : 0;
1652 if (timeout > 0)
1653 sched_debug(
1654 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
1655 area->area_tag, timeout);
1656 else
1657 sched_debug(
1658 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
1659 area->area_tag);
1660 }
1661 }
1662
1663 area->lsp_regenerate_pending[lvl - 1] = 1;
1664 thread_add_timer_msec(master, lsp_refresh,
1665 &area->lsp_refresh_arg[lvl - 1],
1666 timeout,
1667 &area->t_lsp_refresh[lvl - 1]);
1668 }
1669
1670 if (all_pseudo) {
1671 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
1672 lsp_regenerate_schedule_pseudo(circuit, level);
1673 }
1674
1675 return ISIS_OK;
1676 }
1677
1678 /*
1679 * Funcs for pseudonode LSPs
1680 */
1681
1682 /*
1683 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1684 */
1685 static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
1686 int level)
1687 {
1688 struct isis_adjacency *adj;
1689 struct list *adj_list;
1690 struct listnode *node;
1691 struct isis_area *area = circuit->area;
1692 uint16_t mtid;
1693
1694 lsp_clear_data(lsp);
1695 lsp->tlvs = isis_alloc_tlvs();
1696 lsp_debug(
1697 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1698 area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
1699 circuit->interface->name, level);
1700
1701 lsp->level = level;
1702 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1703 lsp->hdr.lsp_bits = lsp_bits_generate(
1704 level, 0, circuit->area->attached_bit_send, area);
1705
1706 /*
1707 * add self to IS neighbours
1708 */
1709 uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
1710
1711 memcpy(ne_id, area->isis->sysid, ISIS_SYS_ID_LEN);
1712 LSP_PSEUDO_ID(ne_id) = 0;
1713
1714 if (circuit->area->oldmetric) {
1715 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1716 lsp_debug(
1717 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1718 area->area_tag, sysid_print(ne_id),
1719 LSP_PSEUDO_ID(ne_id));
1720 }
1721 if (circuit->area->newmetric) {
1722 if (area_is_mt(circuit->area))
1723 mtid = ISIS_MT_IPV4_UNICAST;
1724 else
1725 mtid = ISIS_MT_DISABLE;
1726 isis_tlvs_add_extended_reach(lsp->tlvs, mtid, ne_id, 0, NULL);
1727 lsp_debug(
1728 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1729 area->area_tag, sysid_print(ne_id),
1730 LSP_PSEUDO_ID(ne_id));
1731 }
1732
1733 adj_list = list_new();
1734 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
1735
1736 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
1737 if (!(adj->level & level)) {
1738 lsp_debug(
1739 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1740 area->area_tag, sysid_print(adj->sysid));
1741 continue;
1742 }
1743
1744 if (!(level == IS_LEVEL_1
1745 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
1746 && !(level == IS_LEVEL_1
1747 && adj->sys_type == ISIS_SYSTYPE_L2_IS
1748 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
1749 && !(level == IS_LEVEL_2
1750 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
1751 lsp_debug(
1752 "ISIS (%s): Ignoring neighbor %s, level does not match",
1753 area->area_tag, sysid_print(adj->sysid));
1754 continue;
1755 }
1756
1757 memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
1758 if (circuit->area->oldmetric) {
1759 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1760 lsp_debug(
1761 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1762 area->area_tag, sysid_print(ne_id),
1763 LSP_PSEUDO_ID(ne_id));
1764 }
1765 if (circuit->area->newmetric) {
1766 isis_tlvs_add_extended_reach(lsp->tlvs,
1767 ISIS_MT_IPV4_UNICAST,
1768 ne_id, 0, NULL);
1769 lsp_debug(
1770 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1771 area->area_tag, sysid_print(ne_id),
1772 LSP_PSEUDO_ID(ne_id));
1773 }
1774 }
1775 list_delete(&adj_list);
1776 return;
1777 }
1778
1779 int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
1780 {
1781 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1782 struct isis_lsp *lsp;
1783 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1784 uint16_t rem_lifetime, refresh_time;
1785
1786 if ((circuit->is_type & level) != level
1787 || (circuit->state != C_STATE_UP)
1788 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1789 || (circuit->u.bc.is_dr[level - 1] == 0))
1790 return ISIS_ERROR;
1791
1792 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1793 LSP_FRAGMENT(lsp_id) = 0;
1794 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1795
1796 /*
1797 * If for some reason have a pseudo LSP in the db already -> regenerate
1798 */
1799 if (lsp_search(head, lsp_id))
1800 return lsp_regenerate_schedule_pseudo(circuit, level);
1801
1802 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1803 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1804 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
1805 lsp_bits_generate(circuit->area->is_type, 0,
1806 circuit->area->attached_bit_send,
1807 circuit->area),
1808 0, NULL, level);
1809 lsp->area = circuit->area;
1810
1811 lsp_build_pseudo(lsp, circuit, level);
1812 lsp_pack_pdu(lsp);
1813 lsp->own_lsp = 1;
1814 lsp_insert(head, lsp);
1815 lsp_flood(lsp, NULL);
1816
1817 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1818 THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1819 circuit->lsp_regenerate_pending[level - 1] = 0;
1820 if (level == IS_LEVEL_1)
1821 thread_add_timer(
1822 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1823 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1824 else if (level == IS_LEVEL_2)
1825 thread_add_timer(
1826 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1827 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1828
1829 if (IS_DEBUG_UPDATE_PACKETS) {
1830 zlog_debug(
1831 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1832 circuit->area->area_tag, level,
1833 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1834 lsp->hdr.seqno, lsp->hdr.checksum,
1835 lsp->hdr.rem_lifetime, refresh_time);
1836 }
1837
1838 return ISIS_OK;
1839 }
1840
1841 static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
1842 {
1843 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1844 struct isis_lsp *lsp;
1845 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1846 uint16_t rem_lifetime, refresh_time;
1847
1848 if ((circuit->is_type & level) != level
1849 || (circuit->state != C_STATE_UP)
1850 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1851 || (circuit->u.bc.is_dr[level - 1] == 0))
1852 return ISIS_ERROR;
1853
1854 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1855 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1856 LSP_FRAGMENT(lsp_id) = 0;
1857
1858 lsp = lsp_search(head, lsp_id);
1859
1860 if (!lsp) {
1861 flog_err(EC_LIB_DEVELOPMENT,
1862 "lsp_regenerate_pseudo: no l%d LSP %s found!", level,
1863 rawlspid_print(lsp_id));
1864 return ISIS_ERROR;
1865 }
1866
1867 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1868 lsp->hdr.rem_lifetime = rem_lifetime;
1869 lsp_build_pseudo(lsp, circuit, level);
1870 lsp_inc_seqno(lsp, 0);
1871 lsp->last_generated = time(NULL);
1872 lsp_flood(lsp, NULL);
1873
1874 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1875 if (level == IS_LEVEL_1)
1876 thread_add_timer(
1877 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1878 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1879 else if (level == IS_LEVEL_2)
1880 thread_add_timer(
1881 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1882 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1883
1884 if (IS_DEBUG_UPDATE_PACKETS) {
1885 zlog_debug(
1886 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1887 circuit->area->area_tag, level,
1888 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1889 lsp->hdr.seqno, lsp->hdr.checksum,
1890 lsp->hdr.rem_lifetime, refresh_time);
1891 }
1892
1893 return ISIS_OK;
1894 }
1895
1896 /*
1897 * Something has changed or periodic refresh -> regenerate pseudo LSP
1898 */
1899 static void lsp_l1_refresh_pseudo(struct thread *thread)
1900 {
1901 struct isis_circuit *circuit;
1902 uint8_t id[ISIS_SYS_ID_LEN + 2];
1903
1904 circuit = THREAD_ARG(thread);
1905
1906 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
1907 circuit->lsp_regenerate_pending[0] = 0;
1908
1909 if ((circuit->u.bc.is_dr[0] == 0)
1910 || (circuit->is_type & IS_LEVEL_1) == 0) {
1911 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1912 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1913 LSP_FRAGMENT(id) = 0;
1914 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
1915 return;
1916 }
1917
1918 lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
1919 }
1920
1921 static void lsp_l2_refresh_pseudo(struct thread *thread)
1922 {
1923 struct isis_circuit *circuit;
1924 uint8_t id[ISIS_SYS_ID_LEN + 2];
1925
1926 circuit = THREAD_ARG(thread);
1927
1928 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
1929 circuit->lsp_regenerate_pending[1] = 0;
1930
1931 if ((circuit->u.bc.is_dr[1] == 0)
1932 || (circuit->is_type & IS_LEVEL_2) == 0) {
1933 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1934 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1935 LSP_FRAGMENT(id) = 0;
1936 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
1937 return;
1938 }
1939
1940 lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
1941 }
1942
1943 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
1944 {
1945 struct isis_lsp *lsp;
1946 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1947 time_t now, diff;
1948 long timeout;
1949 int lvl;
1950 struct isis_area *area = circuit->area;
1951
1952 if (circuit->circ_type != CIRCUIT_T_BROADCAST
1953 || circuit->state != C_STATE_UP)
1954 return ISIS_OK;
1955
1956 sched_debug(
1957 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1958 area->area_tag, circuit_t2string(level),
1959 circuit->interface->name);
1960
1961 memcpy(lsp_id, area->isis->sysid, ISIS_SYS_ID_LEN);
1962 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1963 LSP_FRAGMENT(lsp_id) = 0;
1964 now = time(NULL);
1965
1966 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1967 sched_debug(
1968 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1969 area->area_tag, lvl);
1970
1971 if (!((level & lvl) && (circuit->is_type & lvl))) {
1972 sched_debug("ISIS (%s): Level is not active on circuit",
1973 area->area_tag);
1974 continue;
1975 }
1976
1977 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
1978 sched_debug(
1979 "ISIS (%s): This IS is not DR, nothing to do.",
1980 area->area_tag);
1981 continue;
1982 }
1983
1984 if (circuit->lsp_regenerate_pending[lvl - 1]) {
1985 struct timeval remain = thread_timer_remain(
1986 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1987 sched_debug(
1988 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1989 area->area_tag, (long long)remain.tv_sec,
1990 (long long)remain.tv_usec / 1000);
1991 continue;
1992 }
1993
1994 lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
1995 if (!lsp) {
1996 sched_debug(
1997 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1998 area->area_tag);
1999 continue;
2000 }
2001
2002 /*
2003 * Throttle avoidance
2004 */
2005 sched_debug(
2006 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2007 area->area_tag, (long long)lsp->last_generated,
2008 (long long)now);
2009 THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2010 diff = now - lsp->last_generated;
2011 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
2012 timeout =
2013 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
2014 - diff);
2015 sched_debug(
2016 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2017 area->area_tag, timeout);
2018 } else {
2019 timeout = 100;
2020 sched_debug(
2021 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
2022 area->area_tag, timeout);
2023 }
2024
2025 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2026
2027 if (lvl == IS_LEVEL_1) {
2028 thread_add_timer_msec(
2029 master, lsp_l1_refresh_pseudo, circuit, timeout,
2030 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2031 } else if (lvl == IS_LEVEL_2) {
2032 thread_add_timer_msec(
2033 master, lsp_l2_refresh_pseudo, circuit, timeout,
2034 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2035 }
2036 }
2037
2038 return ISIS_OK;
2039 }
2040
2041 /*
2042 * Walk through LSPs for an area
2043 * - set remaining lifetime
2044 */
2045 void lsp_tick(struct thread *thread)
2046 {
2047 struct isis_area *area;
2048 struct isis_lsp *lsp;
2049 int level;
2050 uint16_t rem_lifetime;
2051 bool fabricd_sync_incomplete = false;
2052
2053 area = THREAD_ARG(thread);
2054 assert(area);
2055 area->t_tick = NULL;
2056 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
2057
2058 struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
2059
2060 /*
2061 * Remove LSPs which have aged out
2062 */
2063 for (level = 0; level < ISIS_LEVELS; level++) {
2064 struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
2065 frr_each_from (lspdb, &area->lspdb[level], lsp, next) {
2066 /*
2067 * The lsp rem_lifetime is kept at 0 for MaxAge
2068 * or
2069 * ZeroAgeLifetime depending on explicit purge
2070 * or
2071 * natural age out. So schedule spf only once
2072 * when
2073 * the first time rem_lifetime becomes 0.
2074 */
2075 rem_lifetime = lsp->hdr.rem_lifetime;
2076 lsp_set_time(lsp);
2077
2078 /*
2079 * Schedule may run spf which should be done
2080 * only after
2081 * the lsp rem_lifetime becomes 0 for the first
2082 * time.
2083 * ISO 10589 - 7.3.16.4 first paragraph.
2084 */
2085 if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
2086 /* 7.3.16.4 a) set SRM flags on all */
2087 /* 7.3.16.4 b) retain only the header */
2088 if (lsp->area->purge_originator)
2089 lsp_purge(lsp, lsp->level, NULL);
2090 else
2091 lsp_flood(lsp, NULL);
2092 /* 7.3.16.4 c) record the time to purge
2093 * FIXME */
2094 isis_spf_schedule(lsp->area, lsp->level);
2095 isis_te_lsp_event(lsp, LSP_TICK);
2096 }
2097
2098 if (lsp->age_out == 0) {
2099 zlog_debug(
2100 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2101 area->area_tag, lsp->level,
2102 rawlspid_print(lsp->hdr.lsp_id),
2103 lsp->hdr.seqno);
2104
2105 /* if we're aging out fragment 0, lsp_destroy()
2106 * below will delete all other fragments too,
2107 * so we need to skip over those
2108 */
2109 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2110 while (next &&
2111 !memcmp(next->hdr.lsp_id,
2112 lsp->hdr.lsp_id,
2113 ISIS_SYS_ID_LEN + 1))
2114 next = lspdb_next(
2115 &area->lspdb[level],
2116 next);
2117
2118 lspdb_del(&area->lspdb[level], lsp);
2119 lsp_destroy(lsp);
2120 lsp = NULL;
2121 }
2122
2123 if (fabricd_init_c && lsp) {
2124 fabricd_sync_incomplete |=
2125 ISIS_CHECK_FLAG(lsp->SSNflags,
2126 fabricd_init_c);
2127 }
2128 }
2129 }
2130
2131 if (fabricd_init_c
2132 && !fabricd_sync_incomplete
2133 && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
2134 fabricd_initial_sync_finish(area);
2135 }
2136 }
2137
2138 void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
2139 {
2140 struct isis_lsp *lsp;
2141
2142 lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
2143 if (!lsp)
2144 return;
2145
2146 lsp_purge(lsp, level, NULL);
2147 }
2148
2149 /*
2150 * Purge own LSP that is received and we don't have.
2151 * -> Do as in 7.3.16.4
2152 */
2153 void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
2154 struct isis_area *area)
2155 {
2156 struct isis_lsp *lsp;
2157
2158 /*
2159 * We need to create the LSP to be purged
2160 */
2161 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
2162 lsp->area = area;
2163 lsp->level = level;
2164 lsp_adjust_stream(lsp);
2165 lsp->age_out = ZERO_AGE_LIFETIME;
2166 lsp->area->lsp_purge_count[level - 1]++;
2167
2168 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
2169 lsp->hdr.rem_lifetime = 0;
2170
2171 lsp_purge_add_poi(lsp, NULL);
2172
2173 lsp_pack_pdu(lsp);
2174
2175 lsp_insert(&area->lspdb[lsp->level - 1], lsp);
2176 lsp_flood(lsp, NULL);
2177
2178 return;
2179 }
2180
2181 void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
2182 {
2183 struct listnode *node;
2184 struct isis_circuit *circuit;
2185
2186 assert(lsp);
2187
2188 if (!lsp->area)
2189 return;
2190
2191 struct list *circuit_list = lsp->area->circuit_list;
2192 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
2193 if (set) {
2194 isis_tx_queue_add(circuit->tx_queue, lsp,
2195 TX_LSP_NORMAL);
2196 } else {
2197 isis_tx_queue_del(circuit->tx_queue, lsp);
2198 }
2199 }
2200 }
2201
2202 void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
2203 const char *func, const char *file, int line)
2204 {
2205 if (IS_DEBUG_FLOODING) {
2206 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2207 rawlspid_print(lsp->hdr.lsp_id),
2208 circuit ? " except on " : "",
2209 circuit ? circuit->interface->name : "",
2210 func, file, line);
2211 }
2212
2213 if (!fabricd)
2214 lsp_set_all_srmflags(lsp, true);
2215 else
2216 fabricd_lsp_flood(lsp, circuit);
2217
2218 if (circuit)
2219 isis_tx_queue_del(circuit->tx_queue, lsp);
2220 }
2221
2222 static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
2223 {
2224 lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
2225
2226 /* when an adjacency state changes determine if we need to
2227 * change attach_bits in other area's LSPs
2228 */
2229 isis_reset_attach_bit(adj);
2230
2231 return 0;
2232 }
2233
2234 /*
2235 * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
2236 * address-family and MT-ID.
2237 */
2238 int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
2239 lsp_ip_reach_iter_cb cb, void *arg)
2240 {
2241 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
2242 struct isis_lsp *frag;
2243 struct listnode *node;
2244
2245 if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
2246 return LSP_ITER_CONTINUE;
2247
2248 /* Parse LSP */
2249 if (lsp->tlvs) {
2250 if (!fabricd && !pseudo_lsp && family == AF_INET
2251 && mtid == ISIS_MT_IPV4_UNICAST) {
2252 struct isis_item_list *reachs[] = {
2253 &lsp->tlvs->oldstyle_ip_reach,
2254 &lsp->tlvs->oldstyle_ip_reach_ext};
2255
2256 for (unsigned int i = 0; i < array_size(reachs); i++) {
2257 struct isis_oldstyle_ip_reach *r;
2258
2259 for (r = (struct isis_oldstyle_ip_reach *)
2260 reachs[i]
2261 ->head;
2262 r; r = r->next) {
2263 bool external = i ? true : false;
2264
2265 if ((*cb)((struct prefix *)&r->prefix,
2266 r->metric, external, NULL,
2267 arg)
2268 == LSP_ITER_STOP)
2269 return LSP_ITER_STOP;
2270 }
2271 }
2272 }
2273
2274 if (!pseudo_lsp && family == AF_INET) {
2275 struct isis_item_list *ipv4_reachs;
2276
2277 if (mtid == ISIS_MT_IPV4_UNICAST)
2278 ipv4_reachs = &lsp->tlvs->extended_ip_reach;
2279 else
2280 ipv4_reachs = isis_lookup_mt_items(
2281 &lsp->tlvs->mt_ip_reach, mtid);
2282
2283 struct isis_extended_ip_reach *r;
2284 for (r = ipv4_reachs ? (struct isis_extended_ip_reach *)
2285 ipv4_reachs->head
2286 : NULL;
2287 r; r = r->next) {
2288 if ((*cb)((struct prefix *)&r->prefix,
2289 r->metric, false, r->subtlvs, arg)
2290 == LSP_ITER_STOP)
2291 return LSP_ITER_STOP;
2292 }
2293 }
2294
2295 if (!pseudo_lsp && family == AF_INET6) {
2296 struct isis_item_list *ipv6_reachs;
2297 struct isis_ipv6_reach *r;
2298
2299 if (mtid == ISIS_MT_IPV4_UNICAST)
2300 ipv6_reachs = &lsp->tlvs->ipv6_reach;
2301 else
2302 ipv6_reachs = isis_lookup_mt_items(
2303 &lsp->tlvs->mt_ipv6_reach, mtid);
2304
2305 for (r = ipv6_reachs ? (struct isis_ipv6_reach *)
2306 ipv6_reachs->head
2307 : NULL;
2308 r; r = r->next) {
2309 if ((*cb)((struct prefix *)&r->prefix,
2310 r->metric, r->external, r->subtlvs,
2311 arg)
2312 == LSP_ITER_STOP)
2313 return LSP_ITER_STOP;
2314 }
2315 }
2316 }
2317
2318 /* Parse LSP fragments if it is not a fragment itself */
2319 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2320 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2321 if (!frag->tlvs)
2322 continue;
2323
2324 if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
2325 arg)
2326 == LSP_ITER_STOP)
2327 return LSP_ITER_STOP;
2328 }
2329
2330 return LSP_ITER_CONTINUE;
2331 }
2332
2333 /*
2334 * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
2335 * MT-ID.
2336 */
2337 int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
2338 lsp_is_reach_iter_cb cb, void *arg)
2339 {
2340 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
2341 struct isis_lsp *frag;
2342 struct listnode *node;
2343 struct isis_item *head;
2344 struct isis_item_list *te_neighs;
2345
2346 if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
2347 return LSP_ITER_CONTINUE;
2348
2349 /* Parse LSP */
2350 if (lsp->tlvs) {
2351 if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) {
2352 head = lsp->tlvs->oldstyle_reach.head;
2353 for (struct isis_oldstyle_reach *reach =
2354 (struct isis_oldstyle_reach *)head;
2355 reach; reach = reach->next) {
2356 if ((*cb)(reach->id, reach->metric, true, NULL,
2357 arg)
2358 == LSP_ITER_STOP)
2359 return LSP_ITER_STOP;
2360 }
2361 }
2362
2363 if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST)
2364 te_neighs = &lsp->tlvs->extended_reach;
2365 else
2366 te_neighs =
2367 isis_get_mt_items(&lsp->tlvs->mt_reach, mtid);
2368 if (te_neighs) {
2369 head = te_neighs->head;
2370 for (struct isis_extended_reach *reach =
2371 (struct isis_extended_reach *)head;
2372 reach; reach = reach->next) {
2373 if ((*cb)(reach->id, reach->metric, false,
2374 reach->subtlvs, arg)
2375 == LSP_ITER_STOP)
2376 return LSP_ITER_STOP;
2377 }
2378 }
2379 }
2380
2381 /* Parse LSP fragments if it not a fragment itself. */
2382 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2383 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2384 if (!frag->tlvs)
2385 continue;
2386
2387 if (isis_lsp_iterate_is_reach(frag, mtid, cb, arg)
2388 == LSP_ITER_STOP)
2389 return LSP_ITER_STOP;
2390 }
2391
2392 return LSP_ITER_CONTINUE;
2393 }
2394
2395 void lsp_init(void)
2396 {
2397 device_startup = true;
2398 hook_register(isis_adj_state_change_hook,
2399 lsp_handle_adj_state_change);
2400 }