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