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