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