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