]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
Merge pull request #13227 from mjstapp/ospf_sock_bufsizes
[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 "frrevent.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 event *thread);
53 static void lsp_l1_refresh_pseudo(struct event *thread);
54 static void lsp_l2_refresh_pseudo(struct event *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 event *thread)
433 {
434 struct isis_area *area = EVENT_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 if (area->advertise_passive_only && !circuit->is_passive) {
1175 lsp_debug(
1176 "ISIS (%s): Circuit is not passive, ignoring.",
1177 area->area_tag);
1178 continue;
1179 }
1180
1181 uint32_t metric = area->oldmetric
1182 ? circuit->metric[level - 1]
1183 : circuit->te_metric[level - 1];
1184
1185 if (circuit->ip_router && circuit->ip_addrs->count > 0) {
1186 lsp_debug(
1187 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1188 area->area_tag);
1189 struct listnode *ipnode;
1190 struct prefix_ipv4 *ipv4;
1191 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
1192 ipv4)) {
1193 if (area->oldmetric) {
1194 lsp_debug(
1195 "ISIS (%s): Adding old-style IP reachability for %pFX",
1196 area->area_tag, ipv4);
1197 isis_tlvs_add_oldstyle_ip_reach(
1198 lsp->tlvs, ipv4, metric);
1199 }
1200
1201 if (area->newmetric) {
1202 struct sr_prefix_cfg *pcfg = NULL;
1203
1204 lsp_debug(
1205 "ISIS (%s): Adding te-style IP reachability for %pFX",
1206 area->area_tag, ipv4);
1207
1208 if (area->srdb.enabled)
1209 pcfg = isis_sr_cfg_prefix_find(
1210 area, ipv4);
1211
1212 isis_tlvs_add_extended_ip_reach(
1213 lsp->tlvs, ipv4, metric, false,
1214 pcfg);
1215 }
1216 }
1217 }
1218
1219 if (circuit->ipv6_router && circuit->ipv6_non_link->count > 0) {
1220 struct listnode *ipnode;
1221 struct prefix_ipv6 *ipv6;
1222
1223 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1224 ipnode, ipv6)) {
1225 struct sr_prefix_cfg *pcfg = NULL;
1226
1227 lsp_debug(
1228 "ISIS (%s): Adding IPv6 reachability for %pFX",
1229 area->area_tag, ipv6);
1230
1231 if (area->srdb.enabled)
1232 pcfg = isis_sr_cfg_prefix_find(area,
1233 ipv6);
1234
1235 isis_tlvs_add_ipv6_reach(
1236 lsp->tlvs,
1237 isis_area_ipv6_topology(area), ipv6,
1238 metric, false, pcfg);
1239 }
1240 }
1241
1242 switch (circuit->circ_type) {
1243 case CIRCUIT_T_BROADCAST:
1244 if (level & circuit->is_type) {
1245 uint8_t *ne_id =
1246 (level == IS_LEVEL_1)
1247 ? circuit->u.bc.l1_desig_is
1248 : circuit->u.bc.l2_desig_is;
1249
1250 if (LSP_PSEUDO_ID(ne_id)) {
1251 if (area->oldmetric) {
1252 lsp_debug(
1253 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1254 area->area_tag,
1255 sysid_print(ne_id),
1256 LSP_PSEUDO_ID(ne_id));
1257 isis_tlvs_add_oldstyle_reach(
1258 lsp->tlvs, ne_id,
1259 metric);
1260 }
1261 if (area->newmetric)
1262 tlvs_add_mt_bcast(
1263 lsp->tlvs, circuit,
1264 level, ne_id, metric);
1265 }
1266 } else {
1267 lsp_debug(
1268 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1269 area->area_tag);
1270 }
1271 break;
1272 case CIRCUIT_T_P2P: {
1273 struct isis_adjacency *nei = circuit->u.p2p.neighbor;
1274 if (nei && nei->adj_state == ISIS_ADJ_UP
1275 && (level & nei->circuit_t)) {
1276 uint8_t ne_id[7];
1277 memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
1278 LSP_PSEUDO_ID(ne_id) = 0;
1279
1280 if (area->oldmetric) {
1281 lsp_debug(
1282 "ISIS (%s): Adding old-style is reach for %s",
1283 area->area_tag,
1284 sysid_print(ne_id));
1285 isis_tlvs_add_oldstyle_reach(
1286 lsp->tlvs, ne_id, metric);
1287 }
1288 if (area->newmetric) {
1289 uint32_t neighbor_metric;
1290 if (fabricd_tier(area) == 0) {
1291 neighbor_metric = 0xffe;
1292 } else {
1293 neighbor_metric = metric;
1294 }
1295
1296 tlvs_add_mt_p2p(lsp->tlvs, circuit,
1297 ne_id, neighbor_metric);
1298 }
1299 } else {
1300 lsp_debug(
1301 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1302 area->area_tag);
1303 }
1304 } break;
1305 case CIRCUIT_T_LOOPBACK:
1306 break;
1307 default:
1308 zlog_warn("lsp_area_create: unknown circuit type");
1309 }
1310 }
1311
1312 lsp_build_ext_reach(lsp, area);
1313
1314 struct isis_tlvs *tlvs = lsp->tlvs;
1315 lsp->tlvs = NULL;
1316
1317 lsp_adjust_stream(lsp);
1318 lsp_pack_pdu(lsp);
1319 size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
1320 lsp_clear_data(lsp);
1321
1322 struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
1323 if (!fragments) {
1324 zlog_warn("BUG: could not fragment own LSP:");
1325 log_multiline(LOG_WARNING, " ", "%s",
1326 isis_format_tlvs(tlvs, NULL));
1327 isis_free_tlvs(tlvs);
1328 return;
1329 }
1330 isis_free_tlvs(tlvs);
1331
1332 bool fragment_overflow = false;
1333 frag = lsp;
1334 for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
1335 if (node != listhead(fragments)) {
1336 if (LSP_FRAGMENT(frag->hdr.lsp_id) == 255) {
1337 if (!fragment_overflow) {
1338 fragment_overflow = true;
1339 zlog_warn(
1340 "ISIS (%s): Too much information for 256 fragments",
1341 area->area_tag);
1342 }
1343 isis_free_tlvs(tlvs);
1344 continue;
1345 }
1346
1347 frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
1348 lsp, area, level);
1349 lsp_adjust_stream(frag);
1350 }
1351 frag->tlvs = tlvs;
1352 }
1353
1354 list_delete(&fragments);
1355 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1356 area->area_tag);
1357 return;
1358 }
1359
1360 /*
1361 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1362 */
1363 int lsp_generate(struct isis_area *area, int level)
1364 {
1365 struct isis_lsp *oldlsp, *newlsp;
1366 uint32_t seq_num = 0;
1367 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1368 uint16_t rem_lifetime, refresh_time;
1369 uint32_t overload_time;
1370
1371 if ((area == NULL) || (area->is_type & level) != level)
1372 return ISIS_ERROR;
1373
1374 /* Check if config is still being processed */
1375 if (event_is_scheduled(t_isis_cfg))
1376 return ISIS_OK;
1377
1378 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
1379
1380 memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
1381
1382 /* Check if device should be overloaded on startup */
1383 if (device_startup) {
1384 overload_time = isis_restart_read_overload_time(area);
1385 if (overload_time > 0) {
1386 isis_area_overload_bit_set(area, true);
1387 event_add_timer(master, set_overload_on_start_timer,
1388 area, overload_time,
1389 &area->t_overload_on_startup_timer);
1390 }
1391 device_startup = false;
1392 }
1393
1394 /* only builds the lsp if the area shares the level */
1395 oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
1396 if (oldlsp) {
1397 /* FIXME: we should actually initiate a purge */
1398 seq_num = oldlsp->hdr.seqno;
1399 lsp_search_and_destroy(&area->lspdb[level - 1],
1400 oldlsp->hdr.lsp_id);
1401 }
1402 rem_lifetime = lsp_rem_lifetime(area, level);
1403 newlsp = lsp_new(area, lspid, rem_lifetime, seq_num,
1404 lsp_bits_generate(area->is_type, area->overload_bit,
1405 area->attached_bit_send, area),
1406 0, NULL, level);
1407 newlsp->area = area;
1408 newlsp->own_lsp = 1;
1409
1410 lsp_insert(&area->lspdb[level - 1], newlsp);
1411 /* build_lsp_data (newlsp, area); */
1412 lsp_build(newlsp, area);
1413 /* time to calculate our checksum */
1414 lsp_seqno_update(newlsp);
1415 newlsp->last_generated = time(NULL);
1416 lsp_flood(newlsp, NULL);
1417 area->lsp_gen_count[level - 1]++;
1418
1419 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
1420
1421 EVENT_OFF(area->t_lsp_refresh[level - 1]);
1422 area->lsp_regenerate_pending[level - 1] = 0;
1423 event_add_timer(master, lsp_refresh, &area->lsp_refresh_arg[level - 1],
1424 refresh_time, &area->t_lsp_refresh[level - 1]);
1425
1426 if (IS_DEBUG_UPDATE_PACKETS) {
1427 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1428 area->area_tag, level,
1429 rawlspid_print(newlsp->hdr.lsp_id),
1430 newlsp->hdr.pdu_len, newlsp->hdr.seqno,
1431 newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
1432 refresh_time);
1433 }
1434 sched_debug(
1435 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1436 area->area_tag, level);
1437
1438 #ifndef FABRICD
1439 /* send northbound notification */
1440 isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno,
1441 newlsp->last_generated);
1442 #endif /* ifndef FABRICD */
1443
1444 return ISIS_OK;
1445 }
1446
1447 /*
1448 * Search own LSPs, update holding time and flood
1449 */
1450 static int lsp_regenerate(struct isis_area *area, int level)
1451 {
1452 struct lspdb_head *head;
1453 struct isis_lsp *lsp, *frag;
1454 struct listnode *node;
1455 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1456 uint16_t rem_lifetime, refresh_time;
1457
1458 if ((area == NULL) || (area->is_type & level) != level)
1459 return ISIS_ERROR;
1460
1461 head = &area->lspdb[level - 1];
1462 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
1463 memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
1464
1465 lsp = lsp_search(head, lspid);
1466
1467 if (!lsp) {
1468 flog_err(EC_LIB_DEVELOPMENT,
1469 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1470 area->area_tag, level);
1471 return ISIS_ERROR;
1472 }
1473
1474 lsp_clear_data(lsp);
1475 lsp_build(lsp, area);
1476 rem_lifetime = lsp_rem_lifetime(area, level);
1477 lsp->hdr.rem_lifetime = rem_lifetime;
1478 lsp->last_generated = time(NULL);
1479 lsp_flood(lsp, NULL);
1480 area->lsp_gen_count[level - 1]++;
1481 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
1482 if (!frag->tlvs) {
1483 /* Updating and flooding should only affect fragments
1484 * carrying data
1485 */
1486 continue;
1487 }
1488
1489 frag->hdr.lsp_bits =
1490 lsp_bits_generate(level, area->overload_bit,
1491 area->attached_bit_send, area);
1492 /* Set the lifetime values of all the fragments to the same
1493 * value,
1494 * so that no fragment expires before the lsp is refreshed.
1495 */
1496 frag->hdr.rem_lifetime = rem_lifetime;
1497 frag->age_out = ZERO_AGE_LIFETIME;
1498 lsp_flood(frag, NULL);
1499 }
1500 lsp_seqno_update(lsp);
1501
1502 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1503 event_add_timer(master, lsp_refresh, &area->lsp_refresh_arg[level - 1],
1504 refresh_time, &area->t_lsp_refresh[level - 1]);
1505 area->lsp_regenerate_pending[level - 1] = 0;
1506
1507 if (IS_DEBUG_UPDATE_PACKETS) {
1508 zlog_debug(
1509 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1510 area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
1511 lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
1512 lsp->hdr.rem_lifetime, refresh_time);
1513 }
1514 sched_debug(
1515 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1516 area->area_tag, level);
1517
1518 return ISIS_OK;
1519 }
1520
1521 /*
1522 * Something has changed or periodic refresh -> regenerate LSP
1523 */
1524 static void lsp_refresh(struct event *thread)
1525 {
1526 struct lsp_refresh_arg *arg = EVENT_ARG(thread);
1527
1528 assert(arg);
1529
1530 struct isis_area *area = arg->area;
1531
1532 assert(area);
1533
1534 int level = arg->level;
1535
1536 area->t_lsp_refresh[level - 1] = NULL;
1537 area->lsp_regenerate_pending[level - 1] = 0;
1538
1539 if ((area->is_type & level) == 0)
1540 return;
1541
1542 /*
1543 * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
1544 * message)
1545 */
1546 if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL)
1547 < 100000L
1548 && !(area->bfd_force_spf_refresh)) {
1549 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1550 area->area_tag, level);
1551 _lsp_regenerate_schedule(area, level, 0, false,
1552 __func__, __FILE__, __LINE__);
1553 return;
1554 }
1555
1556 sched_debug(
1557 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1558 area->area_tag, level);
1559 lsp_regenerate(area, level);
1560 }
1561
1562 int _lsp_regenerate_schedule(struct isis_area *area, int level,
1563 int all_pseudo, bool postpone,
1564 const char *func, const char *file,
1565 int line)
1566 {
1567 struct isis_lsp *lsp;
1568 uint8_t id[ISIS_SYS_ID_LEN + 2];
1569 time_t now, diff;
1570 long timeout;
1571 struct listnode *cnode;
1572 struct isis_circuit *circuit;
1573 int lvl;
1574
1575 if (area == NULL)
1576 return ISIS_ERROR;
1577
1578 sched_debug(
1579 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
1580 area->area_tag, circuit_t2string(level),
1581 all_pseudo ? "" : "not ",
1582 func, file, line);
1583
1584 memcpy(id, area->isis->sysid, ISIS_SYS_ID_LEN);
1585 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
1586 now = time(NULL);
1587
1588 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1589 if (!((level & lvl) && (area->is_type & lvl)))
1590 continue;
1591
1592 if (postpone) {
1593 monotime(&area->last_lsp_refresh_event[lvl - 1]);
1594 }
1595
1596 sched_debug(
1597 "ISIS (%s): Checking whether L%d needs to be scheduled",
1598 area->area_tag, lvl);
1599
1600 if (area->lsp_regenerate_pending[lvl - 1]
1601 && !(area->bfd_signalled_down)) {
1602 /*
1603 * Note: in case of a BFD 'down' message the refresh is
1604 * scheduled once again just to be sure
1605 */
1606 struct timeval remain = event_timer_remain(
1607 area->t_lsp_refresh[lvl - 1]);
1608 sched_debug(
1609 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1610 area->area_tag, (long long)remain.tv_sec,
1611 (long long)remain.tv_usec / 1000);
1612 continue;
1613 }
1614
1615 lsp = lsp_search(&area->lspdb[lvl - 1], id);
1616 if (!lsp) {
1617 sched_debug(
1618 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1619 area->area_tag);
1620 continue;
1621 }
1622
1623 /*
1624 * Throttle avoidance
1625 */
1626 sched_debug(
1627 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1628 area->area_tag, (long long)lsp->last_generated,
1629 (long long)now);
1630 EVENT_OFF(area->t_lsp_refresh[lvl - 1]);
1631 diff = now - lsp->last_generated;
1632 if (diff < area->lsp_gen_interval[lvl - 1]
1633 && !(area->bfd_signalled_down)) {
1634 timeout =
1635 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
1636 sched_debug(
1637 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1638 area->area_tag, timeout);
1639 } else {
1640 /*
1641 * Schedule LSP refresh ASAP
1642 */
1643 if (area->bfd_signalled_down) {
1644 sched_debug(
1645 "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
1646 area->area_tag);
1647 area->bfd_signalled_down = false;
1648 area->bfd_force_spf_refresh = true;
1649 timeout = 0;
1650 } else {
1651 int64_t time_since_last = monotime_since(
1652 &area->last_lsp_refresh_event[lvl - 1],
1653 NULL);
1654 timeout = time_since_last < 100000L
1655 ? (100000L - time_since_last)/1000
1656 : 0;
1657 if (timeout > 0)
1658 sched_debug(
1659 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
1660 area->area_tag, timeout);
1661 else
1662 sched_debug(
1663 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
1664 area->area_tag);
1665 }
1666 }
1667
1668 area->lsp_regenerate_pending[lvl - 1] = 1;
1669 event_add_timer_msec(master, lsp_refresh,
1670 &area->lsp_refresh_arg[lvl - 1], timeout,
1671 &area->t_lsp_refresh[lvl - 1]);
1672 }
1673
1674 if (all_pseudo) {
1675 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
1676 lsp_regenerate_schedule_pseudo(circuit, level);
1677 }
1678
1679 return ISIS_OK;
1680 }
1681
1682 /*
1683 * Funcs for pseudonode LSPs
1684 */
1685
1686 /*
1687 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1688 */
1689 static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
1690 int level)
1691 {
1692 struct isis_adjacency *adj;
1693 struct list *adj_list;
1694 struct listnode *node;
1695 struct isis_area *area = circuit->area;
1696 uint16_t mtid;
1697
1698 lsp_clear_data(lsp);
1699 lsp->tlvs = isis_alloc_tlvs();
1700 lsp_debug(
1701 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1702 area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
1703 circuit->interface->name, level);
1704
1705 lsp->level = level;
1706 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1707 lsp->hdr.lsp_bits = lsp_bits_generate(
1708 level, 0, circuit->area->attached_bit_send, area);
1709
1710 /*
1711 * add self to IS neighbours
1712 */
1713 uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
1714
1715 memcpy(ne_id, area->isis->sysid, ISIS_SYS_ID_LEN);
1716 LSP_PSEUDO_ID(ne_id) = 0;
1717
1718 if (circuit->area->oldmetric) {
1719 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1720 lsp_debug(
1721 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1722 area->area_tag, sysid_print(ne_id),
1723 LSP_PSEUDO_ID(ne_id));
1724 }
1725 if (circuit->area->newmetric) {
1726 if (area_is_mt(circuit->area))
1727 mtid = ISIS_MT_IPV4_UNICAST;
1728 else
1729 mtid = ISIS_MT_DISABLE;
1730 isis_tlvs_add_extended_reach(lsp->tlvs, mtid, ne_id, 0, NULL);
1731 lsp_debug(
1732 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1733 area->area_tag, sysid_print(ne_id),
1734 LSP_PSEUDO_ID(ne_id));
1735 }
1736
1737 adj_list = list_new();
1738 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
1739
1740 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
1741 if (!(adj->level & level)) {
1742 lsp_debug(
1743 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1744 area->area_tag, sysid_print(adj->sysid));
1745 continue;
1746 }
1747
1748 if (!(level == IS_LEVEL_1
1749 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
1750 && !(level == IS_LEVEL_1
1751 && adj->sys_type == ISIS_SYSTYPE_L2_IS
1752 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
1753 && !(level == IS_LEVEL_2
1754 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
1755 lsp_debug(
1756 "ISIS (%s): Ignoring neighbor %s, level does not match",
1757 area->area_tag, sysid_print(adj->sysid));
1758 continue;
1759 }
1760
1761 memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
1762 if (circuit->area->oldmetric) {
1763 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1764 lsp_debug(
1765 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1766 area->area_tag, sysid_print(ne_id),
1767 LSP_PSEUDO_ID(ne_id));
1768 }
1769 if (circuit->area->newmetric) {
1770 isis_tlvs_add_extended_reach(lsp->tlvs,
1771 ISIS_MT_IPV4_UNICAST,
1772 ne_id, 0, NULL);
1773 lsp_debug(
1774 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1775 area->area_tag, sysid_print(ne_id),
1776 LSP_PSEUDO_ID(ne_id));
1777 }
1778 }
1779 list_delete(&adj_list);
1780 return;
1781 }
1782
1783 int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
1784 {
1785 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1786 struct isis_lsp *lsp;
1787 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1788 uint16_t rem_lifetime, refresh_time;
1789
1790 if ((circuit->is_type & level) != level
1791 || (circuit->state != C_STATE_UP)
1792 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1793 || (circuit->u.bc.is_dr[level - 1] == 0))
1794 return ISIS_ERROR;
1795
1796 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1797 LSP_FRAGMENT(lsp_id) = 0;
1798 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1799
1800 /*
1801 * If for some reason have a pseudo LSP in the db already -> regenerate
1802 */
1803 if (lsp_search(head, lsp_id))
1804 return lsp_regenerate_schedule_pseudo(circuit, level);
1805
1806 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1807 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1808 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
1809 lsp_bits_generate(circuit->area->is_type, 0,
1810 circuit->area->attached_bit_send,
1811 circuit->area),
1812 0, NULL, level);
1813 lsp->area = circuit->area;
1814
1815 lsp_build_pseudo(lsp, circuit, level);
1816 lsp_pack_pdu(lsp);
1817 lsp->own_lsp = 1;
1818 lsp_insert(head, lsp);
1819 lsp_flood(lsp, NULL);
1820
1821 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1822 EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1823 circuit->lsp_regenerate_pending[level - 1] = 0;
1824 if (level == IS_LEVEL_1)
1825 event_add_timer(master, lsp_l1_refresh_pseudo, circuit,
1826 refresh_time,
1827 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1828 else if (level == IS_LEVEL_2)
1829 event_add_timer(master, lsp_l2_refresh_pseudo, circuit,
1830 refresh_time,
1831 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1832
1833 if (IS_DEBUG_UPDATE_PACKETS) {
1834 zlog_debug(
1835 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1836 circuit->area->area_tag, level,
1837 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1838 lsp->hdr.seqno, lsp->hdr.checksum,
1839 lsp->hdr.rem_lifetime, refresh_time);
1840 }
1841
1842 return ISIS_OK;
1843 }
1844
1845 static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
1846 {
1847 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1848 struct isis_lsp *lsp;
1849 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1850 uint16_t rem_lifetime, refresh_time;
1851
1852 if ((circuit->is_type & level) != level
1853 || (circuit->state != C_STATE_UP)
1854 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1855 || (circuit->u.bc.is_dr[level - 1] == 0))
1856 return ISIS_ERROR;
1857
1858 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1859 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1860 LSP_FRAGMENT(lsp_id) = 0;
1861
1862 lsp = lsp_search(head, lsp_id);
1863
1864 if (!lsp) {
1865 flog_err(EC_LIB_DEVELOPMENT,
1866 "lsp_regenerate_pseudo: no l%d LSP %s found!", level,
1867 rawlspid_print(lsp_id));
1868 return ISIS_ERROR;
1869 }
1870
1871 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1872 lsp->hdr.rem_lifetime = rem_lifetime;
1873 lsp_build_pseudo(lsp, circuit, level);
1874 lsp_inc_seqno(lsp, 0);
1875 lsp->last_generated = time(NULL);
1876 lsp_flood(lsp, NULL);
1877
1878 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1879 if (level == IS_LEVEL_1)
1880 event_add_timer(master, lsp_l1_refresh_pseudo, circuit,
1881 refresh_time,
1882 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1883 else if (level == IS_LEVEL_2)
1884 event_add_timer(master, lsp_l2_refresh_pseudo, circuit,
1885 refresh_time,
1886 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1887
1888 if (IS_DEBUG_UPDATE_PACKETS) {
1889 zlog_debug(
1890 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1891 circuit->area->area_tag, level,
1892 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1893 lsp->hdr.seqno, lsp->hdr.checksum,
1894 lsp->hdr.rem_lifetime, refresh_time);
1895 }
1896
1897 return ISIS_OK;
1898 }
1899
1900 /*
1901 * Something has changed or periodic refresh -> regenerate pseudo LSP
1902 */
1903 static void lsp_l1_refresh_pseudo(struct event *thread)
1904 {
1905 struct isis_circuit *circuit;
1906 uint8_t id[ISIS_SYS_ID_LEN + 2];
1907
1908 circuit = EVENT_ARG(thread);
1909
1910 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
1911 circuit->lsp_regenerate_pending[0] = 0;
1912
1913 if ((circuit->u.bc.is_dr[0] == 0)
1914 || (circuit->is_type & IS_LEVEL_1) == 0) {
1915 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1916 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1917 LSP_FRAGMENT(id) = 0;
1918 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
1919 return;
1920 }
1921
1922 lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
1923 }
1924
1925 static void lsp_l2_refresh_pseudo(struct event *thread)
1926 {
1927 struct isis_circuit *circuit;
1928 uint8_t id[ISIS_SYS_ID_LEN + 2];
1929
1930 circuit = EVENT_ARG(thread);
1931
1932 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
1933 circuit->lsp_regenerate_pending[1] = 0;
1934
1935 if ((circuit->u.bc.is_dr[1] == 0)
1936 || (circuit->is_type & IS_LEVEL_2) == 0) {
1937 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1938 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1939 LSP_FRAGMENT(id) = 0;
1940 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
1941 return;
1942 }
1943
1944 lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
1945 }
1946
1947 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
1948 {
1949 struct isis_lsp *lsp;
1950 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1951 time_t now, diff;
1952 long timeout;
1953 int lvl;
1954 struct isis_area *area = circuit->area;
1955
1956 if (circuit->circ_type != CIRCUIT_T_BROADCAST
1957 || circuit->state != C_STATE_UP)
1958 return ISIS_OK;
1959
1960 sched_debug(
1961 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1962 area->area_tag, circuit_t2string(level),
1963 circuit->interface->name);
1964
1965 memcpy(lsp_id, area->isis->sysid, ISIS_SYS_ID_LEN);
1966 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1967 LSP_FRAGMENT(lsp_id) = 0;
1968 now = time(NULL);
1969
1970 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1971 sched_debug(
1972 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1973 area->area_tag, lvl);
1974
1975 if (!((level & lvl) && (circuit->is_type & lvl))) {
1976 sched_debug("ISIS (%s): Level is not active on circuit",
1977 area->area_tag);
1978 continue;
1979 }
1980
1981 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
1982 sched_debug(
1983 "ISIS (%s): This IS is not DR, nothing to do.",
1984 area->area_tag);
1985 continue;
1986 }
1987
1988 if (circuit->lsp_regenerate_pending[lvl - 1]) {
1989 struct timeval remain = event_timer_remain(
1990 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1991 sched_debug(
1992 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1993 area->area_tag, (long long)remain.tv_sec,
1994 (long long)remain.tv_usec / 1000);
1995 continue;
1996 }
1997
1998 lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
1999 if (!lsp) {
2000 sched_debug(
2001 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2002 area->area_tag);
2003 continue;
2004 }
2005
2006 /*
2007 * Throttle avoidance
2008 */
2009 sched_debug(
2010 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2011 area->area_tag, (long long)lsp->last_generated,
2012 (long long)now);
2013 EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2014 diff = now - lsp->last_generated;
2015 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
2016 timeout =
2017 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
2018 - diff);
2019 sched_debug(
2020 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2021 area->area_tag, timeout);
2022 } else {
2023 timeout = 100;
2024 sched_debug(
2025 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
2026 area->area_tag, timeout);
2027 }
2028
2029 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2030
2031 if (lvl == IS_LEVEL_1) {
2032 event_add_timer_msec(
2033 master, lsp_l1_refresh_pseudo, circuit, timeout,
2034 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2035 } else if (lvl == IS_LEVEL_2) {
2036 event_add_timer_msec(
2037 master, lsp_l2_refresh_pseudo, circuit, timeout,
2038 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2039 }
2040 }
2041
2042 return ISIS_OK;
2043 }
2044
2045 /*
2046 * Walk through LSPs for an area
2047 * - set remaining lifetime
2048 */
2049 void lsp_tick(struct event *thread)
2050 {
2051 struct isis_area *area;
2052 struct isis_lsp *lsp;
2053 int level;
2054 uint16_t rem_lifetime;
2055 bool fabricd_sync_incomplete = false;
2056
2057 area = EVENT_ARG(thread);
2058 assert(area);
2059 area->t_tick = NULL;
2060 event_add_timer(master, lsp_tick, area, 1, &area->t_tick);
2061
2062 struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
2063
2064 /*
2065 * Remove LSPs which have aged out
2066 */
2067 for (level = 0; level < ISIS_LEVELS; level++) {
2068 struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
2069 frr_each_from (lspdb, &area->lspdb[level], lsp, next) {
2070 /*
2071 * The lsp rem_lifetime is kept at 0 for MaxAge
2072 * or
2073 * ZeroAgeLifetime depending on explicit purge
2074 * or
2075 * natural age out. So schedule spf only once
2076 * when
2077 * the first time rem_lifetime becomes 0.
2078 */
2079 rem_lifetime = lsp->hdr.rem_lifetime;
2080 lsp_set_time(lsp);
2081
2082 /*
2083 * Schedule may run spf which should be done
2084 * only after
2085 * the lsp rem_lifetime becomes 0 for the first
2086 * time.
2087 * ISO 10589 - 7.3.16.4 first paragraph.
2088 */
2089 if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
2090 /* 7.3.16.4 a) set SRM flags on all */
2091 /* 7.3.16.4 b) retain only the header */
2092 if (lsp->area->purge_originator)
2093 lsp_purge(lsp, lsp->level, NULL);
2094 else
2095 lsp_flood(lsp, NULL);
2096 /* 7.3.16.4 c) record the time to purge
2097 * FIXME */
2098 isis_spf_schedule(lsp->area, lsp->level);
2099 isis_te_lsp_event(lsp, LSP_TICK);
2100 }
2101
2102 if (lsp->age_out == 0) {
2103 zlog_debug(
2104 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2105 area->area_tag, lsp->level,
2106 rawlspid_print(lsp->hdr.lsp_id),
2107 lsp->hdr.seqno);
2108
2109 /* if we're aging out fragment 0, lsp_destroy()
2110 * below will delete all other fragments too,
2111 * so we need to skip over those
2112 */
2113 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2114 while (next &&
2115 !memcmp(next->hdr.lsp_id,
2116 lsp->hdr.lsp_id,
2117 ISIS_SYS_ID_LEN + 1))
2118 next = lspdb_next(
2119 &area->lspdb[level],
2120 next);
2121
2122 lspdb_del(&area->lspdb[level], lsp);
2123 lsp_destroy(lsp);
2124 lsp = NULL;
2125 }
2126
2127 if (fabricd_init_c && lsp) {
2128 fabricd_sync_incomplete |=
2129 ISIS_CHECK_FLAG(lsp->SSNflags,
2130 fabricd_init_c);
2131 }
2132 }
2133 }
2134
2135 if (fabricd_init_c
2136 && !fabricd_sync_incomplete
2137 && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
2138 fabricd_initial_sync_finish(area);
2139 }
2140 }
2141
2142 void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
2143 {
2144 struct isis_lsp *lsp;
2145
2146 lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
2147 if (!lsp)
2148 return;
2149
2150 lsp_purge(lsp, level, NULL);
2151 }
2152
2153 /*
2154 * Purge own LSP that is received and we don't have.
2155 * -> Do as in 7.3.16.4
2156 */
2157 void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
2158 struct isis_area *area)
2159 {
2160 struct isis_lsp *lsp;
2161
2162 /*
2163 * We need to create the LSP to be purged
2164 */
2165 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
2166 lsp->area = area;
2167 lsp->level = level;
2168 lsp_adjust_stream(lsp);
2169 lsp->age_out = ZERO_AGE_LIFETIME;
2170 lsp->area->lsp_purge_count[level - 1]++;
2171
2172 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
2173 lsp->hdr.rem_lifetime = 0;
2174
2175 lsp_purge_add_poi(lsp, NULL);
2176
2177 lsp_pack_pdu(lsp);
2178
2179 lsp_insert(&area->lspdb[lsp->level - 1], lsp);
2180 lsp_flood(lsp, NULL);
2181
2182 return;
2183 }
2184
2185 void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
2186 {
2187 struct listnode *node;
2188 struct isis_circuit *circuit;
2189
2190 assert(lsp);
2191
2192 if (!lsp->area)
2193 return;
2194
2195 struct list *circuit_list = lsp->area->circuit_list;
2196 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
2197 if (set) {
2198 isis_tx_queue_add(circuit->tx_queue, lsp,
2199 TX_LSP_NORMAL);
2200 } else {
2201 isis_tx_queue_del(circuit->tx_queue, lsp);
2202 }
2203 }
2204 }
2205
2206 void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
2207 const char *func, const char *file, int line)
2208 {
2209 if (IS_DEBUG_FLOODING) {
2210 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2211 rawlspid_print(lsp->hdr.lsp_id),
2212 circuit ? " except on " : "",
2213 circuit ? circuit->interface->name : "",
2214 func, file, line);
2215 }
2216
2217 if (!fabricd)
2218 lsp_set_all_srmflags(lsp, true);
2219 else
2220 fabricd_lsp_flood(lsp, circuit);
2221
2222 if (circuit)
2223 isis_tx_queue_del(circuit->tx_queue, lsp);
2224 }
2225
2226 static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
2227 {
2228 lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
2229
2230 /* when an adjacency state changes determine if we need to
2231 * change attach_bits in other area's LSPs
2232 */
2233 isis_reset_attach_bit(adj);
2234
2235 return 0;
2236 }
2237
2238 /*
2239 * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
2240 * address-family and MT-ID.
2241 */
2242 int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
2243 lsp_ip_reach_iter_cb cb, void *arg)
2244 {
2245 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
2246 struct isis_lsp *frag;
2247 struct listnode *node;
2248
2249 if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
2250 return LSP_ITER_CONTINUE;
2251
2252 /* Parse LSP */
2253 if (lsp->tlvs) {
2254 if (!fabricd && !pseudo_lsp && family == AF_INET
2255 && mtid == ISIS_MT_IPV4_UNICAST) {
2256 struct isis_item_list *reachs[] = {
2257 &lsp->tlvs->oldstyle_ip_reach,
2258 &lsp->tlvs->oldstyle_ip_reach_ext};
2259
2260 for (unsigned int i = 0; i < array_size(reachs); i++) {
2261 struct isis_oldstyle_ip_reach *r;
2262
2263 for (r = (struct isis_oldstyle_ip_reach *)
2264 reachs[i]
2265 ->head;
2266 r; r = r->next) {
2267 bool external = i ? true : false;
2268
2269 if ((*cb)((struct prefix *)&r->prefix,
2270 r->metric, external, NULL,
2271 arg)
2272 == LSP_ITER_STOP)
2273 return LSP_ITER_STOP;
2274 }
2275 }
2276 }
2277
2278 if (!pseudo_lsp && family == AF_INET) {
2279 struct isis_item_list *ipv4_reachs;
2280
2281 if (mtid == ISIS_MT_IPV4_UNICAST)
2282 ipv4_reachs = &lsp->tlvs->extended_ip_reach;
2283 else
2284 ipv4_reachs = isis_lookup_mt_items(
2285 &lsp->tlvs->mt_ip_reach, mtid);
2286
2287 struct isis_extended_ip_reach *r;
2288 for (r = ipv4_reachs ? (struct isis_extended_ip_reach *)
2289 ipv4_reachs->head
2290 : NULL;
2291 r; r = r->next) {
2292 if ((*cb)((struct prefix *)&r->prefix,
2293 r->metric, false, r->subtlvs, arg)
2294 == LSP_ITER_STOP)
2295 return LSP_ITER_STOP;
2296 }
2297 }
2298
2299 if (!pseudo_lsp && family == AF_INET6) {
2300 struct isis_item_list *ipv6_reachs;
2301 struct isis_ipv6_reach *r;
2302
2303 if (mtid == ISIS_MT_IPV4_UNICAST)
2304 ipv6_reachs = &lsp->tlvs->ipv6_reach;
2305 else
2306 ipv6_reachs = isis_lookup_mt_items(
2307 &lsp->tlvs->mt_ipv6_reach, mtid);
2308
2309 for (r = ipv6_reachs ? (struct isis_ipv6_reach *)
2310 ipv6_reachs->head
2311 : NULL;
2312 r; r = r->next) {
2313 if ((*cb)((struct prefix *)&r->prefix,
2314 r->metric, r->external, r->subtlvs,
2315 arg)
2316 == LSP_ITER_STOP)
2317 return LSP_ITER_STOP;
2318 }
2319 }
2320 }
2321
2322 /* Parse LSP fragments if it is not a fragment itself */
2323 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2324 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2325 if (!frag->tlvs)
2326 continue;
2327
2328 if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
2329 arg)
2330 == LSP_ITER_STOP)
2331 return LSP_ITER_STOP;
2332 }
2333
2334 return LSP_ITER_CONTINUE;
2335 }
2336
2337 /*
2338 * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
2339 * MT-ID.
2340 */
2341 int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
2342 lsp_is_reach_iter_cb cb, void *arg)
2343 {
2344 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
2345 struct isis_lsp *frag;
2346 struct listnode *node;
2347 struct isis_item *head;
2348 struct isis_item_list *te_neighs;
2349
2350 if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
2351 return LSP_ITER_CONTINUE;
2352
2353 /* Parse LSP */
2354 if (lsp->tlvs) {
2355 if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) {
2356 head = lsp->tlvs->oldstyle_reach.head;
2357 for (struct isis_oldstyle_reach *reach =
2358 (struct isis_oldstyle_reach *)head;
2359 reach; reach = reach->next) {
2360 if ((*cb)(reach->id, reach->metric, true, NULL,
2361 arg)
2362 == LSP_ITER_STOP)
2363 return LSP_ITER_STOP;
2364 }
2365 }
2366
2367 if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST)
2368 te_neighs = &lsp->tlvs->extended_reach;
2369 else
2370 te_neighs =
2371 isis_get_mt_items(&lsp->tlvs->mt_reach, mtid);
2372 if (te_neighs) {
2373 head = te_neighs->head;
2374 for (struct isis_extended_reach *reach =
2375 (struct isis_extended_reach *)head;
2376 reach; reach = reach->next) {
2377 if ((*cb)(reach->id, reach->metric, false,
2378 reach->subtlvs, arg)
2379 == LSP_ITER_STOP)
2380 return LSP_ITER_STOP;
2381 }
2382 }
2383 }
2384
2385 /* Parse LSP fragments if it not a fragment itself. */
2386 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2387 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2388 if (!frag->tlvs)
2389 continue;
2390
2391 if (isis_lsp_iterate_is_reach(frag, mtid, cb, arg)
2392 == LSP_ITER_STOP)
2393 return LSP_ITER_STOP;
2394 }
2395
2396 return LSP_ITER_CONTINUE;
2397 }
2398
2399 void lsp_init(void)
2400 {
2401 device_startup = true;
2402 hook_register(isis_adj_state_change_hook,
2403 lsp_handle_adj_state_change);
2404 }