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