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