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