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