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