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