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