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