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