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