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