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