]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
Merge pull request #9439 from ton31337/feature/set_ext_community_to_none
[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 lsp_debug("ISIS (%s): Adding circuit specific information.",
1071 area->area_tag);
1072
1073 if (fabricd) {
1074 lsp_debug(
1075 "ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
1076 area->area_tag, fabricd_tier(area));
1077 isis_tlvs_add_spine_leaf(lsp->tlvs, fabricd_tier(area), true,
1078 false, false, false);
1079 }
1080
1081 struct isis_circuit *circuit;
1082 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
1083 if (!circuit->interface)
1084 lsp_debug(
1085 "ISIS (%s): Processing %s circuit %p with unknown interface",
1086 area->area_tag,
1087 circuit_type2string(circuit->circ_type),
1088 circuit);
1089 else
1090 lsp_debug("ISIS (%s): Processing %s circuit %s",
1091 area->area_tag,
1092 circuit_type2string(circuit->circ_type),
1093 circuit->interface->name);
1094
1095 if (circuit->state != C_STATE_UP) {
1096 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1097 area->area_tag);
1098 continue;
1099 }
1100
1101 uint32_t metric = area->oldmetric
1102 ? circuit->metric[level - 1]
1103 : circuit->te_metric[level - 1];
1104
1105 if (circuit->ip_router && circuit->ip_addrs
1106 && circuit->ip_addrs->count > 0) {
1107 lsp_debug(
1108 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1109 area->area_tag);
1110 struct listnode *ipnode;
1111 struct prefix_ipv4 *ipv4;
1112 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
1113 ipv4)) {
1114 if (area->oldmetric) {
1115 lsp_debug(
1116 "ISIS (%s): Adding old-style IP reachability for %pFX",
1117 area->area_tag, ipv4);
1118 isis_tlvs_add_oldstyle_ip_reach(
1119 lsp->tlvs, ipv4, metric);
1120 }
1121
1122 if (area->newmetric) {
1123 struct sr_prefix_cfg *pcfg = NULL;
1124
1125 lsp_debug(
1126 "ISIS (%s): Adding te-style IP reachability for %pFX",
1127 area->area_tag, ipv4);
1128
1129 if (area->srdb.enabled)
1130 pcfg = isis_sr_cfg_prefix_find(
1131 area, ipv4);
1132
1133 isis_tlvs_add_extended_ip_reach(
1134 lsp->tlvs, ipv4, metric, false,
1135 pcfg);
1136 }
1137 }
1138 }
1139
1140 if (circuit->ipv6_router && circuit->ipv6_non_link
1141 && circuit->ipv6_non_link->count > 0) {
1142 struct listnode *ipnode;
1143 struct prefix_ipv6 *ipv6;
1144
1145 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1146 ipnode, ipv6)) {
1147 struct sr_prefix_cfg *pcfg = NULL;
1148
1149 lsp_debug(
1150 "ISIS (%s): Adding IPv6 reachability for %pFX",
1151 area->area_tag, ipv6);
1152
1153 if (area->srdb.enabled)
1154 pcfg = isis_sr_cfg_prefix_find(area,
1155 ipv6);
1156
1157 isis_tlvs_add_ipv6_reach(
1158 lsp->tlvs,
1159 isis_area_ipv6_topology(area), ipv6,
1160 metric, false, pcfg);
1161 }
1162 }
1163
1164 switch (circuit->circ_type) {
1165 case CIRCUIT_T_BROADCAST:
1166 if (level & circuit->is_type) {
1167 uint8_t *ne_id =
1168 (level == IS_LEVEL_1)
1169 ? circuit->u.bc.l1_desig_is
1170 : circuit->u.bc.l2_desig_is;
1171
1172 if (LSP_PSEUDO_ID(ne_id)) {
1173 if (area->oldmetric) {
1174 lsp_debug(
1175 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1176 area->area_tag,
1177 sysid_print(ne_id),
1178 LSP_PSEUDO_ID(ne_id));
1179 isis_tlvs_add_oldstyle_reach(
1180 lsp->tlvs, ne_id,
1181 metric);
1182 }
1183 if (area->newmetric)
1184 tlvs_add_mt_bcast(
1185 lsp->tlvs, circuit,
1186 level, ne_id, metric);
1187 }
1188 } else {
1189 lsp_debug(
1190 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1191 area->area_tag);
1192 }
1193 break;
1194 case CIRCUIT_T_P2P: {
1195 struct isis_adjacency *nei = circuit->u.p2p.neighbor;
1196 if (nei && nei->adj_state == ISIS_ADJ_UP
1197 && (level & nei->circuit_t)) {
1198 uint8_t ne_id[7];
1199 memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
1200 LSP_PSEUDO_ID(ne_id) = 0;
1201
1202 if (area->oldmetric) {
1203 lsp_debug(
1204 "ISIS (%s): Adding old-style is reach for %s",
1205 area->area_tag,
1206 sysid_print(ne_id));
1207 isis_tlvs_add_oldstyle_reach(
1208 lsp->tlvs, ne_id, metric);
1209 }
1210 if (area->newmetric) {
1211 uint32_t neighbor_metric;
1212 if (fabricd_tier(area) == 0) {
1213 neighbor_metric = 0xffe;
1214 } else {
1215 neighbor_metric = metric;
1216 }
1217
1218 tlvs_add_mt_p2p(lsp->tlvs, circuit,
1219 ne_id, neighbor_metric);
1220 }
1221 } else {
1222 lsp_debug(
1223 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1224 area->area_tag);
1225 }
1226 } break;
1227 case CIRCUIT_T_LOOPBACK:
1228 break;
1229 default:
1230 zlog_warn("lsp_area_create: unknown circuit type");
1231 }
1232 }
1233
1234 lsp_build_ext_reach(lsp, area);
1235
1236 struct isis_tlvs *tlvs = lsp->tlvs;
1237 lsp->tlvs = NULL;
1238
1239 lsp_adjust_stream(lsp);
1240 lsp_pack_pdu(lsp);
1241 size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
1242 lsp_clear_data(lsp);
1243
1244 struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
1245 if (!fragments) {
1246 zlog_warn("BUG: could not fragment own LSP:");
1247 log_multiline(LOG_WARNING, " ", "%s",
1248 isis_format_tlvs(tlvs));
1249 isis_free_tlvs(tlvs);
1250 return;
1251 }
1252 isis_free_tlvs(tlvs);
1253
1254 bool fragment_overflow = false;
1255 frag = lsp;
1256 for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
1257 if (node != listhead(fragments)) {
1258 if (LSP_FRAGMENT(frag->hdr.lsp_id) == 255) {
1259 if (!fragment_overflow) {
1260 fragment_overflow = true;
1261 zlog_warn(
1262 "ISIS (%s): Too much information for 256 fragments",
1263 area->area_tag);
1264 }
1265 isis_free_tlvs(tlvs);
1266 continue;
1267 }
1268
1269 frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
1270 lsp, area, level);
1271 lsp_adjust_stream(frag);
1272 }
1273 frag->tlvs = tlvs;
1274 }
1275
1276 list_delete(&fragments);
1277 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1278 area->area_tag);
1279 return;
1280 }
1281
1282 /*
1283 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1284 */
1285 int lsp_generate(struct isis_area *area, int level)
1286 {
1287 struct isis_lsp *oldlsp, *newlsp;
1288 uint32_t seq_num = 0;
1289 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1290 uint16_t rem_lifetime, refresh_time;
1291
1292 if ((area == NULL) || (area->is_type & level) != level)
1293 return ISIS_ERROR;
1294
1295 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
1296
1297 memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
1298
1299 /* only builds the lsp if the area shares the level */
1300 oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
1301 if (oldlsp) {
1302 /* FIXME: we should actually initiate a purge */
1303 seq_num = oldlsp->hdr.seqno;
1304 lsp_search_and_destroy(&area->lspdb[level - 1],
1305 oldlsp->hdr.lsp_id);
1306 }
1307 rem_lifetime = lsp_rem_lifetime(area, level);
1308 newlsp = lsp_new(area, lspid, rem_lifetime, seq_num,
1309 lsp_bits_generate(area->is_type, area->overload_bit,
1310 area->attached_bit_send, area),
1311 0, NULL, level);
1312 newlsp->area = area;
1313 newlsp->own_lsp = 1;
1314
1315 lsp_insert(&area->lspdb[level - 1], newlsp);
1316 /* build_lsp_data (newlsp, area); */
1317 lsp_build(newlsp, area);
1318 /* time to calculate our checksum */
1319 lsp_seqno_update(newlsp);
1320 newlsp->last_generated = time(NULL);
1321 lsp_flood(newlsp, NULL);
1322 area->lsp_gen_count[level - 1]++;
1323
1324 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
1325
1326 thread_cancel(&area->t_lsp_refresh[level - 1]);
1327 area->lsp_regenerate_pending[level - 1] = 0;
1328 thread_add_timer(master, lsp_refresh,
1329 &area->lsp_refresh_arg[level - 1], refresh_time,
1330 &area->t_lsp_refresh[level - 1]);
1331
1332 if (IS_DEBUG_UPDATE_PACKETS) {
1333 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1334 area->area_tag, level,
1335 rawlspid_print(newlsp->hdr.lsp_id),
1336 newlsp->hdr.pdu_len, newlsp->hdr.seqno,
1337 newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
1338 refresh_time);
1339 }
1340 sched_debug(
1341 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1342 area->area_tag, level);
1343
1344 #ifndef FABRICD
1345 /* send northbound notification */
1346 isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno,
1347 newlsp->last_generated);
1348 #endif /* ifndef FABRICD */
1349
1350 return ISIS_OK;
1351 }
1352
1353 /*
1354 * Search own LSPs, update holding time and flood
1355 */
1356 static int lsp_regenerate(struct isis_area *area, int level)
1357 {
1358 struct lspdb_head *head;
1359 struct isis_lsp *lsp, *frag;
1360 struct listnode *node;
1361 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
1362 uint16_t rem_lifetime, refresh_time;
1363
1364 if ((area == NULL) || (area->is_type & level) != level)
1365 return ISIS_ERROR;
1366
1367 head = &area->lspdb[level - 1];
1368 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
1369 memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
1370
1371 lsp = lsp_search(head, lspid);
1372
1373 if (!lsp) {
1374 flog_err(EC_LIB_DEVELOPMENT,
1375 "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1376 area->area_tag, level);
1377 return ISIS_ERROR;
1378 }
1379
1380 lsp_clear_data(lsp);
1381 lsp_build(lsp, area);
1382 rem_lifetime = lsp_rem_lifetime(area, level);
1383 lsp->hdr.rem_lifetime = rem_lifetime;
1384 lsp->last_generated = time(NULL);
1385 lsp_flood(lsp, NULL);
1386 area->lsp_gen_count[level - 1]++;
1387 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
1388 if (!frag->tlvs) {
1389 /* Updating and flooding should only affect fragments
1390 * carrying data
1391 */
1392 continue;
1393 }
1394
1395 frag->hdr.lsp_bits =
1396 lsp_bits_generate(level, area->overload_bit,
1397 area->attached_bit_send, area);
1398 /* Set the lifetime values of all the fragments to the same
1399 * value,
1400 * so that no fragment expires before the lsp is refreshed.
1401 */
1402 frag->hdr.rem_lifetime = rem_lifetime;
1403 frag->age_out = ZERO_AGE_LIFETIME;
1404 lsp_flood(frag, NULL);
1405 }
1406 lsp_seqno_update(lsp);
1407
1408 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1409 thread_add_timer(master, lsp_refresh,
1410 &area->lsp_refresh_arg[level - 1], refresh_time,
1411 &area->t_lsp_refresh[level - 1]);
1412 area->lsp_regenerate_pending[level - 1] = 0;
1413
1414 if (IS_DEBUG_UPDATE_PACKETS) {
1415 zlog_debug(
1416 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
1417 area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
1418 lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
1419 lsp->hdr.rem_lifetime, refresh_time);
1420 }
1421 sched_debug(
1422 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1423 area->area_tag, level);
1424
1425 return ISIS_OK;
1426 }
1427
1428 /*
1429 * Something has changed or periodic refresh -> regenerate LSP
1430 */
1431 static int lsp_refresh(struct thread *thread)
1432 {
1433 struct lsp_refresh_arg *arg = THREAD_ARG(thread);
1434
1435 assert(arg);
1436
1437 struct isis_area *area = arg->area;
1438
1439 assert(area);
1440
1441 int level = arg->level;
1442
1443 area->t_lsp_refresh[level - 1] = NULL;
1444 area->lsp_regenerate_pending[level - 1] = 0;
1445
1446 if ((area->is_type & level) == 0)
1447 return ISIS_ERROR;
1448
1449 /*
1450 * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
1451 * message)
1452 */
1453 if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL)
1454 < 100000L
1455 && !(area->bfd_force_spf_refresh)) {
1456 sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
1457 area->area_tag, level);
1458 _lsp_regenerate_schedule(area, level, 0, false,
1459 __func__, __FILE__, __LINE__);
1460 return 0;
1461 }
1462
1463 sched_debug(
1464 "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
1465 area->area_tag, level);
1466 return lsp_regenerate(area, level);
1467 }
1468
1469 int _lsp_regenerate_schedule(struct isis_area *area, int level,
1470 int all_pseudo, bool postpone,
1471 const char *func, const char *file,
1472 int line)
1473 {
1474 struct isis_lsp *lsp;
1475 uint8_t id[ISIS_SYS_ID_LEN + 2];
1476 time_t now, diff;
1477 long timeout;
1478 struct listnode *cnode;
1479 struct isis_circuit *circuit;
1480 int lvl;
1481
1482 if (area == NULL)
1483 return ISIS_ERROR;
1484
1485 sched_debug(
1486 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
1487 area->area_tag, circuit_t2string(level),
1488 all_pseudo ? "" : "not ",
1489 func, file, line);
1490
1491 memcpy(id, area->isis->sysid, ISIS_SYS_ID_LEN);
1492 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
1493 now = time(NULL);
1494
1495 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1496 if (!((level & lvl) && (area->is_type & lvl)))
1497 continue;
1498
1499 if (postpone) {
1500 monotime(&area->last_lsp_refresh_event[lvl - 1]);
1501 }
1502
1503 sched_debug(
1504 "ISIS (%s): Checking whether L%d needs to be scheduled",
1505 area->area_tag, lvl);
1506
1507 if (area->lsp_regenerate_pending[lvl - 1]
1508 && !(area->bfd_signalled_down)) {
1509 /*
1510 * Note: in case of a BFD 'down' message the refresh is
1511 * scheduled once again just to be sure
1512 */
1513 struct timeval remain = thread_timer_remain(
1514 area->t_lsp_refresh[lvl - 1]);
1515 sched_debug(
1516 "ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1517 area->area_tag, (long long)remain.tv_sec,
1518 (long long)remain.tv_usec / 1000);
1519 continue;
1520 }
1521
1522 lsp = lsp_search(&area->lspdb[lvl - 1], id);
1523 if (!lsp) {
1524 sched_debug(
1525 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1526 area->area_tag);
1527 continue;
1528 }
1529
1530 /*
1531 * Throttle avoidance
1532 */
1533 sched_debug(
1534 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1535 area->area_tag, (long long)lsp->last_generated,
1536 (long long)now);
1537 thread_cancel(&area->t_lsp_refresh[lvl - 1]);
1538 diff = now - lsp->last_generated;
1539 if (diff < area->lsp_gen_interval[lvl - 1]
1540 && !(area->bfd_signalled_down)) {
1541 timeout =
1542 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
1543 sched_debug(
1544 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1545 area->area_tag, timeout);
1546 } else {
1547 /*
1548 * Schedule LSP refresh ASAP
1549 */
1550 if (area->bfd_signalled_down) {
1551 sched_debug(
1552 "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
1553 area->area_tag);
1554 area->bfd_signalled_down = false;
1555 area->bfd_force_spf_refresh = true;
1556 timeout = 0;
1557 } else {
1558 int64_t time_since_last = monotime_since(
1559 &area->last_lsp_refresh_event[lvl - 1],
1560 NULL);
1561 timeout = time_since_last < 100000L
1562 ? (100000L - time_since_last)/1000
1563 : 0;
1564 if (timeout > 0)
1565 sched_debug(
1566 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
1567 area->area_tag, timeout);
1568 else
1569 sched_debug(
1570 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
1571 area->area_tag);
1572 }
1573 }
1574
1575 area->lsp_regenerate_pending[lvl - 1] = 1;
1576 thread_add_timer_msec(master, lsp_refresh,
1577 &area->lsp_refresh_arg[lvl - 1],
1578 timeout,
1579 &area->t_lsp_refresh[lvl - 1]);
1580 }
1581
1582 if (all_pseudo) {
1583 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
1584 lsp_regenerate_schedule_pseudo(circuit, level);
1585 }
1586
1587 return ISIS_OK;
1588 }
1589
1590 /*
1591 * Funcs for pseudonode LSPs
1592 */
1593
1594 /*
1595 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1596 */
1597 static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
1598 int level)
1599 {
1600 struct isis_adjacency *adj;
1601 struct list *adj_list;
1602 struct listnode *node;
1603 struct isis_area *area = circuit->area;
1604
1605 lsp_clear_data(lsp);
1606 lsp->tlvs = isis_alloc_tlvs();
1607 lsp_debug(
1608 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
1609 area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
1610 circuit->interface->name, level);
1611
1612 lsp->level = level;
1613 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1614 lsp->hdr.lsp_bits = lsp_bits_generate(
1615 level, 0, circuit->area->attached_bit_send, area);
1616
1617 /*
1618 * add self to IS neighbours
1619 */
1620 uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
1621
1622 memcpy(ne_id, area->isis->sysid, ISIS_SYS_ID_LEN);
1623 LSP_PSEUDO_ID(ne_id) = 0;
1624
1625 if (circuit->area->oldmetric) {
1626 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1627 lsp_debug(
1628 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
1629 area->area_tag, sysid_print(ne_id),
1630 LSP_PSEUDO_ID(ne_id));
1631 }
1632 if (circuit->area->newmetric) {
1633 isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
1634 ne_id, 0, NULL);
1635 lsp_debug(
1636 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
1637 area->area_tag, sysid_print(ne_id),
1638 LSP_PSEUDO_ID(ne_id));
1639 }
1640
1641 adj_list = list_new();
1642 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
1643
1644 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
1645 if (!(adj->level & level)) {
1646 lsp_debug(
1647 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1648 area->area_tag, sysid_print(adj->sysid));
1649 continue;
1650 }
1651
1652 if (!(level == IS_LEVEL_1
1653 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
1654 && !(level == IS_LEVEL_1
1655 && adj->sys_type == ISIS_SYSTYPE_L2_IS
1656 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
1657 && !(level == IS_LEVEL_2
1658 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
1659 lsp_debug(
1660 "ISIS (%s): Ignoring neighbor %s, level does not match",
1661 area->area_tag, sysid_print(adj->sysid));
1662 continue;
1663 }
1664
1665 memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
1666 if (circuit->area->oldmetric) {
1667 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1668 lsp_debug(
1669 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1670 area->area_tag, sysid_print(ne_id),
1671 LSP_PSEUDO_ID(ne_id));
1672 }
1673 if (circuit->area->newmetric) {
1674 isis_tlvs_add_extended_reach(lsp->tlvs,
1675 ISIS_MT_IPV4_UNICAST,
1676 ne_id, 0, NULL);
1677 lsp_debug(
1678 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1679 area->area_tag, sysid_print(ne_id),
1680 LSP_PSEUDO_ID(ne_id));
1681 }
1682 }
1683 list_delete(&adj_list);
1684 return;
1685 }
1686
1687 int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
1688 {
1689 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1690 struct isis_lsp *lsp;
1691 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1692 uint16_t rem_lifetime, refresh_time;
1693
1694 if ((circuit->is_type & level) != level
1695 || (circuit->state != C_STATE_UP)
1696 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1697 || (circuit->u.bc.is_dr[level - 1] == 0))
1698 return ISIS_ERROR;
1699
1700 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1701 LSP_FRAGMENT(lsp_id) = 0;
1702 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1703
1704 /*
1705 * If for some reason have a pseudo LSP in the db already -> regenerate
1706 */
1707 if (lsp_search(head, lsp_id))
1708 return lsp_regenerate_schedule_pseudo(circuit, level);
1709
1710 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1711 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1712 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
1713 lsp_bits_generate(circuit->area->is_type, 0,
1714 circuit->area->attached_bit_send,
1715 circuit->area),
1716 0, NULL, level);
1717 lsp->area = circuit->area;
1718
1719 lsp_build_pseudo(lsp, circuit, level);
1720 lsp_pack_pdu(lsp);
1721 lsp->own_lsp = 1;
1722 lsp_insert(head, lsp);
1723 lsp_flood(lsp, NULL);
1724
1725 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1726 thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1727 circuit->lsp_regenerate_pending[level - 1] = 0;
1728 if (level == IS_LEVEL_1)
1729 thread_add_timer(
1730 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1731 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1732 else if (level == IS_LEVEL_2)
1733 thread_add_timer(
1734 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1735 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1736
1737 if (IS_DEBUG_UPDATE_PACKETS) {
1738 zlog_debug(
1739 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1740 circuit->area->area_tag, level,
1741 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1742 lsp->hdr.seqno, lsp->hdr.checksum,
1743 lsp->hdr.rem_lifetime, refresh_time);
1744 }
1745
1746 return ISIS_OK;
1747 }
1748
1749 static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
1750 {
1751 struct lspdb_head *head = &circuit->area->lspdb[level - 1];
1752 struct isis_lsp *lsp;
1753 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1754 uint16_t rem_lifetime, refresh_time;
1755
1756 if ((circuit->is_type & level) != level
1757 || (circuit->state != C_STATE_UP)
1758 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1759 || (circuit->u.bc.is_dr[level - 1] == 0))
1760 return ISIS_ERROR;
1761
1762 memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1763 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1764 LSP_FRAGMENT(lsp_id) = 0;
1765
1766 lsp = lsp_search(head, lsp_id);
1767
1768 if (!lsp) {
1769 flog_err(EC_LIB_DEVELOPMENT,
1770 "lsp_regenerate_pseudo: no l%d LSP %s found!", level,
1771 rawlspid_print(lsp_id));
1772 return ISIS_ERROR;
1773 }
1774
1775 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1776 lsp->hdr.rem_lifetime = rem_lifetime;
1777 lsp_build_pseudo(lsp, circuit, level);
1778 lsp_inc_seqno(lsp, 0);
1779 lsp->last_generated = time(NULL);
1780 lsp_flood(lsp, NULL);
1781
1782 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1783 if (level == IS_LEVEL_1)
1784 thread_add_timer(
1785 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1786 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1787 else if (level == IS_LEVEL_2)
1788 thread_add_timer(
1789 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1790 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1791
1792 if (IS_DEBUG_UPDATE_PACKETS) {
1793 zlog_debug(
1794 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
1795 circuit->area->area_tag, level,
1796 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1797 lsp->hdr.seqno, lsp->hdr.checksum,
1798 lsp->hdr.rem_lifetime, refresh_time);
1799 }
1800
1801 return ISIS_OK;
1802 }
1803
1804 /*
1805 * Something has changed or periodic refresh -> regenerate pseudo LSP
1806 */
1807 static int lsp_l1_refresh_pseudo(struct thread *thread)
1808 {
1809 struct isis_circuit *circuit;
1810 uint8_t id[ISIS_SYS_ID_LEN + 2];
1811
1812 circuit = THREAD_ARG(thread);
1813
1814 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
1815 circuit->lsp_regenerate_pending[0] = 0;
1816
1817 if ((circuit->u.bc.is_dr[0] == 0)
1818 || (circuit->is_type & IS_LEVEL_1) == 0) {
1819 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1820 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1821 LSP_FRAGMENT(id) = 0;
1822 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
1823 return ISIS_ERROR;
1824 }
1825
1826 return lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
1827 }
1828
1829 static int lsp_l2_refresh_pseudo(struct thread *thread)
1830 {
1831 struct isis_circuit *circuit;
1832 uint8_t id[ISIS_SYS_ID_LEN + 2];
1833
1834 circuit = THREAD_ARG(thread);
1835
1836 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
1837 circuit->lsp_regenerate_pending[1] = 0;
1838
1839 if ((circuit->u.bc.is_dr[1] == 0)
1840 || (circuit->is_type & IS_LEVEL_2) == 0) {
1841 memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
1842 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1843 LSP_FRAGMENT(id) = 0;
1844 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
1845 return ISIS_ERROR;
1846 }
1847
1848 return lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
1849 }
1850
1851 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
1852 {
1853 struct isis_lsp *lsp;
1854 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
1855 time_t now, diff;
1856 long timeout;
1857 int lvl;
1858 struct isis_area *area = circuit->area;
1859
1860 if (circuit->circ_type != CIRCUIT_T_BROADCAST
1861 || circuit->state != C_STATE_UP)
1862 return ISIS_OK;
1863
1864 sched_debug(
1865 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1866 area->area_tag, circuit_t2string(level),
1867 circuit->interface->name);
1868
1869 memcpy(lsp_id, area->isis->sysid, ISIS_SYS_ID_LEN);
1870 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1871 LSP_FRAGMENT(lsp_id) = 0;
1872 now = time(NULL);
1873
1874 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1875 sched_debug(
1876 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1877 area->area_tag, lvl);
1878
1879 if (!((level & lvl) && (circuit->is_type & lvl))) {
1880 sched_debug("ISIS (%s): Level is not active on circuit",
1881 area->area_tag);
1882 continue;
1883 }
1884
1885 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
1886 sched_debug(
1887 "ISIS (%s): This IS is not DR, nothing to do.",
1888 area->area_tag);
1889 continue;
1890 }
1891
1892 if (circuit->lsp_regenerate_pending[lvl - 1]) {
1893 struct timeval remain = thread_timer_remain(
1894 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1895 sched_debug(
1896 "ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
1897 area->area_tag, (long long)remain.tv_sec,
1898 (long long)remain.tv_usec / 1000);
1899 continue;
1900 }
1901
1902 lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
1903 if (!lsp) {
1904 sched_debug(
1905 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1906 area->area_tag);
1907 continue;
1908 }
1909
1910 /*
1911 * Throttle avoidance
1912 */
1913 sched_debug(
1914 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1915 area->area_tag, (long long)lsp->last_generated,
1916 (long long)now);
1917 thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1918 diff = now - lsp->last_generated;
1919 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
1920 timeout =
1921 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
1922 - diff);
1923 sched_debug(
1924 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1925 area->area_tag, timeout);
1926 } else {
1927 timeout = 100;
1928 sched_debug(
1929 "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
1930 area->area_tag, timeout);
1931 }
1932
1933 circuit->lsp_regenerate_pending[lvl - 1] = 1;
1934
1935 if (lvl == IS_LEVEL_1) {
1936 thread_add_timer_msec(
1937 master, lsp_l1_refresh_pseudo, circuit, timeout,
1938 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1939 } else if (lvl == IS_LEVEL_2) {
1940 thread_add_timer_msec(
1941 master, lsp_l2_refresh_pseudo, circuit, timeout,
1942 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1943 }
1944 }
1945
1946 return ISIS_OK;
1947 }
1948
1949 /*
1950 * Walk through LSPs for an area
1951 * - set remaining lifetime
1952 */
1953 int lsp_tick(struct thread *thread)
1954 {
1955 struct isis_area *area;
1956 struct isis_lsp *lsp;
1957 int level;
1958 uint16_t rem_lifetime;
1959 bool fabricd_sync_incomplete = false;
1960
1961 area = THREAD_ARG(thread);
1962 assert(area);
1963 area->t_tick = NULL;
1964 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
1965
1966 struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
1967
1968 /*
1969 * Remove LSPs which have aged out
1970 */
1971 for (level = 0; level < ISIS_LEVELS; level++) {
1972 struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
1973 frr_each_from (lspdb, &area->lspdb[level], lsp, next) {
1974 /*
1975 * The lsp rem_lifetime is kept at 0 for MaxAge
1976 * or
1977 * ZeroAgeLifetime depending on explicit purge
1978 * or
1979 * natural age out. So schedule spf only once
1980 * when
1981 * the first time rem_lifetime becomes 0.
1982 */
1983 rem_lifetime = lsp->hdr.rem_lifetime;
1984 lsp_set_time(lsp);
1985
1986 /*
1987 * Schedule may run spf which should be done
1988 * only after
1989 * the lsp rem_lifetime becomes 0 for the first
1990 * time.
1991 * ISO 10589 - 7.3.16.4 first paragraph.
1992 */
1993 if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
1994 /* 7.3.16.4 a) set SRM flags on all */
1995 /* 7.3.16.4 b) retain only the header */
1996 if (lsp->area->purge_originator)
1997 lsp_purge(lsp, lsp->level, NULL);
1998 else
1999 lsp_flood(lsp, NULL);
2000 /* 7.3.16.4 c) record the time to purge
2001 * FIXME */
2002 isis_spf_schedule(lsp->area, lsp->level);
2003 }
2004
2005 if (lsp->age_out == 0) {
2006 zlog_debug(
2007 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2008 area->area_tag, lsp->level,
2009 rawlspid_print(lsp->hdr.lsp_id),
2010 lsp->hdr.seqno);
2011
2012 /* if we're aging out fragment 0, lsp_destroy()
2013 * below will delete all other fragments too,
2014 * so we need to skip over those
2015 */
2016 if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
2017 while (next &&
2018 !memcmp(next->hdr.lsp_id,
2019 lsp->hdr.lsp_id,
2020 ISIS_SYS_ID_LEN + 1))
2021 next = lspdb_next(
2022 &area->lspdb[level],
2023 next);
2024
2025 lspdb_del(&area->lspdb[level], lsp);
2026 lsp_destroy(lsp);
2027 lsp = NULL;
2028 }
2029
2030 if (fabricd_init_c && lsp) {
2031 fabricd_sync_incomplete |=
2032 ISIS_CHECK_FLAG(lsp->SSNflags,
2033 fabricd_init_c);
2034 }
2035 }
2036 }
2037
2038 if (fabricd_init_c
2039 && !fabricd_sync_incomplete
2040 && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
2041 fabricd_initial_sync_finish(area);
2042 }
2043
2044 return ISIS_OK;
2045 }
2046
2047 void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
2048 {
2049 struct isis_lsp *lsp;
2050
2051 lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
2052 if (!lsp)
2053 return;
2054
2055 lsp_purge(lsp, level, NULL);
2056 }
2057
2058 /*
2059 * Purge own LSP that is received and we don't have.
2060 * -> Do as in 7.3.16.4
2061 */
2062 void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
2063 struct isis_area *area)
2064 {
2065 struct isis_lsp *lsp;
2066
2067 /*
2068 * We need to create the LSP to be purged
2069 */
2070 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
2071 lsp->area = area;
2072 lsp->level = level;
2073 lsp_adjust_stream(lsp);
2074 lsp->age_out = ZERO_AGE_LIFETIME;
2075 lsp->area->lsp_purge_count[level - 1]++;
2076
2077 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
2078 lsp->hdr.rem_lifetime = 0;
2079
2080 lsp_purge_add_poi(lsp, NULL);
2081
2082 lsp_pack_pdu(lsp);
2083
2084 lsp_insert(&area->lspdb[lsp->level - 1], lsp);
2085 lsp_flood(lsp, NULL);
2086
2087 return;
2088 }
2089
2090 void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
2091 {
2092 struct listnode *node;
2093 struct isis_circuit *circuit;
2094
2095 assert(lsp);
2096
2097 if (!lsp->area)
2098 return;
2099
2100 struct list *circuit_list = lsp->area->circuit_list;
2101 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
2102 if (set) {
2103 isis_tx_queue_add(circuit->tx_queue, lsp,
2104 TX_LSP_NORMAL);
2105 } else {
2106 isis_tx_queue_del(circuit->tx_queue, lsp);
2107 }
2108 }
2109 }
2110
2111 void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
2112 const char *func, const char *file, int line)
2113 {
2114 if (IS_DEBUG_FLOODING) {
2115 zlog_debug("Flooding LSP %s%s%s (From %s %s:%d)",
2116 rawlspid_print(lsp->hdr.lsp_id),
2117 circuit ? " except on " : "",
2118 circuit ? circuit->interface->name : "",
2119 func, file, line);
2120 }
2121
2122 if (!fabricd)
2123 lsp_set_all_srmflags(lsp, true);
2124 else
2125 fabricd_lsp_flood(lsp, circuit);
2126
2127 if (circuit)
2128 isis_tx_queue_del(circuit->tx_queue, lsp);
2129 }
2130
2131 static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
2132 {
2133 lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
2134
2135 /* when an adjacency state changes determine if we need to
2136 * change attach_bits in other area's LSPs
2137 */
2138 isis_reset_attach_bit(adj);
2139
2140 return 0;
2141 }
2142
2143 /*
2144 * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
2145 * address-family and MT-ID.
2146 */
2147 int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
2148 lsp_ip_reach_iter_cb cb, void *arg)
2149 {
2150 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
2151 struct isis_lsp *frag;
2152 struct listnode *node;
2153
2154 if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
2155 return LSP_ITER_CONTINUE;
2156
2157 /* Parse main LSP. */
2158 if (lsp->tlvs) {
2159 if (!fabricd && !pseudo_lsp && family == AF_INET
2160 && mtid == ISIS_MT_IPV4_UNICAST) {
2161 struct isis_item_list *reachs[] = {
2162 &lsp->tlvs->oldstyle_ip_reach,
2163 &lsp->tlvs->oldstyle_ip_reach_ext};
2164
2165 for (unsigned int i = 0; i < array_size(reachs); i++) {
2166 struct isis_oldstyle_ip_reach *r;
2167
2168 for (r = (struct isis_oldstyle_ip_reach *)
2169 reachs[i]
2170 ->head;
2171 r; r = r->next) {
2172 bool external = i ? true : false;
2173
2174 if ((*cb)((struct prefix *)&r->prefix,
2175 r->metric, external, NULL,
2176 arg)
2177 == LSP_ITER_STOP)
2178 return LSP_ITER_STOP;
2179 }
2180 }
2181 }
2182
2183 if (!pseudo_lsp && family == AF_INET) {
2184 struct isis_item_list *ipv4_reachs;
2185
2186 if (mtid == ISIS_MT_IPV4_UNICAST)
2187 ipv4_reachs = &lsp->tlvs->extended_ip_reach;
2188 else
2189 ipv4_reachs = isis_lookup_mt_items(
2190 &lsp->tlvs->mt_ip_reach, mtid);
2191
2192 struct isis_extended_ip_reach *r;
2193 for (r = ipv4_reachs ? (struct isis_extended_ip_reach *)
2194 ipv4_reachs->head
2195 : NULL;
2196 r; r = r->next) {
2197 if ((*cb)((struct prefix *)&r->prefix,
2198 r->metric, false, r->subtlvs, arg)
2199 == LSP_ITER_STOP)
2200 return LSP_ITER_STOP;
2201 }
2202 }
2203
2204 if (!pseudo_lsp && family == AF_INET6) {
2205 struct isis_item_list *ipv6_reachs;
2206 struct isis_ipv6_reach *r;
2207
2208 if (mtid == ISIS_MT_IPV4_UNICAST)
2209 ipv6_reachs = &lsp->tlvs->ipv6_reach;
2210 else
2211 ipv6_reachs = isis_lookup_mt_items(
2212 &lsp->tlvs->mt_ipv6_reach, mtid);
2213
2214 for (r = ipv6_reachs ? (struct isis_ipv6_reach *)
2215 ipv6_reachs->head
2216 : NULL;
2217 r; r = r->next) {
2218 if ((*cb)((struct prefix *)&r->prefix,
2219 r->metric, r->external, r->subtlvs,
2220 arg)
2221 == LSP_ITER_STOP)
2222 return LSP_ITER_STOP;
2223 }
2224 }
2225 }
2226
2227 /* Parse LSP fragments. */
2228 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2229 if (!frag->tlvs)
2230 continue;
2231
2232 isis_lsp_iterate_ip_reach(frag, family, mtid, cb, arg);
2233 }
2234
2235 return LSP_ITER_CONTINUE;
2236 }
2237
2238 /*
2239 * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
2240 * MT-ID.
2241 */
2242 int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
2243 lsp_is_reach_iter_cb cb, void *arg)
2244 {
2245 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
2246 struct isis_lsp *frag;
2247 struct listnode *node;
2248 struct isis_item *head;
2249 struct isis_item_list *te_neighs;
2250
2251 if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
2252 return LSP_ITER_CONTINUE;
2253
2254 /* Parse main LSP. */
2255 if (lsp->tlvs) {
2256 if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) {
2257 head = lsp->tlvs->oldstyle_reach.head;
2258 for (struct isis_oldstyle_reach *reach =
2259 (struct isis_oldstyle_reach *)head;
2260 reach; reach = reach->next) {
2261 if ((*cb)(reach->id, reach->metric, true, NULL,
2262 arg)
2263 == LSP_ITER_STOP)
2264 return LSP_ITER_STOP;
2265 }
2266 }
2267
2268 if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST)
2269 te_neighs = &lsp->tlvs->extended_reach;
2270 else
2271 te_neighs =
2272 isis_get_mt_items(&lsp->tlvs->mt_reach, mtid);
2273 if (te_neighs) {
2274 head = te_neighs->head;
2275 for (struct isis_extended_reach *reach =
2276 (struct isis_extended_reach *)head;
2277 reach; reach = reach->next) {
2278 if ((*cb)(reach->id, reach->metric, false,
2279 reach->subtlvs, arg)
2280 == LSP_ITER_STOP)
2281 return LSP_ITER_STOP;
2282 }
2283 }
2284 }
2285
2286 /* Parse LSP fragments. */
2287 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2288 if (!frag->tlvs)
2289 continue;
2290
2291 isis_lsp_iterate_is_reach(frag, mtid, cb, arg);
2292 }
2293
2294 return LSP_ITER_CONTINUE;
2295 }
2296
2297 void lsp_init(void)
2298 {
2299 hook_register(isis_adj_state_change_hook,
2300 lsp_handle_adj_state_change);
2301 }