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