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