]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
bgpd: IPv6 session flapping with MP_REACH_NLRI and 0.0.0.0 in NEXT_HOP attribute
[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_te.h"
56 #include "isisd/isis_mt.h"
57 #include "isisd/isis_tlvs.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 for_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 for_each (lspdb, head, lsp) {
686 lsp_print(lsp, vty, dynhost);
687 lsp_count++;
688 }
689 } else if (detail == ISIS_UI_LEVEL_DETAIL) {
690 for_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
785 struct prefix_ipv6 *p, *src_p;
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 if (area->ip_circuits > 0) {
867 lsp_debug(
868 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
869 area->area_tag);
870 nlpids.nlpids[nlpids.count] = NLPID_IP;
871 nlpids.count++;
872 }
873 if (area->ipv6_circuits > 0) {
874 lsp_debug(
875 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
876 area->area_tag);
877 nlpids.nlpids[nlpids.count] = NLPID_IPV6;
878 nlpids.count++;
879 }
880 isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
881 }
882
883 if (area_is_mt(area)) {
884 lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
885
886 struct isis_area_mt_setting **mt_settings;
887 unsigned int mt_count;
888
889 mt_settings = area_mt_settings(area, &mt_count);
890 for (unsigned int i = 0; i < mt_count; i++) {
891 isis_tlvs_add_mt_router_info(
892 lsp->tlvs, mt_settings[i]->mtid,
893 mt_settings[i]->overload, false);
894 lsp_debug("ISIS (%s): MT %s", area->area_tag,
895 isis_mtid2str(mt_settings[i]->mtid));
896 }
897 } else {
898 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
899 area->area_tag);
900 }
901 /* Dynamic Hostname */
902 if (area->dynhostname) {
903 isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
904 lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
905 area->area_tag, cmd_hostname_get());
906 } else {
907 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
908 area->area_tag);
909 }
910
911 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
912 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
913 * into
914 * LSP and this address is same as router id. */
915 if (isis->router_id != 0) {
916 struct in_addr id = {.s_addr = isis->router_id};
917 inet_ntop(AF_INET, &id, buf, sizeof(buf));
918 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
919 area->area_tag, buf);
920 isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
921
922 /* Exactly same data is put into TE router ID TLV, but only if
923 * new style
924 * TLV's are in use. */
925 if (area->newmetric) {
926
927 lsp_debug(
928 "ISIS (%s): Adding router ID also as TE router ID tlv.",
929 area->area_tag);
930 isis_tlvs_set_te_router_id(lsp->tlvs, &id);
931 }
932 } else {
933 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
934 area->area_tag);
935 }
936
937 lsp_debug("ISIS (%s): Adding circuit specific information.",
938 area->area_tag);
939
940 if (fabricd) {
941 lsp_debug(
942 "ISIS (%s): Adding tier %" PRIu8 " spine-leaf-extension tlv.",
943 area->area_tag, fabricd_tier(area));
944 isis_tlvs_add_spine_leaf(lsp->tlvs, fabricd_tier(area), true,
945 false, false, false);
946 }
947
948 struct isis_circuit *circuit;
949 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
950 if (!circuit->interface)
951 lsp_debug(
952 "ISIS (%s): Processing %s circuit %p with unknown interface",
953 area->area_tag,
954 circuit_type2string(circuit->circ_type),
955 circuit);
956 else
957 lsp_debug("ISIS (%s): Processing %s circuit %s",
958 area->area_tag,
959 circuit_type2string(circuit->circ_type),
960 circuit->interface->name);
961
962 if (circuit->state != C_STATE_UP) {
963 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
964 area->area_tag);
965 continue;
966 }
967
968 uint32_t metric = area->oldmetric
969 ? circuit->metric[level - 1]
970 : circuit->te_metric[level - 1];
971
972 if (circuit->ip_router && circuit->ip_addrs
973 && circuit->ip_addrs->count > 0) {
974 lsp_debug(
975 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
976 area->area_tag);
977 struct listnode *ipnode;
978 struct prefix_ipv4 *ipv4;
979 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
980 ipv4)) {
981 if (area->oldmetric) {
982 lsp_debug(
983 "ISIS (%s): Adding old-style IP reachability for %s",
984 area->area_tag,
985 prefix2str(ipv4, buf,
986 sizeof(buf)));
987 isis_tlvs_add_oldstyle_ip_reach(
988 lsp->tlvs, ipv4, metric);
989 }
990
991 if (area->newmetric) {
992 lsp_debug(
993 "ISIS (%s): Adding te-style IP reachability for %s",
994 area->area_tag,
995 prefix2str(ipv4, buf,
996 sizeof(buf)));
997 isis_tlvs_add_extended_ip_reach(
998 lsp->tlvs, ipv4, metric);
999 }
1000 }
1001 }
1002
1003 if (circuit->ipv6_router && circuit->ipv6_non_link
1004 && circuit->ipv6_non_link->count > 0) {
1005 struct listnode *ipnode;
1006 struct prefix_ipv6 *ipv6;
1007 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1008 ipnode, ipv6)) {
1009 lsp_debug(
1010 "ISIS (%s): Adding IPv6 reachability for %s",
1011 area->area_tag,
1012 prefix2str(ipv6, buf, sizeof(buf)));
1013 isis_tlvs_add_ipv6_reach(
1014 lsp->tlvs,
1015 isis_area_ipv6_topology(area), ipv6,
1016 metric);
1017 }
1018 }
1019
1020 switch (circuit->circ_type) {
1021 case CIRCUIT_T_BROADCAST:
1022 if (level & circuit->is_type) {
1023 uint8_t *ne_id =
1024 (level == IS_LEVEL_1)
1025 ? circuit->u.bc.l1_desig_is
1026 : circuit->u.bc.l2_desig_is;
1027
1028 if (LSP_PSEUDO_ID(ne_id)) {
1029 if (area->oldmetric) {
1030 lsp_debug(
1031 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1032 area->area_tag,
1033 sysid_print(ne_id),
1034 LSP_PSEUDO_ID(ne_id));
1035 isis_tlvs_add_oldstyle_reach(
1036 lsp->tlvs, ne_id,
1037 metric);
1038 }
1039 if (area->newmetric) {
1040 uint8_t subtlvs[256];
1041 uint8_t subtlv_len;
1042
1043 if (IS_MPLS_TE(area->mta)
1044 && circuit->interface
1045 && HAS_LINK_PARAMS(
1046 circuit->interface))
1047 subtlv_len = add_te_subtlvs(
1048 subtlvs,
1049 circuit->mtc);
1050 else
1051 subtlv_len = 0;
1052
1053 tlvs_add_mt_bcast(
1054 lsp->tlvs, circuit,
1055 level, ne_id, metric,
1056 subtlvs, subtlv_len);
1057 }
1058 }
1059 } else {
1060 lsp_debug(
1061 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1062 area->area_tag);
1063 }
1064 break;
1065 case CIRCUIT_T_P2P: {
1066 struct isis_adjacency *nei = circuit->u.p2p.neighbor;
1067 if (nei && nei->adj_state == ISIS_ADJ_UP
1068 && (level & nei->circuit_t)) {
1069 uint8_t ne_id[7];
1070 memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
1071 LSP_PSEUDO_ID(ne_id) = 0;
1072
1073 if (area->oldmetric) {
1074 lsp_debug(
1075 "ISIS (%s): Adding old-style is reach for %s",
1076 area->area_tag,
1077 sysid_print(ne_id));
1078 isis_tlvs_add_oldstyle_reach(
1079 lsp->tlvs, ne_id, metric);
1080 }
1081 if (area->newmetric) {
1082 uint8_t subtlvs[256];
1083 uint8_t subtlv_len;
1084
1085 if (IS_MPLS_TE(area->mta)
1086 && circuit->interface != NULL
1087 && HAS_LINK_PARAMS(
1088 circuit->interface))
1089 /* Update Local and Remote IP
1090 * address for MPLS TE circuit
1091 * parameters */
1092 /* NOTE sure that it is the
1093 * pertinent place for that
1094 * updates */
1095 /* Local IP address could be
1096 * updated in isis_circuit.c -
1097 * isis_circuit_add_addr() */
1098 /* But, where update remote IP
1099 * address ? in isis_pdu.c -
1100 * process_p2p_hello() ? */
1101
1102 /* Add SubTLVs & Adjust real
1103 * size of SubTLVs */
1104 subtlv_len = add_te_subtlvs(
1105 subtlvs, circuit->mtc);
1106 else
1107 /* Or keep only TE metric with
1108 * no SubTLVs if MPLS_TE is off
1109 */
1110 subtlv_len = 0;
1111
1112 uint32_t neighbor_metric;
1113 if (fabricd_tier(area) == 0) {
1114 neighbor_metric = 0xffe;
1115 } else {
1116 neighbor_metric = metric;
1117 }
1118
1119 tlvs_add_mt_p2p(lsp->tlvs, circuit,
1120 ne_id, neighbor_metric,
1121 subtlvs, subtlv_len);
1122 }
1123 } else {
1124 lsp_debug(
1125 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1126 area->area_tag);
1127 }
1128 } break;
1129 case CIRCUIT_T_LOOPBACK:
1130 break;
1131 default:
1132 zlog_warn("lsp_area_create: unknown circuit type");
1133 }
1134 }
1135
1136 lsp_build_ext_reach(lsp, area);
1137
1138 struct isis_tlvs *tlvs = lsp->tlvs;
1139 lsp->tlvs = NULL;
1140
1141 lsp_adjust_stream(lsp);
1142 lsp_pack_pdu(lsp);
1143 size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
1144 lsp_clear_data(lsp);
1145
1146 struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
1147 if (!fragments) {
1148 zlog_warn("BUG: could not fragment own LSP:");
1149 log_multiline(LOG_WARNING, " ", "%s",
1150 isis_format_tlvs(tlvs));
1151 isis_free_tlvs(tlvs);
1152 return;
1153 }
1154 isis_free_tlvs(tlvs);
1155
1156 bool fragment_overflow = false;
1157 frag = lsp;
1158 for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
1159 if (node != listhead(fragments)) {
1160 if (LSP_FRAGMENT(frag->hdr.lsp_id) == 255) {
1161 if (!fragment_overflow) {
1162 fragment_overflow = true;
1163 zlog_warn(
1164 "ISIS (%s): Too much information for 256 fragments",
1165 area->area_tag);
1166 }
1167 isis_free_tlvs(tlvs);
1168 continue;
1169 }
1170
1171 frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
1172 lsp, area, level);
1173 lsp_adjust_stream(frag);
1174 }
1175 frag->tlvs = tlvs;
1176 }
1177
1178 list_delete(&fragments);
1179 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1180 area->area_tag);
1181 return;
1182 }
1183
1184 /*
1185 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1186 */
1187 int lsp_generate(struct isis_area *area, int level)
1188 {
1189 struct isis_lsp *oldlsp, *newlsp;
1190 uint32_t seq_num = 0;
1191 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1192 uint16_t rem_lifetime, refresh_time;
1193
1194 if ((area == NULL) || (area->is_type & level) != level)
1195 return ISIS_ERROR;
1196
1197 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
1198 memcpy(&lspid, isis->sysid, ISIS_SYS_ID_LEN);
1199
1200 /* only builds the lsp if the area shares the level */
1201 oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
1202 if (oldlsp) {
1203 /* FIXME: we should actually initiate a purge */
1204 seq_num = oldlsp->hdr.seqno;
1205 lsp_search_and_destroy(&area->lspdb[level - 1],
1206 oldlsp->hdr.lsp_id);
1207 }
1208 rem_lifetime = lsp_rem_lifetime(area, level);
1209 newlsp =
1210 lsp_new(area, lspid, rem_lifetime, seq_num,
1211 area->is_type | area->overload_bit | area->attached_bit,
1212 0, NULL, level);
1213 newlsp->area = area;
1214 newlsp->own_lsp = 1;
1215
1216 lsp_insert(&area->lspdb[level - 1], newlsp);
1217 /* build_lsp_data (newlsp, area); */
1218 lsp_build(newlsp, area);
1219 /* time to calculate our checksum */
1220 lsp_seqno_update(newlsp);
1221 newlsp->last_generated = time(NULL);
1222 lsp_flood(newlsp, NULL);
1223 area->lsp_gen_count[level - 1]++;
1224
1225 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
1226
1227 THREAD_TIMER_OFF(area->t_lsp_refresh[level - 1]);
1228 area->lsp_regenerate_pending[level - 1] = 0;
1229 thread_add_timer(master, lsp_refresh,
1230 &area->lsp_refresh_arg[level - 1], refresh_time,
1231 &area->t_lsp_refresh[level - 1]);
1232
1233 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1234 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1235 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1236 ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
1237 area->area_tag, level,
1238 rawlspid_print(newlsp->hdr.lsp_id),
1239 newlsp->hdr.pdu_len, newlsp->hdr.seqno,
1240 newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
1241 refresh_time);
1242 }
1243 sched_debug(
1244 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1245 area->area_tag, level);
1246
1247 #ifndef FABRICD
1248 /* send northbound notification */
1249 isis_notif_lsp_gen(area, rawlspid_print(newlsp->hdr.lsp_id),
1250 newlsp->hdr.seqno, newlsp->last_generated);
1251 #endif /* ifndef FABRICD */
1252
1253 return ISIS_OK;
1254 }
1255
1256 /*
1257 * Search own LSPs, update holding time and flood
1258 */
1259 static int lsp_regenerate(struct isis_area *area, int level)
1260 {
1261 struct lspdb_head *head;
1262 struct isis_lsp *lsp, *frag;
1263 struct listnode *node;
1264 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1265 uint16_t rem_lifetime, refresh_time;
1266
1267 if ((area == NULL) || (area->is_type & level) != level)
1268 return ISIS_ERROR;
1269
1270 head = &area->lspdb[level - 1];
1271
1272 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
1273 memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
1274
1275 lsp = lsp_search(head, lspid);
1276
1277 if (!lsp) {
1278 flog_err(EC_LIB_DEVELOPMENT,
1279 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1280 area->area_tag, level);
1281 return ISIS_ERROR;
1282 }
1283
1284 lsp_clear_data(lsp);
1285 lsp_build(lsp, area);
1286 rem_lifetime = lsp_rem_lifetime(area, level);
1287 lsp->hdr.rem_lifetime = rem_lifetime;
1288 lsp->last_generated = time(NULL);
1289 lsp_flood(lsp, NULL);
1290 area->lsp_gen_count[level - 1]++;
1291 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
1292 if (!frag->tlvs) {
1293 /* Updating and flooding should only affect fragments
1294 * carrying data
1295 */
1296 continue;
1297 }
1298
1299 frag->hdr.lsp_bits = lsp_bits_generate(
1300 level, area->overload_bit, area->attached_bit);
1301 /* Set the lifetime values of all the fragments to the same
1302 * value,
1303 * so that no fragment expires before the lsp is refreshed.
1304 */
1305 frag->hdr.rem_lifetime = rem_lifetime;
1306 frag->age_out = ZERO_AGE_LIFETIME;
1307 lsp_flood(frag, NULL);
1308 }
1309 lsp_seqno_update(lsp);
1310
1311 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1312 thread_add_timer(master, lsp_refresh,
1313 &area->lsp_refresh_arg[level - 1], refresh_time,
1314 &area->t_lsp_refresh[level - 1]);
1315 area->lsp_regenerate_pending[level - 1] = 0;
1316
1317 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1318 zlog_debug(
1319 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1320 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1321 ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
1322 area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
1323 lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
1324 lsp->hdr.rem_lifetime, refresh_time);
1325 }
1326 sched_debug(
1327 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1328 area->area_tag, level);
1329
1330 return ISIS_OK;
1331 }
1332
1333 /*
1334 * Something has changed or periodic refresh -> regenerate LSP
1335 */
1336 static int lsp_refresh(struct thread *thread)
1337 {
1338 struct lsp_refresh_arg *arg = THREAD_ARG(thread);
1339
1340 assert(arg);
1341
1342 struct isis_area *area = arg->area;
1343
1344 assert(area);
1345
1346 int level = arg->level;
1347
1348 area->t_lsp_refresh[level - 1] = NULL;
1349 area->lsp_regenerate_pending[level - 1] = 0;
1350
1351 if ((area->is_type & level) == 0)
1352 return ISIS_ERROR;
1353
1354 if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL) < 100000L) {
1355 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1356 area->area_tag, level);
1357 _lsp_regenerate_schedule(area, level, 0, false,
1358 __func__, __FILE__, __LINE__);
1359 return 0;
1360 }
1361
1362 sched_debug(
1363 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1364 area->area_tag, level);
1365 return lsp_regenerate(area, level);
1366 }
1367
1368 int _lsp_regenerate_schedule(struct isis_area *area, int level,
1369 int all_pseudo, bool postpone,
1370 const char *func, const char *file,
1371 int line)
1372 {
1373 struct isis_lsp *lsp;
1374 uint8_t id[ISIS_SYS_ID_LEN + 2];
1375 time_t now, diff;
1376 long timeout;
1377 struct listnode *cnode;
1378 struct isis_circuit *circuit;
1379 int lvl;
1380
1381 if (area == NULL)
1382 return ISIS_ERROR;
1383
1384 sched_debug(
1385 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs"
1386 " Caller: %s %s:%d",
1387 area->area_tag, circuit_t2string(level),
1388 all_pseudo ? "" : "not ",
1389 func, file, line);
1390
1391 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
1392 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
1393 now = time(NULL);
1394
1395 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1396 if (!((level & lvl) && (area->is_type & lvl)))
1397 continue;
1398
1399 if (postpone) {
1400 monotime(&area->last_lsp_refresh_event[lvl - 1]);
1401 }
1402
1403 sched_debug(
1404 "ISIS (%s): Checking whether L%d needs to be scheduled",
1405 area->area_tag, lvl);
1406
1407 if (area->lsp_regenerate_pending[lvl - 1]) {
1408 struct timeval remain = thread_timer_remain(
1409 area->t_lsp_refresh[lvl - 1]);
1410 sched_debug(
1411 "ISIS (%s): Regeneration is already pending, nothing todo."
1412 " (Due in %lld.%03lld seconds)",
1413 area->area_tag, (long long)remain.tv_sec,
1414 (long long)remain.tv_usec / 1000);
1415 continue;
1416 }
1417
1418 lsp = lsp_search(&area->lspdb[lvl - 1], id);
1419 if (!lsp) {
1420 sched_debug(
1421 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1422 area->area_tag);
1423 continue;
1424 }
1425
1426 /*
1427 * Throttle avoidance
1428 */
1429 sched_debug(
1430 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1431 area->area_tag, (long long)lsp->last_generated,
1432 (long long)now);
1433 THREAD_TIMER_OFF(area->t_lsp_refresh[lvl - 1]);
1434 diff = now - lsp->last_generated;
1435 if (diff < area->lsp_gen_interval[lvl - 1]) {
1436 timeout =
1437 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
1438 sched_debug(
1439 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1440 area->area_tag, timeout);
1441 } else {
1442 /*
1443 * lsps are not regenerated if lsp_regenerate function
1444 * is called
1445 * directly. However if the lsp_regenerate call is
1446 * queued for
1447 * later execution it works.
1448 */
1449 timeout = 100;
1450 sched_debug(
1451 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1452 " Scheduling for execution in %ld ms.",
1453 area->area_tag, timeout);
1454 }
1455
1456 area->lsp_regenerate_pending[lvl - 1] = 1;
1457 thread_add_timer_msec(master, lsp_refresh,
1458 &area->lsp_refresh_arg[lvl - 1],
1459 timeout,
1460 &area->t_lsp_refresh[lvl - 1]);
1461 }
1462
1463 if (all_pseudo) {
1464 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
1465 lsp_regenerate_schedule_pseudo(circuit, level);
1466 }
1467
1468 return ISIS_OK;
1469 }
1470
1471 /*
1472 * Funcs for pseudonode LSPs
1473 */
1474
1475 /*
1476 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1477 */
1478 static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
1479 int level)
1480 {
1481 struct isis_adjacency *adj;
1482 struct list *adj_list;
1483 struct listnode *node;
1484 struct isis_area *area = circuit->area;
1485
1486 lsp_clear_data(lsp);
1487 lsp->tlvs = isis_alloc_tlvs();
1488 lsp_debug(
1489 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1490 area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
1491 circuit->interface->name, level);
1492
1493 lsp->level = level;
1494 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1495 lsp->hdr.lsp_bits =
1496 lsp_bits_generate(level, 0, circuit->area->attached_bit);
1497
1498 /*
1499 * add self to IS neighbours
1500 */
1501 uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
1502
1503 memcpy(ne_id, isis->sysid, ISIS_SYS_ID_LEN);
1504 LSP_PSEUDO_ID(ne_id) = 0;
1505
1506 if (circuit->area->oldmetric) {
1507 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1508 lsp_debug(
1509 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1510 area->area_tag, sysid_print(ne_id),
1511 LSP_PSEUDO_ID(ne_id));
1512 }
1513 if (circuit->area->newmetric) {
1514 isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
1515 ne_id, 0, NULL, 0);
1516 lsp_debug(
1517 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1518 area->area_tag, sysid_print(ne_id),
1519 LSP_PSEUDO_ID(ne_id));
1520 }
1521
1522 adj_list = list_new();
1523 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
1524
1525 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
1526 if (!(adj->level & level)) {
1527 lsp_debug(
1528 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1529 area->area_tag, sysid_print(adj->sysid));
1530 continue;
1531 }
1532
1533 if (!(level == IS_LEVEL_1
1534 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
1535 && !(level == IS_LEVEL_1
1536 && adj->sys_type == ISIS_SYSTYPE_L2_IS
1537 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
1538 && !(level == IS_LEVEL_2
1539 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
1540 lsp_debug(
1541 "ISIS (%s): Ignoring neighbor %s, level does not match",
1542 area->area_tag, sysid_print(adj->sysid));
1543 continue;
1544 }
1545
1546 memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
1547 if (circuit->area->oldmetric) {
1548 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1549 lsp_debug(
1550 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1551 area->area_tag, sysid_print(ne_id),
1552 LSP_PSEUDO_ID(ne_id));
1553 }
1554 if (circuit->area->newmetric) {
1555 isis_tlvs_add_extended_reach(lsp->tlvs,
1556 ISIS_MT_IPV4_UNICAST,
1557 ne_id, 0, NULL, 0);
1558 lsp_debug(
1559 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1560 area->area_tag, sysid_print(ne_id),
1561 LSP_PSEUDO_ID(ne_id));
1562 }
1563 }
1564 list_delete(&adj_list);
1565 return;
1566 }
1567
1568 int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
1569 {
1570 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1571 struct isis_lsp *lsp;
1572 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1573 uint16_t rem_lifetime, refresh_time;
1574
1575 if ((circuit->is_type & level) != level
1576 || (circuit->state != C_STATE_UP)
1577 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1578 || (circuit->u.bc.is_dr[level - 1] == 0))
1579 return ISIS_ERROR;
1580
1581 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1582 LSP_FRAGMENT(lsp_id) = 0;
1583 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1584
1585 /*
1586 * If for some reason have a pseudo LSP in the db already -> regenerate
1587 */
1588 if (lsp_search(head, lsp_id))
1589 return lsp_regenerate_schedule_pseudo(circuit, level);
1590
1591 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1592 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1593 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
1594 circuit->area->is_type | circuit->area->attached_bit, 0,
1595 NULL, level);
1596 lsp->area = circuit->area;
1597
1598 lsp_build_pseudo(lsp, circuit, level);
1599 lsp_pack_pdu(lsp);
1600 lsp->own_lsp = 1;
1601 lsp_insert(head, lsp);
1602 lsp_flood(lsp, NULL);
1603
1604 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1605 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1606 circuit->lsp_regenerate_pending[level - 1] = 0;
1607 if (level == IS_LEVEL_1)
1608 thread_add_timer(
1609 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1610 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1611 else if (level == IS_LEVEL_2)
1612 thread_add_timer(
1613 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1614 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1615
1616 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1617 zlog_debug(
1618 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1619 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1620 ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
1621 circuit->area->area_tag, level,
1622 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1623 lsp->hdr.seqno, lsp->hdr.checksum,
1624 lsp->hdr.rem_lifetime, refresh_time);
1625 }
1626
1627 return ISIS_OK;
1628 }
1629
1630 static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
1631 {
1632 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1633 struct isis_lsp *lsp;
1634 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1635 uint16_t rem_lifetime, refresh_time;
1636
1637 if ((circuit->is_type & level) != level
1638 || (circuit->state != C_STATE_UP)
1639 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1640 || (circuit->u.bc.is_dr[level - 1] == 0))
1641 return ISIS_ERROR;
1642
1643 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1644 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1645 LSP_FRAGMENT(lsp_id) = 0;
1646
1647 lsp = lsp_search(head, lsp_id);
1648
1649 if (!lsp) {
1650 flog_err(EC_LIB_DEVELOPMENT,
1651 "lsp_regenerate_pseudo: no l%d LSP %s found!", level,
1652 rawlspid_print(lsp_id));
1653 return ISIS_ERROR;
1654 }
1655
1656 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1657 lsp->hdr.rem_lifetime = rem_lifetime;
1658 lsp_build_pseudo(lsp, circuit, level);
1659 lsp_inc_seqno(lsp, 0);
1660 lsp->last_generated = time(NULL);
1661 lsp_flood(lsp, NULL);
1662
1663 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1664 if (level == IS_LEVEL_1)
1665 thread_add_timer(
1666 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1667 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1668 else if (level == IS_LEVEL_2)
1669 thread_add_timer(
1670 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1671 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1672
1673 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1674 zlog_debug(
1675 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1676 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1677 ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
1678 circuit->area->area_tag, level,
1679 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1680 lsp->hdr.seqno, lsp->hdr.checksum,
1681 lsp->hdr.rem_lifetime, refresh_time);
1682 }
1683
1684 return ISIS_OK;
1685 }
1686
1687 /*
1688 * Something has changed or periodic refresh -> regenerate pseudo LSP
1689 */
1690 static int lsp_l1_refresh_pseudo(struct thread *thread)
1691 {
1692 struct isis_circuit *circuit;
1693 uint8_t id[ISIS_SYS_ID_LEN + 2];
1694
1695 circuit = THREAD_ARG(thread);
1696
1697 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
1698 circuit->lsp_regenerate_pending[0] = 0;
1699
1700 if ((circuit->u.bc.is_dr[0] == 0)
1701 || (circuit->is_type & IS_LEVEL_1) == 0) {
1702 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
1703 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1704 LSP_FRAGMENT(id) = 0;
1705 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
1706 return ISIS_ERROR;
1707 }
1708
1709 return lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
1710 }
1711
1712 static int lsp_l2_refresh_pseudo(struct thread *thread)
1713 {
1714 struct isis_circuit *circuit;
1715 uint8_t id[ISIS_SYS_ID_LEN + 2];
1716
1717 circuit = THREAD_ARG(thread);
1718
1719 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
1720 circuit->lsp_regenerate_pending[1] = 0;
1721
1722 if ((circuit->u.bc.is_dr[1] == 0)
1723 || (circuit->is_type & IS_LEVEL_2) == 0) {
1724 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
1725 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1726 LSP_FRAGMENT(id) = 0;
1727 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
1728 return ISIS_ERROR;
1729 }
1730
1731 return lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
1732 }
1733
1734 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
1735 {
1736 struct isis_lsp *lsp;
1737 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1738 time_t now, diff;
1739 long timeout;
1740 int lvl;
1741 struct isis_area *area = circuit->area;
1742
1743 if (circuit->circ_type != CIRCUIT_T_BROADCAST
1744 || circuit->state != C_STATE_UP)
1745 return ISIS_OK;
1746
1747 sched_debug(
1748 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1749 area->area_tag, circuit_t2string(level),
1750 circuit->interface->name);
1751
1752 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1753 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1754 LSP_FRAGMENT(lsp_id) = 0;
1755 now = time(NULL);
1756
1757 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1758 sched_debug(
1759 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1760 area->area_tag, lvl);
1761
1762 if (!((level & lvl) && (circuit->is_type & lvl))) {
1763 sched_debug("ISIS (%s): Level is not active on circuit",
1764 area->area_tag);
1765 continue;
1766 }
1767
1768 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
1769 sched_debug(
1770 "ISIS (%s): This IS is not DR, nothing to do.",
1771 area->area_tag);
1772 continue;
1773 }
1774
1775 if (circuit->lsp_regenerate_pending[lvl - 1]) {
1776 struct timeval remain = thread_timer_remain(
1777 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1778 sched_debug(
1779 "ISIS (%s): Regenerate is already pending, nothing todo."
1780 " (Due in %lld.%03lld seconds)",
1781 area->area_tag, (long long)remain.tv_sec,
1782 (long long)remain.tv_usec / 1000);
1783 continue;
1784 }
1785
1786 lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
1787 if (!lsp) {
1788 sched_debug(
1789 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1790 area->area_tag);
1791 continue;
1792 }
1793
1794 /*
1795 * Throttle avoidance
1796 */
1797 sched_debug(
1798 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1799 area->area_tag, (long long)lsp->last_generated,
1800 (long long)now);
1801 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1802 diff = now - lsp->last_generated;
1803 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
1804 timeout =
1805 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
1806 - diff);
1807 sched_debug(
1808 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1809 area->area_tag, timeout);
1810 } else {
1811 timeout = 100;
1812 sched_debug(
1813 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1814 " Scheduling for execution in %ld ms.",
1815 area->area_tag, timeout);
1816 }
1817
1818 circuit->lsp_regenerate_pending[lvl - 1] = 1;
1819
1820 if (lvl == IS_LEVEL_1) {
1821 thread_add_timer_msec(
1822 master, lsp_l1_refresh_pseudo, circuit, timeout,
1823 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1824 } else if (lvl == IS_LEVEL_2) {
1825 thread_add_timer_msec(
1826 master, lsp_l2_refresh_pseudo, circuit, timeout,
1827 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1828 }
1829 }
1830
1831 return ISIS_OK;
1832 }
1833
1834 /*
1835 * Walk through LSPs for an area
1836 * - set remaining lifetime
1837 */
1838 int lsp_tick(struct thread *thread)
1839 {
1840 struct isis_area *area;
1841 struct isis_lsp *lsp;
1842 int level;
1843 uint16_t rem_lifetime;
1844 bool fabricd_sync_incomplete = false;
1845
1846 area = THREAD_ARG(thread);
1847 assert(area);
1848 area->t_tick = NULL;
1849 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
1850
1851 struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
1852
1853 /*
1854 * Remove LSPs which have aged out
1855 */
1856 for (level = 0; level < ISIS_LEVELS; level++) {
1857 struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
1858 for_each_from (lspdb, &area->lspdb[level], lsp, next) {
1859 /*
1860 * The lsp rem_lifetime is kept at 0 for MaxAge
1861 * or
1862 * ZeroAgeLifetime depending on explicit purge
1863 * or
1864 * natural age out. So schedule spf only once
1865 * when
1866 * the first time rem_lifetime becomes 0.
1867 */
1868 rem_lifetime = lsp->hdr.rem_lifetime;
1869 lsp_set_time(lsp);
1870
1871 /*
1872 * Schedule may run spf which should be done
1873 * only after
1874 * the lsp rem_lifetime becomes 0 for the first
1875 * time.
1876 * ISO 10589 - 7.3.16.4 first paragraph.
1877 */
1878 if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
1879 /* 7.3.16.4 a) set SRM flags on all */
1880 /* 7.3.16.4 b) retain only the header */
1881 if (lsp->area->purge_originator)
1882 lsp_purge(lsp, lsp->level, NULL);
1883 else
1884 lsp_flood(lsp, NULL);
1885 /* 7.3.16.4 c) record the time to purge
1886 * FIXME */
1887 isis_spf_schedule(lsp->area, lsp->level);
1888 }
1889
1890 if (lsp->age_out == 0) {
1891 zlog_debug(
1892 "ISIS-Upd (%s): L%u LSP %s seq "
1893 "0x%08" PRIx32 " aged out",
1894 area->area_tag, lsp->level,
1895 rawlspid_print(lsp->hdr.lsp_id),
1896 lsp->hdr.seqno);
1897
1898 /* if we're aging out fragment 0, lsp_destroy()
1899 * below will delete all other fragments too,
1900 * so we need to skip over those
1901 */
1902 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
1903 while (next &&
1904 !memcmp(next->hdr.lsp_id,
1905 lsp->hdr.lsp_id,
1906 ISIS_SYS_ID_LEN + 1))
1907 next = lspdb_next(
1908 &area->lspdb[level],
1909 next);
1910
1911 lspdb_del(&area->lspdb[level], lsp);
1912 lsp_destroy(lsp);
1913 lsp = NULL;
1914 }
1915
1916 if (fabricd_init_c && lsp) {
1917 fabricd_sync_incomplete |=
1918 ISIS_CHECK_FLAG(lsp->SSNflags,
1919 fabricd_init_c);
1920 }
1921 }
1922 }
1923
1924 if (fabricd_init_c
1925 && !fabricd_sync_incomplete
1926 && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
1927 fabricd_initial_sync_finish(area);
1928 }
1929
1930 return ISIS_OK;
1931 }
1932
1933 void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
1934 {
1935 struct isis_lsp *lsp;
1936
1937 lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
1938 if (!lsp)
1939 return;
1940
1941 lsp_purge(lsp, level, NULL);
1942 }
1943
1944 /*
1945 * Purge own LSP that is received and we don't have.
1946 * -> Do as in 7.3.16.4
1947 */
1948 void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
1949 struct isis_area *area)
1950 {
1951 struct isis_lsp *lsp;
1952
1953 /*
1954 * We need to create the LSP to be purged
1955 */
1956 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
1957 lsp->area = area;
1958 lsp->level = level;
1959 lsp_adjust_stream(lsp);
1960 lsp->age_out = ZERO_AGE_LIFETIME;
1961 lsp->area->lsp_purge_count[level - 1]++;
1962
1963 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
1964 lsp->hdr.rem_lifetime = 0;
1965
1966 lsp_purge_add_poi(lsp, NULL);
1967
1968 lsp_pack_pdu(lsp);
1969
1970 lsp_insert(&area->lspdb[lsp->level - 1], lsp);
1971 lsp_flood(lsp, NULL);
1972
1973 return;
1974 }
1975
1976 void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
1977 {
1978 struct listnode *node;
1979 struct isis_circuit *circuit;
1980
1981 assert(lsp);
1982
1983 if (!lsp->area)
1984 return;
1985
1986 struct list *circuit_list = lsp->area->circuit_list;
1987 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
1988 if (set) {
1989 isis_tx_queue_add(circuit->tx_queue, lsp,
1990 TX_LSP_NORMAL);
1991 } else {
1992 isis_tx_queue_del(circuit->tx_queue, lsp);
1993 }
1994 }
1995 }
1996
1997 void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
1998 const char *func, const char *file, int line)
1999 {
2000 if (isis->debugs & DEBUG_FLOODING) {
2001 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2002 rawlspid_print(lsp->hdr.lsp_id),
2003 circuit ? " except on " : "",
2004 circuit ? circuit->interface->name : "",
2005 func, file, line);
2006 }
2007
2008 if (!fabricd)
2009 lsp_set_all_srmflags(lsp, true);
2010 else
2011 fabricd_lsp_flood(lsp, circuit);
2012
2013 if (circuit)
2014 isis_tx_queue_del(circuit->tx_queue, lsp);
2015 }
2016
2017 static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
2018 {
2019 lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
2020 return 0;
2021 }
2022
2023 void lsp_init(void)
2024 {
2025 hook_register(isis_adj_state_change_hook,
2026 lsp_handle_adj_state_change);
2027 }