]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_lsp.c
Merge pull request #1157 from donaldsharp/recursive_blackhole
[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
af8ac8f9
CF
1123 frag = lsp;
1124 for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
1125 if (node != listhead(fragments)) {
1126 frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
1127 lsp, area, level);
d62a17ae 1128 }
af8ac8f9 1129 frag->tlvs = tlvs;
d62a17ae 1130 }
1131
af8ac8f9
CF
1132 list_delete(fragments);
1133 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1134 area->area_tag);
d62a17ae 1135 return;
eb5d44eb 1136}
eb5d44eb 1137
1138/*
3f045a08 1139 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
eb5d44eb 1140 */
d62a17ae 1141int lsp_generate(struct isis_area *area, int level)
f390d2c7 1142{
d62a17ae 1143 struct isis_lsp *oldlsp, *newlsp;
1144 u_int32_t seq_num = 0;
1145 u_char lspid[ISIS_SYS_ID_LEN + 2];
1146 u_int16_t rem_lifetime, refresh_time;
1147
1148 if ((area == NULL) || (area->is_type & level) != level)
1149 return ISIS_ERROR;
1150
1151 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
1152 memcpy(&lspid, isis->sysid, ISIS_SYS_ID_LEN);
1153
1154 /* only builds the lsp if the area shares the level */
1155 oldlsp = lsp_search(lspid, area->lspdb[level - 1]);
1156 if (oldlsp) {
1157 /* FIXME: we should actually initiate a purge */
af8ac8f9
CF
1158 seq_num = oldlsp->hdr.seqno;
1159 lsp_search_and_destroy(oldlsp->hdr.lsp_id,
d62a17ae 1160 area->lspdb[level - 1]);
1161 }
1162 rem_lifetime = lsp_rem_lifetime(area, level);
1163 newlsp =
1164 lsp_new(area, lspid, rem_lifetime, seq_num,
1165 area->is_type | area->overload_bit | area->attached_bit,
8f5dbe18 1166 0, NULL, level);
d62a17ae 1167 newlsp->area = area;
1168 newlsp->own_lsp = 1;
1169
1170 lsp_insert(newlsp, area->lspdb[level - 1]);
1171 /* build_lsp_data (newlsp, area); */
1172 lsp_build(newlsp, area);
1173 /* time to calculate our checksum */
af8ac8f9 1174 lsp_seqno_update(newlsp);
d62a17ae 1175 newlsp->last_generated = time(NULL);
1176 lsp_set_all_srmflags(newlsp);
1177
1178 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
1179
1180 THREAD_TIMER_OFF(area->t_lsp_refresh[level - 1]);
1181 area->lsp_regenerate_pending[level - 1] = 0;
1182 if (level == IS_LEVEL_1)
1183 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
1184 &area->t_lsp_refresh[level - 1]);
1185 else if (level == IS_LEVEL_2)
1186 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
1187 &area->t_lsp_refresh[level - 1]);
1188
1189 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
af8ac8f9
CF
1190 zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
1191 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1192 ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
1193 area->area_tag, level,
1194 rawlspid_print(newlsp->hdr.lsp_id),
1195 newlsp->hdr.pdu_len, newlsp->hdr.seqno,
1196 newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
1197 refresh_time);
d62a17ae 1198 }
1199 sched_debug(
1200 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1201 area->area_tag, level);
1202
1203 return ISIS_OK;
eb5d44eb 1204}
1205
1206/*
3f045a08 1207 * Search own LSPs, update holding time and set SRM
eb5d44eb 1208 */
d62a17ae 1209static int lsp_regenerate(struct isis_area *area, int level)
eb5d44eb 1210{
d62a17ae 1211 dict_t *lspdb;
1212 struct isis_lsp *lsp, *frag;
1213 struct listnode *node;
1214 u_char lspid[ISIS_SYS_ID_LEN + 2];
1215 u_int16_t rem_lifetime, refresh_time;
1216
1217 if ((area == NULL) || (area->is_type & level) != level)
1218 return ISIS_ERROR;
1219
1220 lspdb = area->lspdb[level - 1];
1221
1222 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
1223 memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
1224
1225 lsp = lsp_search(lspid, lspdb);
1226
1227 if (!lsp) {
1228 zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1229 area->area_tag, level);
1230 return ISIS_ERROR;
1231 }
1232
1233 lsp_clear_data(lsp);
1234 lsp_build(lsp, area);
d62a17ae 1235 rem_lifetime = lsp_rem_lifetime(area, level);
af8ac8f9 1236 lsp->hdr.rem_lifetime = rem_lifetime;
d62a17ae 1237 lsp->last_generated = time(NULL);
1238 lsp_set_all_srmflags(lsp);
1239 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
af8ac8f9 1240 frag->hdr.lsp_bits = lsp_bits_generate(
d62a17ae 1241 level, area->overload_bit, area->attached_bit);
1242 /* Set the lifetime values of all the fragments to the same
1243 * value,
1244 * so that no fragment expires before the lsp is refreshed.
1245 */
af8ac8f9 1246 frag->hdr.rem_lifetime = rem_lifetime;
d62a17ae 1247 lsp_set_all_srmflags(frag);
1248 }
af8ac8f9 1249 lsp_seqno_update(lsp);
d62a17ae 1250
1251 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1252 if (level == IS_LEVEL_1)
1253 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
1254 &area->t_lsp_refresh[level - 1]);
1255 else if (level == IS_LEVEL_2)
1256 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
1257 &area->t_lsp_refresh[level - 1]);
1258 area->lsp_regenerate_pending[level - 1] = 0;
1259
1260 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1261 zlog_debug(
af8ac8f9
CF
1262 "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
1263 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1264 ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
1265 area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
1266 lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
1267 lsp->hdr.rem_lifetime, refresh_time);
d62a17ae 1268 }
1269 sched_debug(
1270 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1271 area->area_tag, level);
1272
1273 return ISIS_OK;
eb5d44eb 1274}
1275
eb5d44eb 1276/*
3f045a08 1277 * Something has changed or periodic refresh -> regenerate LSP
eb5d44eb 1278 */
d62a17ae 1279static int lsp_l1_refresh(struct thread *thread)
eb5d44eb 1280{
d62a17ae 1281 struct isis_area *area;
eb5d44eb 1282
d62a17ae 1283 area = THREAD_ARG(thread);
1284 assert(area);
f390d2c7 1285
d62a17ae 1286 area->t_lsp_refresh[0] = NULL;
1287 area->lsp_regenerate_pending[0] = 0;
eb5d44eb 1288
d62a17ae 1289 if ((area->is_type & IS_LEVEL_1) == 0)
1290 return ISIS_ERROR;
d70f99e1 1291
d62a17ae 1292 sched_debug(
1293 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
1294 area->area_tag);
1295 return lsp_regenerate(area, IS_LEVEL_1);
eb5d44eb 1296}
1297
d62a17ae 1298static int lsp_l2_refresh(struct thread *thread)
eb5d44eb 1299{
d62a17ae 1300 struct isis_area *area;
eb5d44eb 1301
d62a17ae 1302 area = THREAD_ARG(thread);
1303 assert(area);
f390d2c7 1304
d62a17ae 1305 area->t_lsp_refresh[1] = NULL;
1306 area->lsp_regenerate_pending[1] = 0;
f390d2c7 1307
d62a17ae 1308 if ((area->is_type & IS_LEVEL_2) == 0)
1309 return ISIS_ERROR;
3f045a08 1310
d62a17ae 1311 sched_debug(
1312 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
1313 area->area_tag);
1314 return lsp_regenerate(area, IS_LEVEL_2);
eb5d44eb 1315}
1316
d62a17ae 1317int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo)
eb5d44eb 1318{
d62a17ae 1319 struct isis_lsp *lsp;
1320 u_char id[ISIS_SYS_ID_LEN + 2];
1321 time_t now, diff;
1322 long timeout;
1323 struct listnode *cnode;
1324 struct isis_circuit *circuit;
1325 int lvl;
1326
1327 if (area == NULL)
1328 return ISIS_ERROR;
1329
1330 sched_debug(
1331 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
1332 area->area_tag, circuit_t2string(level),
1333 all_pseudo ? "" : "not ");
1334
1335 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
1336 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
1337 now = time(NULL);
1338
1339 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1340 if (!((level & lvl) && (area->is_type & lvl)))
1341 continue;
1342
1343 sched_debug(
1344 "ISIS (%s): Checking whether L%d needs to be scheduled",
1345 area->area_tag, lvl);
1346
1347 if (area->lsp_regenerate_pending[lvl - 1]) {
1348 struct timeval remain = thread_timer_remain(
1349 area->t_lsp_refresh[lvl - 1]);
1350 sched_debug(
1351 "ISIS (%s): Regeneration is already pending, nothing todo."
1352 " (Due in %lld.%03lld seconds)",
1353 area->area_tag, (long long)remain.tv_sec,
1354 (long long)remain.tv_usec / 1000);
1355 continue;
1356 }
1357
1358 lsp = lsp_search(id, area->lspdb[lvl - 1]);
1359 if (!lsp) {
1360 sched_debug(
1361 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
1362 area->area_tag);
1363 continue;
1364 }
1365
1366 /*
1367 * Throttle avoidance
1368 */
1369 sched_debug(
1370 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
1371 area->area_tag, (long long)lsp->last_generated,
1372 (long long)now);
1373 THREAD_TIMER_OFF(area->t_lsp_refresh[lvl - 1]);
1374 diff = now - lsp->last_generated;
1375 if (diff < area->lsp_gen_interval[lvl - 1]) {
1376 timeout =
1377 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
1378 sched_debug(
1379 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
1380 area->area_tag, timeout);
1381 } else {
1382 /*
1383 * lsps are not regenerated if lsp_regenerate function
1384 * is called
1385 * directly. However if the lsp_regenerate call is
1386 * queued for
1387 * later execution it works.
1388 */
1389 timeout = 100;
1390 sched_debug(
1391 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1392 " Scheduling for execution in %ld ms.",
1393 area->area_tag, timeout);
1394 }
1395
1396 area->lsp_regenerate_pending[lvl - 1] = 1;
1397 if (lvl == IS_LEVEL_1) {
1398 thread_add_timer_msec(master, lsp_l1_refresh, area,
1399 timeout,
1400 &area->t_lsp_refresh[lvl - 1]);
1401 } else if (lvl == IS_LEVEL_2) {
1402 thread_add_timer_msec(master, lsp_l2_refresh, area,
1403 timeout,
1404 &area->t_lsp_refresh[lvl - 1]);
1405 }
1406 }
1407
1408 if (all_pseudo) {
1409 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
1410 lsp_regenerate_schedule_pseudo(circuit, level);
1411 }
1412
1413 return ISIS_OK;
eb5d44eb 1414}
1415
1416/*
1417 * Funcs for pseudonode LSPs
1418 */
1419
1420/*
d62a17ae 1421 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
eb5d44eb 1422 */
d62a17ae 1423static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
1424 int level)
eb5d44eb 1425{
d62a17ae 1426 struct isis_adjacency *adj;
d62a17ae 1427 struct list *adj_list;
1428 struct listnode *node;
1429 struct isis_area *area = circuit->area;
1430
af8ac8f9
CF
1431 lsp_clear_data(lsp);
1432 lsp->tlvs = isis_alloc_tlvs();
d62a17ae 1433 lsp_debug(
1434 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
af8ac8f9 1435 area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
d62a17ae 1436 circuit->interface->name, level);
1437
1438 lsp->level = level;
1439 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
af8ac8f9 1440 lsp->hdr.lsp_bits =
d62a17ae 1441 lsp_bits_generate(level, 0, circuit->area->attached_bit);
1442
1443 /*
1444 * add self to IS neighbours
1445 */
af8ac8f9
CF
1446 uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
1447
1448 memcpy(ne_id, isis->sysid, ISIS_SYS_ID_LEN);
1449 LSP_PSEUDO_ID(ne_id) = 0;
d62a17ae 1450
af8ac8f9
CF
1451 if (circuit->area->oldmetric) {
1452 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
d62a17ae 1453 lsp_debug(
1454 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
af8ac8f9
CF
1455 area->area_tag, sysid_print(ne_id),
1456 LSP_PSEUDO_ID(ne_id));
d62a17ae 1457 }
1458 if (circuit->area->newmetric) {
af8ac8f9
CF
1459 isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
1460 ne_id, 0, NULL, 0);
d62a17ae 1461 lsp_debug(
1462 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
af8ac8f9
CF
1463 area->area_tag, sysid_print(ne_id),
1464 LSP_PSEUDO_ID(ne_id));
d62a17ae 1465 }
1466
1467 adj_list = list_new();
1468 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
1469
1470 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
af8ac8f9 1471 if (!(adj->level & level)) {
d62a17ae 1472 lsp_debug(
1473 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
1474 area->area_tag, sysid_print(adj->sysid));
af8ac8f9 1475 continue;
f390d2c7 1476 }
d62a17ae 1477
af8ac8f9
CF
1478 if (!(level == IS_LEVEL_1
1479 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
1480 && !(level == IS_LEVEL_1
1481 && adj->sys_type == ISIS_SYSTYPE_L2_IS
1482 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
1483 && !(level == IS_LEVEL_2
1484 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
1485 lsp_debug(
1486 "ISIS (%s): Ignoring neighbor %s, level does not match",
1487 area->area_tag, sysid_print(adj->sysid));
1488 continue;
1489 }
d62a17ae 1490
af8ac8f9
CF
1491 memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
1492 if (circuit->area->oldmetric) {
1493 isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
1494 lsp_debug(
1495 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
1496 area->area_tag, sysid_print(ne_id),
1497 LSP_PSEUDO_ID(ne_id));
1498 }
1499 if (circuit->area->newmetric) {
1500 isis_tlvs_add_extended_reach(lsp->tlvs,
1501 ISIS_MT_IPV4_UNICAST,
1502 ne_id, 0, NULL, 0);
1503 lsp_debug(
1504 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
1505 area->area_tag, sysid_print(ne_id),
1506 LSP_PSEUDO_ID(ne_id));
1507 }
1508 }
1509 list_delete(adj_list);
d62a17ae 1510 return;
eb5d44eb 1511}
1512
d62a17ae 1513int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
3f045a08 1514{
d62a17ae 1515 dict_t *lspdb = circuit->area->lspdb[level - 1];
1516 struct isis_lsp *lsp;
1517 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1518 u_int16_t rem_lifetime, refresh_time;
1519
1520 if ((circuit->is_type & level) != level
1521 || (circuit->state != C_STATE_UP)
1522 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1523 || (circuit->u.bc.is_dr[level - 1] == 0))
1524 return ISIS_ERROR;
1525
1526 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1527 LSP_FRAGMENT(lsp_id) = 0;
1528 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1529
1530 /*
1531 * If for some reason have a pseudo LSP in the db already -> regenerate
1532 */
1533 if (lsp_search(lsp_id, lspdb))
1534 return lsp_regenerate_schedule_pseudo(circuit, level);
1535
1536 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
1537 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1538 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
1539 circuit->area->is_type | circuit->area->attached_bit, 0,
8f5dbe18 1540 NULL, level);
d62a17ae 1541 lsp->area = circuit->area;
1542
1543 lsp_build_pseudo(lsp, circuit, level);
af8ac8f9 1544 lsp_pack_pdu(lsp);
d62a17ae 1545 lsp->own_lsp = 1;
1546 lsp_insert(lsp, lspdb);
1547 lsp_set_all_srmflags(lsp);
1548
1549 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1550 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1551 circuit->lsp_regenerate_pending[level - 1] = 0;
1552 if (level == IS_LEVEL_1)
1553 thread_add_timer(
1554 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1555 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1556 else if (level == IS_LEVEL_2)
1557 thread_add_timer(
1558 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1559 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1560
1561 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1562 zlog_debug(
af8ac8f9
CF
1563 "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
1564 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1565 ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
d62a17ae 1566 circuit->area->area_tag, level,
af8ac8f9
CF
1567 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1568 lsp->hdr.seqno, lsp->hdr.checksum,
1569 lsp->hdr.rem_lifetime, refresh_time);
d62a17ae 1570 }
1571
1572 return ISIS_OK;
3f045a08
JB
1573}
1574
d62a17ae 1575static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
eb5d44eb 1576{
d62a17ae 1577 dict_t *lspdb = circuit->area->lspdb[level - 1];
1578 struct isis_lsp *lsp;
1579 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1580 u_int16_t rem_lifetime, refresh_time;
1581
1582 if ((circuit->is_type & level) != level
1583 || (circuit->state != C_STATE_UP)
1584 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
1585 || (circuit->u.bc.is_dr[level - 1] == 0))
1586 return ISIS_ERROR;
1587
1588 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1589 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1590 LSP_FRAGMENT(lsp_id) = 0;
1591
1592 lsp = lsp_search(lsp_id, lspdb);
1593
1594 if (!lsp) {
1595 zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level,
1596 rawlspid_print(lsp_id));
1597 return ISIS_ERROR;
1598 }
d62a17ae 1599
d62a17ae 1600 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
af8ac8f9
CF
1601 lsp->hdr.rem_lifetime = rem_lifetime;
1602 lsp_build_pseudo(lsp, circuit, level);
1603 lsp_inc_seqno(lsp, 0);
d62a17ae 1604 lsp->last_generated = time(NULL);
1605 lsp_set_all_srmflags(lsp);
1606
1607 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
1608 if (level == IS_LEVEL_1)
1609 thread_add_timer(
1610 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
1611 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1612 else if (level == IS_LEVEL_2)
1613 thread_add_timer(
1614 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
1615 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1616
1617 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
1618 zlog_debug(
af8ac8f9
CF
1619 "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
1620 ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
1621 ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
d62a17ae 1622 circuit->area->area_tag, level,
af8ac8f9
CF
1623 rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
1624 lsp->hdr.seqno, lsp->hdr.checksum,
1625 lsp->hdr.rem_lifetime, refresh_time);
d62a17ae 1626 }
1627
1628 return ISIS_OK;
eb5d44eb 1629}
1630
3f045a08
JB
1631/*
1632 * Something has changed or periodic refresh -> regenerate pseudo LSP
1633 */
d62a17ae 1634static int lsp_l1_refresh_pseudo(struct thread *thread)
eb5d44eb 1635{
d62a17ae 1636 struct isis_circuit *circuit;
1637 u_char id[ISIS_SYS_ID_LEN + 2];
eb5d44eb 1638
d62a17ae 1639 circuit = THREAD_ARG(thread);
f390d2c7 1640
d62a17ae 1641 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
1642 circuit->lsp_regenerate_pending[0] = 0;
13c48f72 1643
d62a17ae 1644 if ((circuit->u.bc.is_dr[0] == 0)
1645 || (circuit->is_type & IS_LEVEL_1) == 0) {
1646 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
1647 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1648 LSP_FRAGMENT(id) = 0;
1649 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
1650 return ISIS_ERROR;
1651 }
eb5d44eb 1652
d62a17ae 1653 return lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
eb5d44eb 1654}
1655
d62a17ae 1656static int lsp_l2_refresh_pseudo(struct thread *thread)
eb5d44eb 1657{
d62a17ae 1658 struct isis_circuit *circuit;
1659 u_char id[ISIS_SYS_ID_LEN + 2];
f390d2c7 1660
d62a17ae 1661 circuit = THREAD_ARG(thread);
f390d2c7 1662
d62a17ae 1663 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
1664 circuit->lsp_regenerate_pending[1] = 0;
13c48f72 1665
d62a17ae 1666 if ((circuit->u.bc.is_dr[1] == 0)
1667 || (circuit->is_type & IS_LEVEL_2) == 0) {
1668 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
1669 LSP_PSEUDO_ID(id) = circuit->circuit_id;
1670 LSP_FRAGMENT(id) = 0;
1671 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
1672 return ISIS_ERROR;
1673 }
eb5d44eb 1674
d62a17ae 1675 return lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
eb5d44eb 1676}
1677
d62a17ae 1678int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
eb5d44eb 1679{
d62a17ae 1680 struct isis_lsp *lsp;
1681 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1682 time_t now, diff;
1683 long timeout;
1684 int lvl;
1685 struct isis_area *area = circuit->area;
1686
1687 if (circuit->circ_type != CIRCUIT_T_BROADCAST
1688 || circuit->state != C_STATE_UP)
1689 return ISIS_OK;
1690
1691 sched_debug(
1692 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
1693 area->area_tag, circuit_t2string(level),
1694 circuit->interface->name);
1695
1696 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1697 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
1698 LSP_FRAGMENT(lsp_id) = 0;
1699 now = time(NULL);
1700
1701 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
1702 sched_debug(
1703 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
1704 area->area_tag, lvl);
1705
1706 if (!((level & lvl) && (circuit->is_type & lvl))) {
1707 sched_debug("ISIS (%s): Level is not active on circuit",
1708 area->area_tag);
1709 continue;
1710 }
1711
1712 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
1713 sched_debug(
1714 "ISIS (%s): This IS is not DR, nothing to do.",
1715 area->area_tag);
1716 continue;
1717 }
1718
1719 if (circuit->lsp_regenerate_pending[lvl - 1]) {
1720 struct timeval remain = thread_timer_remain(
1721 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1722 sched_debug(
1723 "ISIS (%s): Regenerate is already pending, nothing todo."
1724 " (Due in %lld.%03lld seconds)",
1725 area->area_tag, (long long)remain.tv_sec,
1726 (long long)remain.tv_usec / 1000);
1727 continue;
1728 }
1729
1730 lsp = lsp_search(lsp_id, circuit->area->lspdb[lvl - 1]);
1731 if (!lsp) {
1732 sched_debug(
1733 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
1734 area->area_tag);
1735 continue;
1736 }
1737
1738 /*
1739 * Throttle avoidance
1740 */
1741 sched_debug(
1742 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
1743 area->area_tag, (long long)lsp->last_generated,
1744 (long long)now);
1745 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1746 diff = now - lsp->last_generated;
1747 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
9d303b37
DL
1748 timeout =
1749 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
1750 - diff);
d62a17ae 1751 sched_debug(
1752 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
1753 area->area_tag, timeout);
1754 } else {
1755 timeout = 100;
1756 sched_debug(
1757 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
1758 " Scheduling for execution in %ld ms.",
1759 area->area_tag, timeout);
1760 }
1761
1762 circuit->lsp_regenerate_pending[lvl - 1] = 1;
1763
1764 if (lvl == IS_LEVEL_1) {
1765 thread_add_timer_msec(
1766 master, lsp_l1_refresh_pseudo, circuit, timeout,
1767 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1768 } else if (lvl == IS_LEVEL_2) {
1769 thread_add_timer_msec(
1770 master, lsp_l2_refresh_pseudo, circuit, timeout,
1771 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
1772 }
1773 }
1774
1775 return ISIS_OK;
f390d2c7 1776}
eb5d44eb 1777
1778/*
1779 * Walk through LSPs for an area
1780 * - set remaining lifetime
1781 * - set LSPs with SRMflag set for sending
1782 */
d62a17ae 1783int lsp_tick(struct thread *thread)
eb5d44eb 1784{
d62a17ae 1785 struct isis_area *area;
1786 struct isis_circuit *circuit;
1787 struct isis_lsp *lsp;
1788 struct list *lsp_list;
1789 struct listnode *lspnode, *cnode;
1790 dnode_t *dnode, *dnode_next;
1791 int level;
1792 u_int16_t rem_lifetime;
1793
1794 lsp_list = list_new();
1795
1796 area = THREAD_ARG(thread);
1797 assert(area);
1798 area->t_tick = NULL;
1799 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
1800
1801 /*
1802 * Build a list of LSPs with (any) SRMflag set
1803 * and removed the ones that have aged out
1804 */
1805 for (level = 0; level < ISIS_LEVELS; level++) {
1806 if (area->lspdb[level] && dict_count(area->lspdb[level]) > 0) {
1807 for (dnode = dict_first(area->lspdb[level]);
1808 dnode != NULL; dnode = dnode_next) {
1809 dnode_next =
1810 dict_next(area->lspdb[level], dnode);
1811 lsp = dnode_get(dnode);
1812
1813 /*
1814 * The lsp rem_lifetime is kept at 0 for MaxAge
1815 * or
1816 * ZeroAgeLifetime depending on explicit purge
1817 * or
1818 * natural age out. So schedule spf only once
1819 * when
1820 * the first time rem_lifetime becomes 0.
1821 */
af8ac8f9 1822 rem_lifetime = lsp->hdr.rem_lifetime;
d62a17ae 1823 lsp_set_time(lsp);
1824
1825 /*
1826 * Schedule may run spf which should be done
1827 * only after
1828 * the lsp rem_lifetime becomes 0 for the first
1829 * time.
1830 * ISO 10589 - 7.3.16.4 first paragraph.
1831 */
af8ac8f9 1832 if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
d62a17ae 1833 /* 7.3.16.4 a) set SRM flags on all */
1834 lsp_set_all_srmflags(lsp);
1835 /* 7.3.16.4 b) retain only the header
1836 * FIXME */
1837 /* 7.3.16.4 c) record the time to purge
1838 * FIXME */
1839 /* run/schedule spf */
1840 /* isis_spf_schedule is called inside
1841 * lsp_destroy() below;
1842 * so it is not needed here. */
1843 /* isis_spf_schedule (lsp->area,
1844 * lsp->level); */
1845 }
1846
1847 if (lsp->age_out == 0) {
1848 zlog_debug(
af8ac8f9
CF
1849 "ISIS-Upd (%s): L%u LSP %s seq "
1850 "0x%08" PRIx32 " aged out",
d62a17ae 1851 area->area_tag, lsp->level,
af8ac8f9
CF
1852 rawlspid_print(lsp->hdr.lsp_id),
1853 lsp->hdr.seqno);
d62a17ae 1854 lsp_destroy(lsp);
1855 lsp = NULL;
1856 dict_delete_free(area->lspdb[level],
1857 dnode);
1858 } else if (flags_any_set(lsp->SRMflags))
1859 listnode_add(lsp_list, lsp);
1860 }
1861
1862 /*
1863 * Send LSPs on circuits indicated by the SRMflags
1864 */
1865 if (listcount(lsp_list) > 0) {
1866 for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
1867 cnode, circuit)) {
1868 int diff =
1869 time(NULL)
1870 - circuit->lsp_queue_last_cleared;
1871 if (circuit->lsp_queue == NULL
1872 || diff < MIN_LSP_TRANS_INTERVAL)
1873 continue;
1874 for (ALL_LIST_ELEMENTS_RO(
1875 lsp_list, lspnode, lsp)) {
1876 if (circuit->upadjcount
1877 [lsp->level - 1]
1878 && ISIS_CHECK_FLAG(
1879 lsp->SRMflags,
1880 circuit)) {
1881 /* Add the lsp only if
1882 * it is not already in
1883 * lsp
1884 * queue */
1885 if (!listnode_lookup(
1886 circuit->lsp_queue,
1887 lsp)) {
1888 listnode_add(
1889 circuit->lsp_queue,
1890 lsp);
1891 thread_add_event(
1892 master,
1893 send_lsp,
1894 circuit,
1895 0,
1896 NULL);
1897 }
1898 }
1899 }
1900 }
1901 list_delete_all_node(lsp_list);
1902 }
1903 }
1904 }
1905
1906 list_delete(lsp_list);
1907
1908 return ISIS_OK;
eb5d44eb 1909}
1910
d62a17ae 1911void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level)
eb5d44eb 1912{
d62a17ae 1913 struct isis_lsp *lsp;
d62a17ae 1914
1915 lsp = lsp_search(id, circuit->area->lspdb[level - 1]);
1916 if (!lsp)
1917 return;
1918
af8ac8f9 1919 lsp_purge(lsp, level);
eb5d44eb 1920}
1921
1922/*
d62a17ae 1923 * Purge own LSP that is received and we don't have.
eb5d44eb 1924 * -> Do as in 7.3.16.4
1925 */
af8ac8f9 1926void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
d62a17ae 1927 struct isis_area *area)
eb5d44eb 1928{
d62a17ae 1929 struct isis_lsp *lsp;
1930
1931 /*
1932 * We need to create the LSP to be purged
1933 */
1934 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
1935 lsp->area = area;
1936 lsp->level = level;
1937 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
af8ac8f9 1938 lsp->age_out = ZERO_AGE_LIFETIME;
d62a17ae 1939
af8ac8f9
CF
1940 memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
1941 lsp->hdr.rem_lifetime = 0;
d62a17ae 1942
af8ac8f9 1943 lsp_pack_pdu(lsp);
d62a17ae 1944
d62a17ae 1945 lsp_insert(lsp, area->lspdb[lsp->level - 1]);
d62a17ae 1946 lsp_set_all_srmflags(lsp);
1947
1948 return;
eb5d44eb 1949}
1950
d62a17ae 1951void lsp_set_all_srmflags(struct isis_lsp *lsp)
3f045a08 1952{
d62a17ae 1953 struct listnode *node;
1954 struct isis_circuit *circuit;
3f045a08 1955
d62a17ae 1956 assert(lsp);
3f045a08 1957
d62a17ae 1958 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
3f045a08 1959
d62a17ae 1960 if (lsp->area) {
1961 struct list *circuit_list = lsp->area->circuit_list;
1962 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
1963 ISIS_SET_FLAG(lsp->SRMflags, circuit);
1964 }
1965 }
3f045a08 1966}