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