]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_lsp.c
isisd: fix disabled flex-algo on race condition
[mirror_frr.git] / isisd / isis_lsp.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
eb5d44eb 2/*
3 * IS-IS Rout(e)ing protocol - isis_lsp.c
4 * LSP processing
5 *
6 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 7 * Tampere University of Technology
eb5d44eb 8 * Institute of Communications Engineering
f3ccedaa 9 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
eb5d44eb 10 */
15935e9a 11
eb5d44eb 12#include <zebra.h>
eb5d44eb 13
14#include "linklist.h"
24a58196 15#include "frrevent.h"
eb5d44eb 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"
6a270cd9 24#include "checksum.h"
3f045a08 25#include "md5.h"
f3ccedaa 26#include "table.h"
d43d2df5 27#include "srcdest_table.h"
38937bd5 28#include "lib_errors.h"
eb5d44eb 29
eb5d44eb 30#include "isisd/isis_constants.h"
31#include "isisd/isis_common.h"
3f045a08 32#include "isisd/isis_flags.h"
eb5d44eb 33#include "isisd/isis_circuit.h"
34#include "isisd/isisd.h"
eb5d44eb 35#include "isisd/isis_lsp.h"
36#include "isisd/isis_pdu.h"
37#include "isisd/isis_dynhn.h"
38#include "isisd/isis_misc.h"
eb5d44eb 39#include "isisd/isis_csm.h"
40#include "isisd/isis_adjacency.h"
41#include "isisd/isis_spf.h"
99894f9a 42#include "isisd/isis_mt.h"
841791b6 43#include "isisd/isis_tlvs.h"
1b3f47d0 44#include "isisd/isis_te.h"
26f6acaf 45#include "isisd/isis_sr.h"
8e6fb83b 46#include "isisd/fabricd.h"
9b39405f 47#include "isisd/isis_tx_queue.h"
2a1c520e 48#include "isisd/isis_nb.h"
78774bbc 49#include "isisd/isis_flex_algo.h"
eb5d44eb 50
66b9a381
DL
51DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
52
e6685141
DS
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);
3f045a08 56
4bef0ec4
DL
57static void lsp_destroy(struct isis_lsp *lsp);
58
49b27ea2
IL
59static bool device_startup;
60
d7c0a89a 61int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
f390d2c7 62{
d62a17ae 63 return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
eb5d44eb 64}
65
4bef0ec4 66int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b)
eb5d44eb 67{
4bef0ec4 68 return memcmp(a->hdr.lsp_id, b->hdr.lsp_id, sizeof(a->hdr.lsp_id));
eb5d44eb 69}
70
4bef0ec4 71void lsp_db_init(struct lspdb_head *head)
eb5d44eb 72{
4bef0ec4
DL
73 lspdb_init(head);
74}
d62a17ae 75
4bef0ec4
DL
76void lsp_db_fini(struct lspdb_head *head)
77{
78 struct isis_lsp *lsp;
eb5d44eb 79
4bef0ec4
DL
80 while ((lsp = lspdb_pop(head)))
81 lsp_destroy(lsp);
82 lspdb_fini(head);
83}
f390d2c7 84
4bef0ec4
DL
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));
eb5d44eb 89
4bef0ec4 90 return lspdb_find(head, &searchfor);
eb5d44eb 91}
92
d62a17ae 93static void lsp_clear_data(struct isis_lsp *lsp)
eb5d44eb 94{
d62a17ae 95 if (!lsp)
96 return;
97
af8ac8f9
CF
98 isis_free_tlvs(lsp->tlvs);
99 lsp->tlvs = NULL;
eb5d44eb 100}
101
4bef0ec4 102static void lsp_remove_frags(struct lspdb_head *head, struct list *frags);
dc84cf14 103
d62a17ae 104static void lsp_destroy(struct isis_lsp *lsp)
eb5d44eb 105{
58e16237 106 struct listnode *cnode;
d62a17ae 107 struct isis_circuit *circuit;
108
109 if (!lsp)
110 return;
111
58e16237 112 for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode, circuit))
9b39405f 113 isis_tx_queue_del(circuit->tx_queue, lsp);
58e16237 114
d62a17ae 115 ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
d62a17ae 116
d9884a75
OD
117 isis_te_lsp_event(lsp, LSP_DEL);
118
d62a17ae 119 lsp_clear_data(lsp);
120
dc84cf14
CF
121 if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
122 if (lsp->lspu.frags) {
4bef0ec4
DL
123 lsp_remove_frags(&lsp->area->lspdb[lsp->level - 1],
124 lsp->lspu.frags);
dc84cf14
CF
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 }
d62a17ae 132 }
133
134 isis_spf_schedule(lsp->area, lsp->level);
135
136 if (lsp->pdu)
137 stream_free(lsp->pdu);
1eb7c3a1
CF
138
139 fabricd_lsp_free(lsp);
d62a17ae 140 XFREE(MTYPE_ISIS_LSP, lsp);
eb5d44eb 141}
142
eb5d44eb 143/*
144 * Remove all the frags belonging to the given lsp
145 */
4bef0ec4 146static void lsp_remove_frags(struct lspdb_head *head, struct list *frags)
eb5d44eb 147{
d62a17ae 148 struct listnode *lnode, *lnnode;
149 struct isis_lsp *lsp;
150
151 for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
4bef0ec4
DL
152 lsp = lsp_search(head, lsp->hdr.lsp_id);
153 lspdb_del(head, lsp);
d62a17ae 154 lsp_destroy(lsp);
d62a17ae 155 }
eb5d44eb 156}
157
4bef0ec4 158void lsp_search_and_destroy(struct lspdb_head *head, const uint8_t *id)
eb5d44eb 159{
d62a17ae 160 struct isis_lsp *lsp;
161
4bef0ec4
DL
162 lsp = lsp_search(head, id);
163 if (lsp) {
164 lspdb_del(head, lsp);
d62a17ae 165 /*
166 * If this is a zero lsp, remove all the frags now
167 */
af8ac8f9 168 if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) {
d62a17ae 169 if (lsp->lspu.frags)
4bef0ec4 170 lsp_remove_frags(head, lsp->lspu.frags);
d62a17ae 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);
d62a17ae 182 }
eb5d44eb 183}
184
185/*
186 * Compares a LSP to given values
187 * Params are given in net order
188 */
af8ac8f9
CF
189int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
190 uint16_t checksum, uint16_t rem_lifetime)
eb5d44eb 191{
af8ac8f9
CF
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))) {
e740f9c1 195 if (IS_DEBUG_SNP_PACKETS) {
d62a17ae 196 zlog_debug(
5d39a819
OD
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);
d62a17ae 200 zlog_debug(
6cde4b45 201 "ISIS-Snp (%s): is equal to ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
af8ac8f9 202 areatag, seqno, checksum, rem_lifetime);
d62a17ae 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 */
af8ac8f9
CF
219 if (seqno > lsp->hdr.seqno
220 || (seqno == lsp->hdr.seqno
221 && ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
16c2ab97
CF
222 || (lsp->hdr.checksum != checksum
223 && lsp->hdr.rem_lifetime)))) {
e740f9c1 224 if (IS_DEBUG_SNP_PACKETS) {
d62a17ae 225 zlog_debug(
5d39a819
OD
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);
d62a17ae 229 zlog_debug(
6cde4b45 230 "ISIS-Snp (%s): is newer than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
af8ac8f9
CF
231 areatag, lsp->hdr.seqno, lsp->hdr.checksum,
232 lsp->hdr.rem_lifetime);
d62a17ae 233 }
234 return LSP_NEWER;
235 }
e740f9c1 236 if (IS_DEBUG_SNP_PACKETS) {
5d39a819
OD
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);
d62a17ae 241 zlog_debug(
6cde4b45 242 "ISIS-Snp (%s): is older than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
af8ac8f9
CF
243 areatag, lsp->hdr.seqno, lsp->hdr.checksum,
244 lsp->hdr.rem_lifetime);
d62a17ae 245 }
246
247 return LSP_OLDER;
eb5d44eb 248}
249
c55018ab 250static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer, bool keep)
3f045a08 251{
af8ac8f9
CF
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;
b599ec55 256 size_t orig_getp = 0, orig_endp = 0;
c55018ab
CF
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);
af8ac8f9
CF
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);
c55018ab
CF
276
277 if (keep) {
278 stream_set_endp(lsp->pdu, orig_endp);
279 stream_set_getp(lsp->pdu, orig_getp);
280 }
3f045a08
JB
281}
282
af8ac8f9 283static void lsp_add_auth(struct isis_lsp *lsp)
3f045a08 284{
d62a17ae 285 struct isis_passwd *passwd;
af8ac8f9
CF
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}
d62a17ae 290
af8ac8f9
CF
291static void lsp_pack_pdu(struct isis_lsp *lsp)
292{
293 if (!lsp->tlvs)
294 lsp->tlvs = isis_alloc_tlvs();
d62a17ae 295
af8ac8f9 296 lsp_add_auth(lsp);
d62a17ae 297
af8ac8f9 298 size_t len_pointer;
c55018ab 299 put_lsp_hdr(lsp, &len_pointer, false);
af8ac8f9
CF
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));
3f045a08
JB
306}
307
af8ac8f9 308void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
eb5d44eb 309{
af8ac8f9 310 uint32_t newseq;
d62a17ae 311
af8ac8f9
CF
312 if (seqno == 0 || lsp->hdr.seqno > seqno)
313 newseq = lsp->hdr.seqno + 1;
d62a17ae 314 else
af8ac8f9 315 newseq = seqno + 1;
d62a17ae 316
b21b068d
EDP
317#ifndef FABRICD
318 /* check for overflow */
319 if (newseq < lsp->hdr.seqno) {
320 /* send northbound notification */
1ee746d9 321 lsp->area->lsp_exceeded_max_counter++;
322 isis_notif_lsp_exceed_max(lsp->area, lsp->hdr.lsp_id);
b21b068d
EDP
323 }
324#endif /* ifndef FABRICD */
325
af8ac8f9
CF
326 lsp->hdr.seqno = newseq;
327
328 lsp_pack_pdu(lsp);
d62a17ae 329 isis_spf_schedule(lsp->area, lsp->level);
d9884a75 330 isis_te_lsp_event(lsp, LSP_INC);
af8ac8f9 331}
d62a17ae 332
2c92bee4
CF
333static void lsp_purge_add_poi(struct isis_lsp *lsp,
334 const uint8_t *sender)
335{
eab88f36
K
336 if (lsp->area == NULL)
337 return;
338
2c92bee4
CF
339 if (!lsp->area->purge_originator)
340 return;
341
342 /* add purge originator identification */
343 if (!lsp->tlvs)
344 lsp->tlvs = isis_alloc_tlvs();
eab88f36
K
345 isis_tlvs_set_purge_originator(lsp->tlvs, lsp->area->isis->sysid,
346 sender);
2c92bee4
CF
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)
af8ac8f9
CF
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];
6f004b60 362 lsp->area->lsp_purge_count[level - 1]++;
af8ac8f9 363
2c92bee4
CF
364 lsp_purge_add_poi(lsp, sender);
365
af8ac8f9 366 lsp_pack_pdu(lsp);
9b39405f 367 lsp_flood(lsp, NULL);
eb5d44eb 368}
369
370/*
af8ac8f9 371 * Generates checksum for LSP and its frags
eb5d44eb 372 */
af8ac8f9 373static void lsp_seqno_update(struct isis_lsp *lsp0)
eb5d44eb 374{
d62a17ae 375 struct isis_lsp *lsp;
376 struct listnode *node;
f390d2c7 377
af8ac8f9 378 lsp_inc_seqno(lsp0, 0);
eb5d44eb 379
d62a17ae 380 if (!lsp0->lspu.frags)
381 return;
eb5d44eb 382
af8ac8f9
CF
383 for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) {
384 if (lsp->tlvs)
385 lsp_inc_seqno(lsp, 0);
8f27aa27
CF
386 else if (lsp->hdr.rem_lifetime) {
387 /* Purge should only be applied when the fragment has
388 * non-zero remaining lifetime.
389 */
2c92bee4 390 lsp_purge(lsp, lsp0->level, NULL);
8f27aa27 391 }
af8ac8f9 392 }
f390d2c7 393
d62a17ae 394 return;
eb5d44eb 395}
396
a4777e46 397bool isis_level2_adj_up(struct isis_area *area)
f3abc412 398{
399 struct listnode *node, *cnode;
400 struct isis_circuit *circuit;
401 struct list *adjdb;
402 struct isis_adjacency *adj;
74ef8dd9 403
a4777e46
IR
404 if (area->is_type == IS_LEVEL_1)
405 return false;
406
74ef8dd9
IR
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)) {
77d73edf 414 if (adj->level != ISIS_ADJ_LEVEL1
f3abc412 415 && adj->adj_state == ISIS_ADJ_UP)
416 return true;
417 }
74ef8dd9
IR
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;
f3abc412 424 }
425 }
74ef8dd9 426
f3abc412 427 return false;
428}
429
49b27ea2
IL
430/*
431 * Unset the overload bit after the timer expires
432 */
e6685141 433void set_overload_on_start_timer(struct event *thread)
49b27ea2 434{
e16d030c 435 struct isis_area *area = EVENT_ARG(thread);
49b27ea2
IL
436 assert(area);
437
438 area->t_overload_on_startup_timer = NULL;
4afc7836
IL
439
440 /* Check if set-overload-bit is not currently configured */
441 if (!area->overload_configured)
442 isis_area_overload_bit_set(area, false);
49b27ea2
IL
443}
444
74ef8dd9 445static void isis_reset_attach_bit(struct isis_adjacency *adj)
77d73edf 446{
74ef8dd9 447 struct isis_area *area = adj->circuit->area;
77d73edf 448 struct lspdb_head *head;
449 struct isis_lsp *lsp;
450 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
451
74ef8dd9
IR
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
77d73edf 456 */
74ef8dd9
IR
457
458 if (area->is_type != IS_LEVEL_1_AND_2 || adj->level == ISIS_ADJ_LEVEL1)
77d73edf 459 return;
460
74ef8dd9
IR
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);
77d73edf 483 }
484}
485
f3abc412 486static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit,
487 struct isis_area *area)
e38e0df0 488{
d7c0a89a 489 uint8_t lsp_bits = 0;
d0f14921 490 if (area->is_type == IS_LEVEL_1)
d62a17ae 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;
f3abc412 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;
d62a17ae 503 return lsp_bits;
e38e0df0
SV
504}
505
af8ac8f9
CF
506static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
507 struct isis_tlvs *tlvs, struct stream *stream,
d62a17ae 508 struct isis_area *area, int level)
eb5d44eb 509{
d62a17ae 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
af8ac8f9 518 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
d62a17ae 519 lsp->area = area;
520 lsp->level = level;
521 lsp->age_out = ZERO_AGE_LIFETIME;
522 lsp->installed = time(NULL);
d62a17ae 523
af8ac8f9
CF
524 lsp->tlvs = tlvs;
525
2c92bee4
CF
526 if (area->dynhostname && lsp->tlvs->hostname
527 && lsp->hdr.rem_lifetime) {
240f48b3
IR
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);
d62a17ae 533 }
534
535 return;
eb5d44eb 536}
537
0b8b6cab
CF
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
af8ac8f9
CF
551void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
552 struct isis_tlvs *tlvs, struct stream *stream,
164066e4 553 struct isis_area *area, int level, bool confusion)
eb5d44eb 554{
d62a17ae 555 if (lsp->own_lsp) {
af4c2728 556 flog_err(
450971aa 557 EC_LIB_DEVELOPMENT,
5d39a819
OD
558 "ISIS-Upd (%s): BUG updating LSP %pLS still marked as own LSP",
559 area->area_tag, lsp->hdr.lsp_id);
d62a17ae 560 lsp_clear_data(lsp);
561 lsp->own_lsp = 0;
562 }
563
164066e4 564 if (confusion) {
2c92bee4
CF
565 lsp_purge(lsp, level, NULL);
566 } else {
567 lsp_update_data(lsp, hdr, tlvs, stream, area, level);
164066e4 568 }
d62a17ae 569
0b8b6cab
CF
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;
eb5d44eb 573
0b8b6cab
CF
574 memcpy(lspid, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
575 LSP_FRAGMENT(lspid) = 0;
4bef0ec4 576 lsp0 = lsp_search(&area->lspdb[level - 1], lspid);
0b8b6cab
CF
577 if (lsp0)
578 lsp_link_fragment(lsp, lsp0);
8f5dbe18 579 }
0b8b6cab 580
d9884a75 581 if (lsp->hdr.seqno) {
5304211a 582 isis_spf_schedule(lsp->area, lsp->level);
d9884a75
OD
583 isis_te_lsp_event(lsp, LSP_UPD);
584 }
8f5dbe18
CF
585}
586
eb5d44eb 587/* creation of LSP directly from what we received */
af8ac8f9
CF
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)
eb5d44eb 592{
d62a17ae 593 struct isis_lsp *lsp;
594
595 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
af8ac8f9 596 lsp_update_data(lsp, hdr, tlvs, stream, area, level);
8f5dbe18 597 lsp_link_fragment(lsp, lsp0);
d62a17ae 598
599 return lsp;
eb5d44eb 600}
601
d07067ba
CF
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
d7c0a89a 613struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
af8ac8f9 614 uint16_t rem_lifetime, uint32_t seqno,
8f5dbe18
CF
615 uint8_t lsp_bits, uint16_t checksum,
616 struct isis_lsp *lsp0, int level)
eb5d44eb 617{
d62a17ae 618 struct isis_lsp *lsp;
619
620 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
621 lsp->area = area;
622
d07067ba 623 lsp_adjust_stream(lsp);
d62a17ae 624
d62a17ae 625 /* Minimal LSP PDU size */
af8ac8f9
CF
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;
d62a17ae 632 lsp->level = level;
633 lsp->age_out = ZERO_AGE_LIFETIME;
8f5dbe18 634 lsp_link_fragment(lsp, lsp0);
c55018ab 635 put_lsp_hdr(lsp, NULL, false);
d62a17ae 636
e740f9c1 637 if (IS_DEBUG_EVENTS)
5d39a819
OD
638 zlog_debug("New LSP with ID %pLS len %d seqnum %08x", lsp_id,
639 lsp->hdr.pdu_len, lsp->hdr.seqno);
d62a17ae 640
641 return lsp;
eb5d44eb 642}
643
4bef0ec4 644void lsp_insert(struct lspdb_head *head, struct isis_lsp *lsp)
eb5d44eb 645{
4bef0ec4 646 lspdb_add(head, lsp);
d9884a75 647 if (lsp->hdr.seqno) {
d62a17ae 648 isis_spf_schedule(lsp->area, lsp->level);
d9884a75
OD
649 isis_te_lsp_event(lsp, LSP_ADD);
650 }
eb5d44eb 651}
652
653/*
94829496 654 * Build a list of LSPs with non-zero ht and seqno bounded by start and stop ids
eb5d44eb 655 */
4bef0ec4
DL
656void lsp_build_list_nonzero_ht(struct lspdb_head *head, const uint8_t *start_id,
657 const uint8_t *stop_id, struct list *list)
eb5d44eb 658{
4bef0ec4
DL
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));
eb5d44eb 663
4bef0ec4 664 start = lspdb_find_gteq(head, &searchfor);
81fddbe7 665 frr_each_from (lspdb, head, lsp, start) {
9337256e
CF
666 if (memcmp(lsp->hdr.lsp_id, stop_id,
667 ISIS_SYS_ID_LEN + 2) > 0)
d62a17ae 668 break;
f390d2c7 669
94829496 670 if (lsp->hdr.rem_lifetime && lsp->hdr.seqno)
9337256e
CF
671 listnode_add(list, lsp);
672 }
eb5d44eb 673}
674
d62a17ae 675static void lsp_set_time(struct isis_lsp *lsp)
eb5d44eb 676{
d62a17ae 677 assert(lsp);
f390d2c7 678
af8ac8f9 679 if (lsp->hdr.rem_lifetime == 0) {
d62a17ae 680 if (lsp->age_out > 0)
681 lsp->age_out--;
682 return;
683 }
eb5d44eb 684
af8ac8f9
CF
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);
eb5d44eb 688}
689
7533cad7
QY
690void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
691 char frag, struct isis *isis)
eb5d44eb 692{
d62a17ae 693 struct isis_dynhn *dyn = NULL;
772270f3 694 char id[SYSID_STRLEN];
d62a17ae 695
696 if (dynhost)
240f48b3 697 dyn = dynhn_find_by_id(isis, lsp_id);
d62a17ae 698 else
699 dyn = NULL;
700
701 if (dyn)
4ced1a2c 702 snprintf(id, sizeof(id), "%.14s", dyn->hostname);
d62a17ae 703 else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
4ced1a2c 704 snprintf(id, sizeof(id), "%.14s", cmd_hostname_get());
d62a17ae 705 else
5d39a819 706 snprintf(id, sizeof(id), "%pSY", lsp_id);
eab88f36 707
d62a17ae 708 if (frag)
7533cad7
QY
709 snprintf(dest, dest_len, "%s.%02x-%02x", id,
710 LSP_PSEUDO_ID(lsp_id), LSP_FRAGMENT(lsp_id));
d62a17ae 711 else
7533cad7 712 snprintf(dest, dest_len, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id));
eb5d44eb 713}
714
f390d2c7 715/* Convert the lsp attribute bits to attribute string */
36228974 716static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
f390d2c7 717{
36228974 718 char *pos = buf;
eb5d44eb 719
af8ac8f9 720 if (!lsp_bits)
d62a17ae 721 return " none";
eb5d44eb 722
36228974 723 if (buf_size < 2 * 3)
724 return " error";
725
d62a17ae 726 /* we only focus on the default metric */
f3abc412 727 pos += snprintf(pos, buf_size, "%d/",
728 ISIS_MASK_LSP_ATT_BITS(lsp_bits) ? 1 : 0);
eb5d44eb 729
f3abc412 730 pos += snprintf(pos, buf_size, "%d/",
731 ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
f390d2c7 732
f3abc412 733 snprintf(pos, buf_size, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
eb5d44eb 734
36228974 735 return buf;
eb5d44eb 736}
737
738/* this function prints the lsp on show isis database */
a2cac12a
JG
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)
eb5d44eb 781{
0d6fb551 782 char LSPid[255];
d62a17ae 783 char age_out[8];
36228974 784 char b[200];
d62a17ae 785
7533cad7 786 lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis);
d62a17ae 787 vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
6cde4b45
DL
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);
af8ac8f9 791 if (lsp->hdr.rem_lifetime == 0) {
772270f3 792 snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out);
d62a17ae 793 age_out[7] = '\0';
794 vty_out(vty, "%7s ", age_out);
795 } else
6cde4b45 796 vty_out(vty, " %5hu ", lsp->hdr.rem_lifetime);
36228974 797 vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
c3ae3127
CF
798}
799
a2cac12a
JG
800void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty,
801 struct json_object *json, char dynhost,
802 struct isis *isis)
eb5d44eb 803{
a2cac12a
JG
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 }
eb5d44eb 816}
817
818/* print all the lsps info in the local lspdb */
a2cac12a
JG
819int lsp_print_all(struct vty *vty, struct json_object *json,
820 struct lspdb_head *head, char detail, char dynhost,
821 struct isis *isis)
eb5d44eb 822{
4bef0ec4 823 struct isis_lsp *lsp;
d62a17ae 824 int lsp_count = 0;
825
826 if (detail == ISIS_UI_LEVEL_BRIEF) {
81fddbe7 827 frr_each (lspdb, head, lsp) {
a2cac12a 828 lsp_print_common(lsp, vty, json, dynhost, isis);
d62a17ae 829 lsp_count++;
830 }
831 } else if (detail == ISIS_UI_LEVEL_DETAIL) {
81fddbe7 832 frr_each (lspdb, head, lsp) {
a2cac12a 833 lsp_print_detail(lsp, vty, json, dynhost, isis);
d62a17ae 834 lsp_count++;
835 }
836 }
837
838 return lsp_count;
eb5d44eb 839}
840
d7c0a89a 841static uint16_t lsp_rem_lifetime(struct isis_area *area, int level)
3f045a08 842{
d7c0a89a 843 uint16_t rem_lifetime;
3f045a08 844
d62a17ae 845 /* Add jitter to configured LSP lifetime */
846 rem_lifetime =
847 isis_jitter(area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER);
3f045a08 848
d62a17ae 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];
3f045a08 856
d62a17ae 857 return rem_lifetime;
3f045a08
JB
858}
859
d7c0a89a 860static uint16_t lsp_refresh_time(struct isis_lsp *lsp, uint16_t rem_lifetime)
3f045a08 861{
d62a17ae 862 struct isis_area *area = lsp->area;
863 int level = lsp->level;
d7c0a89a 864 uint16_t refresh_time;
3f045a08 865
d62a17ae 866 /* Add jitter to LSP refresh time */
867 refresh_time =
868 isis_jitter(area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER);
3f045a08 869
d62a17ae 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;
3f045a08 875
d62a17ae 876 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
877 * we accept this violation to satisfy refresh_time <= rem_lifetime -
878 * 300 */
3f045a08 879
d62a17ae 880 return refresh_time;
3f045a08
JB
881}
882
484ab405
LS
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)
78774bbc
HS
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 */
484ab405
LS
908 pcfgs[i] =
909 isis_sr_cfg_prefix_find(area, ipv4, i);
78774bbc 910 }
484ab405
LS
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)
78774bbc
HS
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 */
484ab405 934 pcfgs[i] = isis_sr_cfg_prefix_find(area, ipv6, i);
78774bbc 935 }
484ab405
LS
936
937 isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), ipv6,
938 metric, false, pcfgs);
939}
940
941
d62a17ae 942static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
af8ac8f9 943 struct isis_area *area)
f3ccedaa 944{
af8ac8f9 945 struct route_table *er_table = get_ext_reach(area, AF_INET, lsp->level);
d62a17ae 946 if (!er_table)
947 return;
948
af8ac8f9
CF
949 for (struct route_node *rn = route_top(er_table); rn;
950 rn = route_next(rn)) {
d62a17ae 951 if (!rn->info)
952 continue;
953
af8ac8f9
CF
954 struct prefix_ipv4 *ipv4 = (struct prefix_ipv4 *)&rn->p;
955 struct isis_ext_info *info = rn->info;
f3ccedaa 956
af8ac8f9
CF
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;
d62a17ae 962
af8ac8f9
CF
963 if (area->oldmetric)
964 isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4,
965 metric);
26f6acaf 966 if (area->newmetric) {
0de7b433
HS
967 struct sr_prefix_cfg *pcfgs[SR_ALGORITHM_COUNT] = {
968 NULL};
26f6acaf
RW
969
970 if (area->srdb.enabled)
78774bbc
HS
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 */
0de7b433
HS
978 pcfgs[i] = isis_sr_cfg_prefix_find(
979 area, ipv4, i);
78774bbc 980 }
26f6acaf
RW
981
982 isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric,
0de7b433 983 true, pcfgs);
26f6acaf 984 }
af8ac8f9 985 }
c3ae3127
CF
986}
987
d62a17ae 988static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
af8ac8f9 989 struct isis_area *area)
f3ccedaa 990{
af8ac8f9
CF
991 struct route_table *er_table =
992 get_ext_reach(area, AF_INET6, lsp->level);
d62a17ae 993 if (!er_table)
994 return;
995
af8ac8f9 996 for (struct route_node *rn = route_top(er_table); rn;
d43d2df5 997 rn = srcdest_route_next(rn)) {
d62a17ae 998 if (!rn->info)
999 continue;
af8ac8f9 1000 struct isis_ext_info *info = rn->info;
d43d2df5 1001 struct prefix_ipv6 *p, *src_p;
1b3f47d0 1002
d43d2df5
CF
1003 srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
1004 (const struct prefix **)&src_p);
1005
af8ac8f9 1006 uint32_t metric = info->metric;
d62a17ae 1007 if (info->metric > MAX_WIDE_PATH_METRIC)
af8ac8f9 1008 metric = MAX_WIDE_PATH_METRIC;
d43d2df5
CF
1009
1010 if (!src_p || !src_p->prefixlen) {
0de7b433
HS
1011 struct sr_prefix_cfg *pcfgs[SR_ALGORITHM_COUNT] = {
1012 NULL};
26f6acaf
RW
1013
1014 if (area->srdb.enabled)
78774bbc
HS
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 */
0de7b433
HS
1022 pcfgs[i] = isis_sr_cfg_prefix_find(
1023 area, p, i);
78774bbc 1024 }
26f6acaf 1025
d43d2df5
CF
1026 isis_tlvs_add_ipv6_reach(lsp->tlvs,
1027 isis_area_ipv6_topology(area),
0de7b433 1028 p, metric, true, pcfgs);
d43d2df5
CF
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 }
d62a17ae 1034 }
f3ccedaa
CF
1035}
1036
af8ac8f9 1037static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area)
f3ccedaa 1038{
af8ac8f9
CF
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
4bef0ec4 1052 lsp = lsp_search(&area->lspdb[level - 1], frag_id);
af8ac8f9
CF
1053 if (lsp) {
1054 lsp_clear_data(lsp);
0b8b6cab
CF
1055 if (!lsp->lspu.zero_lsp)
1056 lsp_link_fragment(lsp, lsp0);
af8ac8f9
CF
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,
f3abc412 1062 area->attached_bit_send, area),
8f5dbe18 1063 0, lsp0, level);
af8ac8f9 1064 lsp->own_lsp = 1;
4bef0ec4 1065 lsp_insert(&area->lspdb[level - 1], lsp);
af8ac8f9 1066 return lsp;
f3ccedaa
CF
1067}
1068
eb5d44eb 1069/*
d62a17ae 1070 * Builds the LSP data part. This func creates a new frag whenever
eb5d44eb 1071 * area->lsp_frag_threshold is exceeded.
1072 */
d62a17ae 1073static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
eb5d44eb 1074{
d62a17ae 1075 int level = lsp->level;
af8ac8f9
CF
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);
d62a17ae 1082
af8ac8f9 1083 lsp->tlvs = isis_alloc_tlvs();
d62a17ae 1084 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1085 area->area_tag, level);
1086
af8ac8f9 1087 lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
f3abc412 1088 area->attached_bit_send, area);
d62a17ae 1089
af8ac8f9 1090 lsp_add_auth(lsp);
d62a17ae 1091
af8ac8f9 1092 isis_tlvs_add_area_addresses(lsp->tlvs, area->area_addrs);
d62a17ae 1093
1094 /* Protocols Supported */
1095 if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
af8ac8f9 1096 struct nlpids nlpids = {.count = 0};
1b3f47d0 1097
d62a17ae 1098 if (area->ip_circuits > 0) {
1099 lsp_debug(
1100 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1101 area->area_tag);
af8ac8f9
CF
1102 nlpids.nlpids[nlpids.count] = NLPID_IP;
1103 nlpids.count++;
d62a17ae 1104 }
1105 if (area->ipv6_circuits > 0) {
1106 lsp_debug(
1107 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1108 area->area_tag);
af8ac8f9
CF
1109 nlpids.nlpids[nlpids.count] = NLPID_IPV6;
1110 nlpids.count++;
d62a17ae 1111 }
af8ac8f9 1112 isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
d62a17ae 1113 }
1114
1115 if (area_is_mt(area)) {
1116 lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
d62a17ae 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++) {
af8ac8f9
CF
1123 isis_tlvs_add_mt_router_info(
1124 lsp->tlvs, mt_settings[i]->mtid,
1125 mt_settings[i]->overload, false);
d62a17ae 1126 lsp_debug("ISIS (%s): MT %s", area->area_tag,
af8ac8f9 1127 isis_mtid2str(mt_settings[i]->mtid));
aa4376ec 1128 }
d62a17ae 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) {
6b3ee3a0 1135 isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
af8ac8f9 1136 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
6b3ee3a0 1137 area->area_tag, cmd_hostname_get());
d62a17ae 1138 } else {
1139 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1140 area->area_tag);
1141 }
1142
26f6acaf 1143 /* Add Router Capability TLV. */
eab88f36 1144 if (area->isis->router_id != 0) {
78774bbc
HS
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);
26f6acaf 1153
78774bbc 1154 rcap->router_id.s_addr = area->isis->router_id;
e7948f8c 1155
78774bbc
HS
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 */
26f6acaf
RW
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
d8391312 1175 /* SRGB first */
26f6acaf
RW
1176 range_size = srdb->config.srgb_upper_bound
1177 - srdb->config.srgb_lower_bound + 1;
78774bbc
HS
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;
d8391312 1182 /* Then Algorithm */
78774bbc
HS
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(
3f55b8c6
LS
1194 fa->algorithm, area, &rcap_fad)) {
1195 fa->state = false;
78774bbc 1196 continue;
3f55b8c6
LS
1197 }
1198 fa->state = true;
78774bbc
HS
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 */
d8391312 1204 /* SRLB */
78774bbc 1205 rcap->srlb.flags = 0;
d8391312
OD
1206 range_size = srdb->config.srlb_upper_bound
1207 - srdb->config.srlb_lower_bound + 1;
78774bbc
HS
1208 rcap->srlb.range_size = range_size;
1209 rcap->srlb.lower_bound = srdb->config.srlb_lower_bound;
d8391312 1210 /* And finally MSD */
78774bbc 1211 rcap->msd = srdb->config.msd;
26f6acaf 1212 }
26f6acaf
RW
1213 }
1214
1b3f47d0
OD
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 */
eab88f36
K
1221 if (area->isis->router_id != 0) {
1222 struct in_addr id = {.s_addr = area->isis->router_id};
2dbe669b
DA
1223 lsp_debug("ISIS (%s): Adding router ID %pI4 as IPv4 tlv.",
1224 area->area_tag, &id);
af8ac8f9 1225 isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
d62a17ae 1226
1b3f47d0
OD
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 */
d62a17ae 1231 if (area->newmetric) {
1b3f47d0 1232 if (IS_MPLS_TE(area->mta)
3a6290bd 1233 && area->mta->router_id.s_addr != INADDR_ANY)
1b3f47d0 1234 id.s_addr = area->mta->router_id.s_addr;
d62a17ae 1235 lsp_debug(
1236 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1237 area->area_tag);
af8ac8f9 1238 isis_tlvs_set_te_router_id(lsp->tlvs, &id);
aa4376ec 1239 }
d62a17ae 1240 } else {
1241 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1242 area->area_tag);
1243 }
1244
173f8887
OD
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
d62a17ae 1253 lsp_debug("ISIS (%s): Adding circuit specific information.",
1254 area->area_tag);
1255
92ed0cde
CF
1256 if (fabricd) {
1257 lsp_debug(
6cde4b45 1258 "ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
92ed0cde
CF
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
af8ac8f9 1264 struct isis_circuit *circuit;
d62a17ae 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;
aa4376ec 1282 }
d62a17ae 1283
3f3608d8
DO
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
af8ac8f9
CF
1291 uint32_t metric = area->oldmetric
1292 ? circuit->metric[level - 1]
1293 : circuit->te_metric[level - 1];
1294
91a5bbc4 1295 if (circuit->ip_router && circuit->ip_addrs->count > 0) {
d62a17ae 1296 lsp_debug(
1297 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1298 area->area_tag);
af8ac8f9
CF
1299 struct listnode *ipnode;
1300 struct prefix_ipv4 *ipv4;
1301 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
484ab405
LS
1302 ipv4))
1303 lsp_build_internal_reach_ipv4(lsp, area, ipv4,
1304 metric);
f390d2c7 1305 }
d62a17ae 1306
91a5bbc4 1307 if (circuit->ipv6_router && circuit->ipv6_non_link->count > 0) {
af8ac8f9
CF
1308 struct listnode *ipnode;
1309 struct prefix_ipv6 *ipv6;
1b3f47d0 1310
d62a17ae 1311 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
484ab405
LS
1312 ipnode, ipv6))
1313 lsp_build_internal_reach_ipv6(lsp, area, ipv6,
1314 metric);
aa4376ec 1315 }
d62a17ae 1316
1317 switch (circuit->circ_type) {
1318 case CIRCUIT_T_BROADCAST:
1319 if (level & circuit->is_type) {
af8ac8f9
CF
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) {
d62a17ae 1327 lsp_debug(
5d39a819
OD
1328 "ISIS (%s): Adding DIS %pPN as old-style neighbor",
1329 area->area_tag, ne_id);
af8ac8f9
CF
1330 isis_tlvs_add_oldstyle_reach(
1331 lsp->tlvs, ne_id,
1332 metric);
d62a17ae 1333 }
1b3f47d0 1334 if (area->newmetric)
d62a17ae 1335 tlvs_add_mt_bcast(
af8ac8f9 1336 lsp->tlvs, circuit,
1b3f47d0 1337 level, ne_id, metric);
d62a17ae 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;
af8ac8f9
CF
1345 case CIRCUIT_T_P2P: {
1346 struct isis_adjacency *nei = circuit->u.p2p.neighbor;
44b89511
CF
1347 if (nei && nei->adj_state == ISIS_ADJ_UP
1348 && (level & nei->circuit_t)) {
af8ac8f9
CF
1349 uint8_t ne_id[7];
1350 memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
1351 LSP_PSEUDO_ID(ne_id) = 0;
1352
d62a17ae 1353 if (area->oldmetric) {
d62a17ae 1354 lsp_debug(
5d39a819
OD
1355 "ISIS (%s): Adding old-style is reach for %pSY",
1356 area->area_tag, ne_id);
af8ac8f9
CF
1357 isis_tlvs_add_oldstyle_reach(
1358 lsp->tlvs, ne_id, metric);
d62a17ae 1359 }
1360 if (area->newmetric) {
a191178d
CF
1361 uint32_t neighbor_metric;
1362 if (fabricd_tier(area) == 0) {
1363 neighbor_metric = 0xffe;
1364 } else {
1365 neighbor_metric = metric;
1366 }
1367
af8ac8f9 1368 tlvs_add_mt_p2p(lsp->tlvs, circuit,
1b3f47d0 1369 ne_id, neighbor_metric);
d62a17ae 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 }
af8ac8f9 1376 } break;
d62a17ae 1377 case CIRCUIT_T_LOOPBACK:
1378 break;
1379 default:
1380 zlog_warn("lsp_area_create: unknown circuit type");
aa4376ec 1381 }
d62a17ae 1382 }
1383
af8ac8f9 1384 lsp_build_ext_reach(lsp, area);
d62a17ae 1385
af8ac8f9
CF
1386 struct isis_tlvs *tlvs = lsp->tlvs;
1387 lsp->tlvs = NULL;
d62a17ae 1388
d07067ba 1389 lsp_adjust_stream(lsp);
af8ac8f9
CF
1390 lsp_pack_pdu(lsp);
1391 size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
1392 lsp_clear_data(lsp);
d62a17ae 1393
af8ac8f9
CF
1394 struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
1395 if (!fragments) {
1396 zlog_warn("BUG: could not fragment own LSP:");
996c9314 1397 log_multiline(LOG_WARNING, " ", "%s",
a2cac12a 1398 isis_format_tlvs(tlvs, NULL));
af8ac8f9
CF
1399 isis_free_tlvs(tlvs);
1400 return;
d62a17ae 1401 }
af8ac8f9 1402 isis_free_tlvs(tlvs);
d62a17ae 1403
789c4dfc 1404 bool fragment_overflow = false;
af8ac8f9
CF
1405 frag = lsp;
1406 for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
1407 if (node != listhead(fragments)) {
789c4dfc
CF
1408 if (LSP_FRAGMENT(frag->hdr.lsp_id) == 255) {
1409 if (!fragment_overflow) {
1410 fragment_overflow = true;
996c9314
LB
1411 zlog_warn(
1412 "ISIS (%s): Too much information for 256 fragments",
1413 area->area_tag);
789c4dfc
CF
1414 }
1415 isis_free_tlvs(tlvs);
1416 continue;
1417 }
1418
af8ac8f9
CF
1419 frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
1420 lsp, area, level);
d07067ba 1421 lsp_adjust_stream(frag);
d62a17ae 1422 }
af8ac8f9 1423 frag->tlvs = tlvs;
d62a17ae 1424 }
1425
6a154c88 1426 list_delete(&fragments);
af8ac8f9
CF
1427 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1428 area->area_tag);
d62a17ae 1429 return;
eb5d44eb 1430}
eb5d44eb 1431
1432/*
3f045a08 1433 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
eb5d44eb 1434 */
d62a17ae 1435int lsp_generate(struct isis_area *area, int level)
f390d2c7 1436{
d62a17ae 1437 struct isis_lsp *oldlsp, *newlsp;
d7c0a89a
QY
1438 uint32_t seq_num = 0;
1439 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1440 uint16_t rem_lifetime, refresh_time;
450841fe 1441 uint32_t overload_time;
d62a17ae 1442
1443 if ((area == NULL) || (area->is_type & level) != level)
1444 return ISIS_ERROR;
1445
3b0e97e1 1446 /* Check if config is still being processed */
5f6eaa9b 1447 if (event_is_scheduled(t_isis_cfg))
3b0e97e1
IL
1448 return ISIS_OK;
1449
d62a17ae 1450 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
eab88f36
K
1451
1452 memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 1453
450841fe
IL
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);
907a2395
DS
1459 event_add_timer(master, set_overload_on_start_timer,
1460 area, overload_time,
1461 &area->t_overload_on_startup_timer);
450841fe
IL
1462 }
1463 device_startup = false;
1464 }
1465
d62a17ae 1466 /* only builds the lsp if the area shares the level */
4bef0ec4 1467 oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
d62a17ae 1468 if (oldlsp) {
1469 /* FIXME: we should actually initiate a purge */
af8ac8f9 1470 seq_num = oldlsp->hdr.seqno;
4bef0ec4
DL
1471 lsp_search_and_destroy(&area->lspdb[level - 1],
1472 oldlsp->hdr.lsp_id);
d62a17ae 1473 }
1474 rem_lifetime = lsp_rem_lifetime(area, level);
f3abc412 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);
d62a17ae 1479 newlsp->area = area;
1480 newlsp->own_lsp = 1;
1481
4bef0ec4 1482 lsp_insert(&area->lspdb[level - 1], newlsp);
d62a17ae 1483 /* build_lsp_data (newlsp, area); */
1484 lsp_build(newlsp, area);
1485 /* time to calculate our checksum */
af8ac8f9 1486 lsp_seqno_update(newlsp);
d62a17ae 1487 newlsp->last_generated = time(NULL);
9b39405f 1488 lsp_flood(newlsp, NULL);
062f4d36 1489 area->lsp_gen_count[level - 1]++;
d62a17ae 1490
1491 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
1492
e16d030c 1493 EVENT_OFF(area->t_lsp_refresh[level - 1]);
d62a17ae 1494 area->lsp_regenerate_pending[level - 1] = 0;
907a2395
DS
1495 event_add_timer(master, lsp_refresh, &area->lsp_refresh_arg[level - 1],
1496 refresh_time, &area->t_lsp_refresh[level - 1]);
d62a17ae 1497
e740f9c1 1498 if (IS_DEBUG_UPDATE_PACKETS) {
5d39a819
OD
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);
d62a17ae 1505 }
1506 sched_debug(
1507 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1508 area->area_tag, level);
1509
998011fa
EDP
1510#ifndef FABRICD
1511 /* send northbound notification */
1ee746d9 1512 isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno,
1513 newlsp->last_generated);
998011fa
EDP
1514#endif /* ifndef FABRICD */
1515
d62a17ae 1516 return ISIS_OK;
eb5d44eb 1517}
1518
1519/*
9b39405f 1520 * Search own LSPs, update holding time and flood
eb5d44eb 1521 */
d62a17ae 1522static int lsp_regenerate(struct isis_area *area, int level)
eb5d44eb 1523{
4bef0ec4 1524 struct lspdb_head *head;
d62a17ae 1525 struct isis_lsp *lsp, *frag;
1526 struct listnode *node;
d7c0a89a
QY
1527 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1528 uint16_t rem_lifetime, refresh_time;
d62a17ae 1529
1530 if ((area == NULL) || (area->is_type & level) != level)
1531 return ISIS_ERROR;
1532
4bef0ec4 1533 head = &area->lspdb[level - 1];
d62a17ae 1534 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
eab88f36 1535 memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 1536
4bef0ec4 1537 lsp = lsp_search(head, lspid);
d62a17ae 1538
1539 if (!lsp) {
450971aa 1540 flog_err(EC_LIB_DEVELOPMENT,
1c50c1c0
QY
1541 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1542 area->area_tag, level);
d62a17ae 1543 return ISIS_ERROR;
1544 }
1545
1546 lsp_clear_data(lsp);
1547 lsp_build(lsp, area);
d62a17ae 1548 rem_lifetime = lsp_rem_lifetime(area, level);
af8ac8f9 1549 lsp->hdr.rem_lifetime = rem_lifetime;
d62a17ae 1550 lsp->last_generated = time(NULL);
9b39405f 1551 lsp_flood(lsp, NULL);
062f4d36 1552 area->lsp_gen_count[level - 1]++;
d62a17ae 1553 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
8f27aa27
CF
1554 if (!frag->tlvs) {
1555 /* Updating and flooding should only affect fragments
1556 * carrying data
1557 */
1558 continue;
1559 }
1560
f3abc412 1561 frag->hdr.lsp_bits =
1562 lsp_bits_generate(level, area->overload_bit,
1563 area->attached_bit_send, area);
d62a17ae 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 */
af8ac8f9 1568 frag->hdr.rem_lifetime = rem_lifetime;
0b8b6cab 1569 frag->age_out = ZERO_AGE_LIFETIME;
9b39405f 1570 lsp_flood(frag, NULL);
d62a17ae 1571 }
af8ac8f9 1572 lsp_seqno_update(lsp);
d62a17ae 1573
1574 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
907a2395
DS
1575 event_add_timer(master, lsp_refresh, &area->lsp_refresh_arg[level - 1],
1576 refresh_time, &area->t_lsp_refresh[level - 1]);
d62a17ae 1577 area->lsp_regenerate_pending[level - 1] = 0;
1578
e740f9c1 1579 if (IS_DEBUG_UPDATE_PACKETS) {
d62a17ae 1580 zlog_debug(
5d39a819
OD
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,
af8ac8f9
CF
1583 lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
1584 lsp->hdr.rem_lifetime, refresh_time);
d62a17ae 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;
eb5d44eb 1591}
1592
eb5d44eb 1593/*
3f045a08 1594 * Something has changed or periodic refresh -> regenerate LSP
eb5d44eb 1595 */
e6685141 1596static void lsp_refresh(struct event *thread)
eb5d44eb 1597{
e16d030c 1598 struct lsp_refresh_arg *arg = EVENT_ARG(thread);
d70f99e1 1599
9196731f 1600 assert(arg);
eb5d44eb 1601
9196731f 1602 struct isis_area *area = arg->area;
eb5d44eb 1603
d62a17ae 1604 assert(area);
f390d2c7 1605
9196731f 1606 int level = arg->level;
f390d2c7 1607
9196731f
CF
1608 area->t_lsp_refresh[level - 1] = NULL;
1609 area->lsp_regenerate_pending[level - 1] = 0;
1610
1611 if ((area->is_type & level) == 0)
cc9f21da 1612 return;
3f045a08 1613
690497fb
G
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)) {
f93025e1
CF
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__);
cc9f21da 1625 return;
f93025e1
CF
1626 }
1627
d62a17ae 1628 sched_debug(
9196731f
CF
1629 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1630 area->area_tag, level);
cc9f21da 1631 lsp_regenerate(area, level);
eb5d44eb 1632}
1633
691f3e76 1634int _lsp_regenerate_schedule(struct isis_area *area, int level,
f93025e1
CF
1635 int all_pseudo, bool postpone,
1636 const char *func, const char *file,
1637 int line)
eb5d44eb 1638{
d62a17ae 1639 struct isis_lsp *lsp;
d7c0a89a 1640 uint8_t id[ISIS_SYS_ID_LEN + 2];
d62a17ae 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(
3efd0893 1651 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
d62a17ae 1652 area->area_tag, circuit_t2string(level),
691f3e76
CF
1653 all_pseudo ? "" : "not ",
1654 func, file, line);
d62a17ae 1655
eab88f36 1656 memcpy(id, area->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 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
f93025e1
CF
1664 if (postpone) {
1665 monotime(&area->last_lsp_refresh_event[lvl - 1]);
1666 }
1667
d62a17ae 1668 sched_debug(
1669 "ISIS (%s): Checking whether L%d needs to be scheduled",
1670 area->area_tag, lvl);
1671
690497fb
G
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 */
4f830a07 1678 struct timeval remain = event_timer_remain(
d62a17ae 1679 area->t_lsp_refresh[lvl - 1]);
1680 sched_debug(
3efd0893 1681 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
d62a17ae 1682 area->area_tag, (long long)remain.tv_sec,
1683 (long long)remain.tv_usec / 1000);
1684 continue;
1685 }
1686
4bef0ec4 1687 lsp = lsp_search(&area->lspdb[lvl - 1], id);
d62a17ae 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);
e16d030c 1702 EVENT_OFF(area->t_lsp_refresh[lvl - 1]);
d62a17ae 1703 diff = now - lsp->last_generated;
690497fb
G
1704 if (diff < area->lsp_gen_interval[lvl - 1]
1705 && !(area->bfd_signalled_down)) {
d62a17ae 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 /*
690497fb 1713 * Schedule LSP refresh ASAP
d62a17ae 1714 */
690497fb
G
1715 if (area->bfd_signalled_down) {
1716 sched_debug(
ec7b1425 1717 "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
690497fb
G
1718 area->area_tag);
1719 area->bfd_signalled_down = false;
1720 area->bfd_force_spf_refresh = true;
d2232b3e 1721 timeout = 0;
690497fb 1722 } else {
d2232b3e
EDP
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);
690497fb 1737 }
d62a17ae 1738 }
1739
1740 area->lsp_regenerate_pending[lvl - 1] = 1;
907a2395
DS
1741 event_add_timer_msec(master, lsp_refresh,
1742 &area->lsp_refresh_arg[lvl - 1], timeout,
1743 &area->t_lsp_refresh[lvl - 1]);
d62a17ae 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;
eb5d44eb 1752}
1753
1754/*
1755 * Funcs for pseudonode LSPs
1756 */
1757
1758/*
d62a17ae 1759 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
eb5d44eb 1760 */
d62a17ae 1761static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
1762 int level)
eb5d44eb 1763{
d62a17ae 1764 struct isis_adjacency *adj;
d62a17ae 1765 struct list *adj_list;
1766 struct listnode *node;
1767 struct isis_area *area = circuit->area;
173f8887 1768 uint16_t mtid;
d62a17ae 1769
af8ac8f9
CF
1770 lsp_clear_data(lsp);
1771 lsp->tlvs = isis_alloc_tlvs();
d62a17ae 1772 lsp_debug(
5d39a819
OD
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);
d62a17ae 1776
1777 lsp->level = level;
1778 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
f3abc412 1779 lsp->hdr.lsp_bits = lsp_bits_generate(
1780 level, 0, circuit->area->attached_bit_send, area);
d62a17ae 1781
1782 /*
1783 * add self to IS neighbours
1784 */
af8ac8f9
CF
1785 uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
1786
eab88f36 1787 memcpy(ne_id, area->isis->sysid, ISIS_SYS_ID_LEN);
af8ac8f9 1788 LSP_PSEUDO_ID(ne_id) = 0;
d62a17ae 1789
af8ac8f9
CF
1790 if (circuit->area->oldmetric) {
1791 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
5d39a819
OD
1792 lsp_debug("ISIS (%s): Adding %pPN as old-style neighbor (self)",
1793 area->area_tag, ne_id);
d62a17ae 1794 }
1795 if (circuit->area->newmetric) {
173f8887
OD
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);
5d39a819
OD
1801 lsp_debug("ISIS (%s): Adding %pPN as te-style neighbor (self)",
1802 area->area_tag, ne_id);
d62a17ae 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)) {
af8ac8f9 1809 if (!(adj->level & level)) {
d62a17ae 1810 lsp_debug(
5d39a819
OD
1811 "ISIS (%s): Ignoring neighbor %pSY, level does not intersect",
1812 area->area_tag, adj->sysid);
af8ac8f9 1813 continue;
f390d2c7 1814 }
d62a17ae 1815
af8ac8f9
CF
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(
5d39a819
OD
1824 "ISIS (%s): Ignoring neighbor %pSY, level does not match",
1825 area->area_tag, adj->sysid);
af8ac8f9
CF
1826 continue;
1827 }
d62a17ae 1828
af8ac8f9
CF
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(
5d39a819
OD
1833 "ISIS (%s): Adding %pPN as old-style neighbor (peer)",
1834 area->area_tag, ne_id);
af8ac8f9
CF
1835 }
1836 if (circuit->area->newmetric) {
1837 isis_tlvs_add_extended_reach(lsp->tlvs,
1838 ISIS_MT_IPV4_UNICAST,
d607c409 1839 ne_id, 0, NULL);
af8ac8f9 1840 lsp_debug(
5d39a819
OD
1841 "ISIS (%s): Adding %pPN as te-style neighbor (peer)",
1842 area->area_tag, ne_id);
af8ac8f9
CF
1843 }
1844 }
6a154c88 1845 list_delete(&adj_list);
d62a17ae 1846 return;
eb5d44eb 1847}
1848
d62a17ae 1849int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
3f045a08 1850{
4bef0ec4 1851 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
d62a17ae 1852 struct isis_lsp *lsp;
d7c0a89a
QY
1853 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1854 uint16_t rem_lifetime, refresh_time;
d62a17ae 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
99e5d4af 1862 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 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 */
4bef0ec4 1869 if (lsp_search(head, lsp_id))
d62a17ae 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,
f3abc412 1875 lsp_bits_generate(circuit->area->is_type, 0,
1876 circuit->area->attached_bit_send,
1877 circuit->area),
1878 0, NULL, level);
d62a17ae 1879 lsp->area = circuit->area;
1880
1881 lsp_build_pseudo(lsp, circuit, level);
af8ac8f9 1882 lsp_pack_pdu(lsp);
d62a17ae 1883 lsp->own_lsp = 1;
4bef0ec4 1884 lsp_insert(head, lsp);
9b39405f 1885 lsp_flood(lsp, NULL);
d62a17ae 1886
1887 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
e16d030c 1888 EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
d62a17ae 1889 circuit->lsp_regenerate_pending[level - 1] = 0;
1890 if (level == IS_LEVEL_1)
907a2395
DS
1891 event_add_timer(master, lsp_l1_refresh_pseudo, circuit,
1892 refresh_time,
1893 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
d62a17ae 1894 else if (level == IS_LEVEL_2)
907a2395
DS
1895 event_add_timer(master, lsp_l2_refresh_pseudo, circuit,
1896 refresh_time,
1897 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
d62a17ae 1898
e740f9c1 1899 if (IS_DEBUG_UPDATE_PACKETS) {
d62a17ae 1900 zlog_debug(
5d39a819
OD
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,
af8ac8f9 1904 lsp->hdr.rem_lifetime, refresh_time);
d62a17ae 1905 }
1906
1907 return ISIS_OK;
3f045a08
JB
1908}
1909
d62a17ae 1910static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
eb5d44eb 1911{
4bef0ec4 1912 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
d62a17ae 1913 struct isis_lsp *lsp;
d7c0a89a
QY
1914 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1915 uint16_t rem_lifetime, refresh_time;
d62a17ae 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
99e5d4af 1923 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 1924 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1925 LSP_FRAGMENT(lsp_id) = 0;
1926
4bef0ec4 1927 lsp = lsp_search(head, lsp_id);
d62a17ae 1928
1929 if (!lsp) {
450971aa 1930 flog_err(EC_LIB_DEVELOPMENT,
5d39a819
OD
1931 "lsp_regenerate_pseudo: no l%d LSP %pLS found!", level,
1932 lsp_id);
d62a17ae 1933 return ISIS_ERROR;
1934 }
d62a17ae 1935
d62a17ae 1936 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
af8ac8f9
CF
1937 lsp->hdr.rem_lifetime = rem_lifetime;
1938 lsp_build_pseudo(lsp, circuit, level);
1939 lsp_inc_seqno(lsp, 0);
d62a17ae 1940 lsp->last_generated = time(NULL);
9b39405f 1941 lsp_flood(lsp, NULL);
d62a17ae 1942
1943 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1944 if (level == IS_LEVEL_1)
907a2395
DS
1945 event_add_timer(master, lsp_l1_refresh_pseudo, circuit,
1946 refresh_time,
1947 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
d62a17ae 1948 else if (level == IS_LEVEL_2)
907a2395
DS
1949 event_add_timer(master, lsp_l2_refresh_pseudo, circuit,
1950 refresh_time,
1951 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
d62a17ae 1952
e740f9c1 1953 if (IS_DEBUG_UPDATE_PACKETS) {
d62a17ae 1954 zlog_debug(
5d39a819
OD
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,
af8ac8f9 1958 lsp->hdr.rem_lifetime, refresh_time);
d62a17ae 1959 }
1960
1961 return ISIS_OK;
eb5d44eb 1962}
1963
3f045a08
JB
1964/*
1965 * Something has changed or periodic refresh -> regenerate pseudo LSP
1966 */
e6685141 1967static void lsp_l1_refresh_pseudo(struct event *thread)
eb5d44eb 1968{
d62a17ae 1969 struct isis_circuit *circuit;
d7c0a89a 1970 uint8_t id[ISIS_SYS_ID_LEN + 2];
eb5d44eb 1971
e16d030c 1972 circuit = EVENT_ARG(thread);
f390d2c7 1973
d62a17ae 1974 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
1975 circuit->lsp_regenerate_pending[0] = 0;
13c48f72 1976
d62a17ae 1977 if ((circuit->u.bc.is_dr[0] == 0)
1978 || (circuit->is_type & IS_LEVEL_1) == 0) {
99e5d4af 1979 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 1980 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1981 LSP_FRAGMENT(id) = 0;
1982 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
cc9f21da 1983 return;
d62a17ae 1984 }
eb5d44eb 1985
cc9f21da 1986 lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
eb5d44eb 1987}
1988
e6685141 1989static void lsp_l2_refresh_pseudo(struct event *thread)
eb5d44eb 1990{
d62a17ae 1991 struct isis_circuit *circuit;
d7c0a89a 1992 uint8_t id[ISIS_SYS_ID_LEN + 2];
f390d2c7 1993
e16d030c 1994 circuit = EVENT_ARG(thread);
f390d2c7 1995
d62a17ae 1996 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
1997 circuit->lsp_regenerate_pending[1] = 0;
13c48f72 1998
d62a17ae 1999 if ((circuit->u.bc.is_dr[1] == 0)
2000 || (circuit->is_type & IS_LEVEL_2) == 0) {
99e5d4af 2001 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 2002 LSP_PSEUDO_ID(id) = circuit->circuit_id;
2003 LSP_FRAGMENT(id) = 0;
2004 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
cc9f21da 2005 return;
d62a17ae 2006 }
eb5d44eb 2007
cc9f21da 2008 lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
eb5d44eb 2009}
2010
d62a17ae 2011int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
eb5d44eb 2012{
d62a17ae 2013 struct isis_lsp *lsp;
d7c0a89a 2014 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
d62a17ae 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
eab88f36 2029 memcpy(lsp_id, area->isis->sysid, ISIS_SYS_ID_LEN);
d62a17ae 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]) {
4f830a07 2053 struct timeval remain = event_timer_remain(
d62a17ae 2054 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2055 sched_debug(
3efd0893 2056 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
d62a17ae 2057 area->area_tag, (long long)remain.tv_sec,
2058 (long long)remain.tv_usec / 1000);
2059 continue;
2060 }
2061
4bef0ec4 2062 lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
d62a17ae 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);
e16d030c 2077 EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
d62a17ae 2078 diff = now - lsp->last_generated;
2079 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
9d303b37
DL
2080 timeout =
2081 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
2082 - diff);
d62a17ae 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(
3efd0893 2089 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
d62a17ae 2090 area->area_tag, timeout);
2091 }
2092
2093 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2094
2095 if (lvl == IS_LEVEL_1) {
907a2395 2096 event_add_timer_msec(
d62a17ae 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) {
907a2395 2100 event_add_timer_msec(
d62a17ae 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;
f390d2c7 2107}
eb5d44eb 2108
2109/*
2110 * Walk through LSPs for an area
2111 * - set remaining lifetime
eb5d44eb 2112 */
e6685141 2113void lsp_tick(struct event *thread)
eb5d44eb 2114{
d62a17ae 2115 struct isis_area *area;
d62a17ae 2116 struct isis_lsp *lsp;
d62a17ae 2117 int level;
d7c0a89a 2118 uint16_t rem_lifetime;
8e6fb83b 2119 bool fabricd_sync_incomplete = false;
d62a17ae 2120
e16d030c 2121 area = EVENT_ARG(thread);
d62a17ae 2122 assert(area);
2123 area->t_tick = NULL;
907a2395 2124 event_add_timer(master, lsp_tick, area, 1, &area->t_tick);
d62a17ae 2125
8e6fb83b
CF
2126 struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
2127
d62a17ae 2128 /*
9b39405f 2129 * Remove LSPs which have aged out
d62a17ae 2130 */
2131 for (level = 0; level < ISIS_LEVELS; level++) {
4bef0ec4 2132 struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
81fddbe7 2133 frr_each_from (lspdb, &area->lspdb[level], lsp, next) {
4bef0ec4
DL
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);
d62a17ae 2145
4bef0ec4
DL
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);
d9884a75 2163 isis_te_lsp_event(lsp, LSP_TICK);
4bef0ec4 2164 }
0c77e178 2165
4bef0ec4
DL
2166 if (lsp->age_out == 0) {
2167 zlog_debug(
5d39a819 2168 "ISIS-Upd (%s): L%u LSP %pLS seq 0x%08x aged out",
4bef0ec4 2169 area->area_tag, lsp->level,
5d39a819 2170 lsp->hdr.lsp_id, lsp->hdr.seqno);
4bef0ec4
DL
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 }
8e6fb83b 2189
4bef0ec4
DL
2190 if (fabricd_init_c && lsp) {
2191 fabricd_sync_incomplete |=
2192 ISIS_CHECK_FLAG(lsp->SSNflags,
2193 fabricd_init_c);
d62a17ae 2194 }
2195 }
2196 }
2197
9b39405f
CF
2198 if (fabricd_init_c
2199 && !fabricd_sync_incomplete
2200 && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
8e6fb83b 2201 fabricd_initial_sync_finish(area);
9b39405f 2202 }
eb5d44eb 2203}
2204
d7c0a89a 2205void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
eb5d44eb 2206{
d62a17ae 2207 struct isis_lsp *lsp;
d62a17ae 2208
4bef0ec4 2209 lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
d62a17ae 2210 if (!lsp)
2211 return;
2212
2c92bee4 2213 lsp_purge(lsp, level, NULL);
eb5d44eb 2214}
2215
2216/*
d62a17ae 2217 * Purge own LSP that is received and we don't have.
eb5d44eb 2218 * -> Do as in 7.3.16.4
2219 */
af8ac8f9 2220void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
d62a17ae 2221 struct isis_area *area)
eb5d44eb 2222{
d62a17ae 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;
d07067ba 2231 lsp_adjust_stream(lsp);
af8ac8f9 2232 lsp->age_out = ZERO_AGE_LIFETIME;
6f004b60 2233 lsp->area->lsp_purge_count[level - 1]++;
d62a17ae 2234
af8ac8f9
CF
2235 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
2236 lsp->hdr.rem_lifetime = 0;
d62a17ae 2237
2c92bee4
CF
2238 lsp_purge_add_poi(lsp, NULL);
2239
af8ac8f9 2240 lsp_pack_pdu(lsp);
d62a17ae 2241
4bef0ec4 2242 lsp_insert(&area->lspdb[lsp->level - 1], lsp);
9b39405f 2243 lsp_flood(lsp, NULL);
d62a17ae 2244
2245 return;
eb5d44eb 2246}
2247
9b39405f 2248void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
3f045a08 2249{
d62a17ae 2250 struct listnode *node;
2251 struct isis_circuit *circuit;
3f045a08 2252
d62a17ae 2253 assert(lsp);
3f045a08 2254
9b39405f
CF
2255 if (!lsp->area)
2256 return;
3f045a08 2257
9b39405f
CF
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);
d62a17ae 2265 }
2266 }
3f045a08 2267}
9b39405f 2268
ddb33326
CF
2269void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
2270 const char *func, const char *file, int line)
9b39405f 2271{
e740f9c1 2272 if (IS_DEBUG_FLOODING) {
5d39a819
OD
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);
ddb33326
CF
2277 }
2278
37212c41 2279 if (!fabricd)
9d224819 2280 lsp_set_all_srmflags(lsp, true);
37212c41 2281 else
1eb7c3a1 2282 fabricd_lsp_flood(lsp, circuit);
37212c41
CF
2283
2284 if (circuit)
2285 isis_tx_queue_del(circuit->tx_queue, lsp);
9b39405f 2286}
a5b5e946
CF
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);
77d73edf 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
a5b5e946
CF
2297 return 0;
2298}
2299
98a49636
RW
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
d9884a75 2314 /* Parse LSP */
98a49636
RW
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
d9884a75
OD
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;
98a49636 2389
d9884a75
OD
2390 if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
2391 arg)
2392 == LSP_ITER_STOP)
2393 return LSP_ITER_STOP;
2394 }
98a49636
RW
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
d9884a75 2415 /* Parse LSP */
98a49636
RW
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
d9884a75
OD
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;
98a49636 2452
d9884a75
OD
2453 if (isis_lsp_iterate_is_reach(frag, mtid, cb, arg)
2454 == LSP_ITER_STOP)
2455 return LSP_ITER_STOP;
2456 }
98a49636
RW
2457
2458 return LSP_ITER_CONTINUE;
2459}
2460
a5b5e946
CF
2461void lsp_init(void)
2462{
49b27ea2 2463 device_startup = true;
a5b5e946
CF
2464 hook_register(isis_adj_state_change_hook,
2465 lsp_handle_adj_state_change);
2466}