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