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