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