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