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