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