]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_lsp.c
isisd: send/receive *SNPs with new parser
[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"
47#include "isisd/isis_tlv.h"
48#include "isisd/isis_lsp.h"
49#include "isisd/isis_pdu.h"
50#include "isisd/isis_dynhn.h"
51#include "isisd/isis_misc.h"
eb5d44eb 52#include "isisd/isis_csm.h"
53#include "isisd/isis_adjacency.h"
54#include "isisd/isis_spf.h"
f8c06e2c 55#include "isisd/isis_te.h"
99894f9a 56#include "isisd/isis_mt.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
108 if (lsp->tlv_data.hostname)
109 isis_dynhn_remove(lsp->lsp_header->lsp_id);
110
111 if (lsp->own_lsp) {
112 if (lsp->tlv_data.nlpids)
113 XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
114 if (lsp->tlv_data.hostname)
115 XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
116 if (lsp->tlv_data.router_id)
117 XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
118 }
119
120 free_tlvs(&lsp->tlv_data);
eb5d44eb 121}
122
d62a17ae 123static void lsp_destroy(struct isis_lsp *lsp)
eb5d44eb 124{
d62a17ae 125 struct listnode *cnode, *lnode, *lnnode;
126 struct isis_lsp *lsp_in_list;
127 struct isis_circuit *circuit;
128
129 if (!lsp)
130 return;
131
132 if (lsp->area->circuit_list) {
133 for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode,
134 circuit)) {
135 if (circuit->lsp_queue == NULL)
136 continue;
137 for (ALL_LIST_ELEMENTS(circuit->lsp_queue, lnode,
138 lnnode, lsp_in_list))
139 if (lsp_in_list == lsp)
140 list_delete_node(circuit->lsp_queue,
141 lnode);
142 }
143 }
144 ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
145 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
146
147 lsp_clear_data(lsp);
148
149 if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) {
150 list_delete(lsp->lspu.frags);
151 lsp->lspu.frags = NULL;
152 }
153
154 isis_spf_schedule(lsp->area, lsp->level);
155
156 if (lsp->pdu)
157 stream_free(lsp->pdu);
158 XFREE(MTYPE_ISIS_LSP, lsp);
eb5d44eb 159}
160
d62a17ae 161void lsp_db_destroy(dict_t *lspdb)
eb5d44eb 162{
d62a17ae 163 dnode_t *dnode, *next;
164 struct isis_lsp *lsp;
165
166 dnode = dict_first(lspdb);
167 while (dnode) {
168 next = dict_next(lspdb, dnode);
169 lsp = dnode_get(dnode);
170 lsp_destroy(lsp);
171 dict_delete_free(lspdb, dnode);
172 dnode = next;
173 }
174
175 dict_free(lspdb);
176
177 return;
eb5d44eb 178}
179
180/*
181 * Remove all the frags belonging to the given lsp
182 */
d62a17ae 183static void lsp_remove_frags(struct list *frags, dict_t *lspdb)
eb5d44eb 184{
d62a17ae 185 dnode_t *dnode;
186 struct listnode *lnode, *lnnode;
187 struct isis_lsp *lsp;
188
189 for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
190 dnode = dict_lookup(lspdb, lsp->lsp_header->lsp_id);
191 lsp_destroy(lsp);
192 dnode_destroy(dict_delete(lspdb, dnode));
193 }
f390d2c7 194
d62a17ae 195 list_delete_all_node(frags);
f390d2c7 196
d62a17ae 197 return;
eb5d44eb 198}
199
d62a17ae 200void lsp_search_and_destroy(u_char *id, dict_t *lspdb)
eb5d44eb 201{
d62a17ae 202 dnode_t *node;
203 struct isis_lsp *lsp;
204
205 node = dict_lookup(lspdb, id);
206 if (node) {
207 node = dict_delete(lspdb, node);
208 lsp = dnode_get(node);
209 /*
210 * If this is a zero lsp, remove all the frags now
211 */
212 if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0) {
213 if (lsp->lspu.frags)
214 lsp_remove_frags(lsp->lspu.frags, lspdb);
215 } else {
216 /*
217 * else just remove this frag, from the zero lsps' frag
218 * list
219 */
220 if (lsp->lspu.zero_lsp
221 && lsp->lspu.zero_lsp->lspu.frags)
222 listnode_delete(lsp->lspu.zero_lsp->lspu.frags,
223 lsp);
224 }
225 lsp_destroy(lsp);
226 dnode_destroy(node);
227 }
eb5d44eb 228}
229
230/*
231 * Compares a LSP to given values
232 * Params are given in net order
233 */
d62a17ae 234int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
235 u_int16_t checksum, u_int16_t rem_lifetime)
eb5d44eb 236{
17c9dcd5
CF
237 seq_num = htonl(seq_num);
238 checksum = htons(checksum);
239 rem_lifetime = htons(rem_lifetime);
240
d62a17ae 241 /* no point in double ntohl on seqnum */
242 if (lsp->lsp_header->seq_num == seq_num
243 && lsp->lsp_header->checksum == checksum &&
244 /*comparing with 0, no need to do ntohl */
245 ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0)
246 || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) {
247 if (isis->debugs & DEBUG_SNP_PACKETS) {
248 zlog_debug(
249 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
250 " lifetime %us",
251 areatag,
252 rawlspid_print(lsp->lsp_header->lsp_id),
253 ntohl(lsp->lsp_header->seq_num),
254 ntohs(lsp->lsp_header->checksum),
255 ntohs(lsp->lsp_header->rem_lifetime));
256 zlog_debug(
257 "ISIS-Snp (%s): is equal to ours seq 0x%08x,"
258 " cksum 0x%04x, lifetime %us",
259 areatag, ntohl(seq_num), ntohs(checksum),
260 ntohs(rem_lifetime));
261 }
262 return LSP_EQUAL;
263 }
264
265 /*
266 * LSPs with identical checksums should only be treated as newer if:
267 * a) The current LSP has a remaining lifetime != 0 and the other LSP
268 * has a
269 * remaining lifetime == 0. In this case, we should participate in
270 * the purge
271 * and should not treat the current LSP with remaining lifetime == 0
272 * as older.
273 * b) The LSP has an incorrect checksum. In this case, we need to react
274 * as given
275 * in 7.3.16.2.
276 */
277 if (ntohl(seq_num) > ntohl(lsp->lsp_header->seq_num)
278 || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
279 && ((lsp->lsp_header->rem_lifetime != 0 && rem_lifetime == 0)
280 || lsp->lsp_header->checksum != checksum))) {
281 if (isis->debugs & DEBUG_SNP_PACKETS) {
282 zlog_debug(
283 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
284 " lifetime %us",
285 areatag,
286 rawlspid_print(lsp->lsp_header->lsp_id),
287 ntohl(seq_num), ntohs(checksum),
288 ntohs(rem_lifetime));
289 zlog_debug(
290 "ISIS-Snp (%s): is newer than ours seq 0x%08x, "
291 "cksum 0x%04x, lifetime %us",
292 areatag, ntohl(lsp->lsp_header->seq_num),
293 ntohs(lsp->lsp_header->checksum),
294 ntohs(lsp->lsp_header->rem_lifetime));
295 }
296 return LSP_NEWER;
297 }
298 if (isis->debugs & DEBUG_SNP_PACKETS) {
299 zlog_debug(
300 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
301 areatag, rawlspid_print(lsp->lsp_header->lsp_id),
302 ntohl(seq_num), ntohs(checksum), ntohs(rem_lifetime));
303 zlog_debug(
304 "ISIS-Snp (%s): is older than ours seq 0x%08x,"
305 " cksum 0x%04x, lifetime %us",
306 areatag, ntohl(lsp->lsp_header->seq_num),
307 ntohs(lsp->lsp_header->checksum),
308 ntohs(lsp->lsp_header->rem_lifetime));
309 }
310
311 return LSP_OLDER;
eb5d44eb 312}
313
d62a17ae 314static void lsp_auth_add(struct isis_lsp *lsp)
3f045a08 315{
d62a17ae 316 struct isis_passwd *passwd;
317 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
318
319 /*
320 * Add the authentication info if its present
321 */
322 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
323 : (passwd = &lsp->area->domain_passwd);
324 switch (passwd->type) {
325 /* Cleartext */
326 case ISIS_PASSWD_TYPE_CLEARTXT:
327 memcpy(&lsp->tlv_data.auth_info, passwd,
328 sizeof(struct isis_passwd));
329 tlv_add_authinfo(passwd->type, passwd->len, passwd->passwd,
330 lsp->pdu);
331 break;
332
333 /* HMAC MD5 */
334 case ISIS_PASSWD_TYPE_HMAC_MD5:
335 /* Remember where TLV is written so we can later
336 * overwrite the MD5 hash */
337 lsp->auth_tlv_offset = stream_get_endp(lsp->pdu);
338 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
339 lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
340 lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
341 memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
342 ISIS_AUTH_MD5_SIZE);
343 tlv_add_authinfo(passwd->type, ISIS_AUTH_MD5_SIZE,
344 hmac_md5_hash, lsp->pdu);
345 break;
346
347 default:
348 break;
349 }
3f045a08
JB
350}
351
d62a17ae 352static void lsp_auth_update(struct isis_lsp *lsp)
3f045a08 353{
d62a17ae 354 struct isis_passwd *passwd;
355 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
356 uint16_t checksum, rem_lifetime;
357
358 /* For HMAC MD5 we need to recompute the md5 hash and store it */
359 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
360 : (passwd = &lsp->area->domain_passwd);
361 if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
362 return;
363
364 /*
365 * In transient conditions (when net is configured where authentication
366 * config and lsp regenerate schedule is not yet run), there could be
367 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
368 * return, when lsp_regenerate is run, lsp will have auth tlv.
369 */
370 if (lsp->auth_tlv_offset == 0)
371 return;
372
373 /*
374 * RFC 5304 set auth value, checksum and remaining lifetime to zero
375 * before computation and reset to old values after computation.
376 */
377 checksum = lsp->lsp_header->checksum;
378 rem_lifetime = lsp->lsp_header->rem_lifetime;
379 lsp->lsp_header->checksum = 0;
380 lsp->lsp_header->rem_lifetime = 0;
381 /* Set the authentication value as well to zero */
382 memset(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, 0,
383 ISIS_AUTH_MD5_SIZE);
384 /* Compute autentication value */
385 hmac_md5(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu),
386 (unsigned char *)&passwd->passwd, passwd->len,
387 (unsigned char *)&hmac_md5_hash);
388 /* Copy the hash into the stream */
389 memcpy(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash,
390 ISIS_AUTH_MD5_SIZE);
391 memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
392 ISIS_AUTH_MD5_SIZE);
393 /* Copy back the checksum and remaining lifetime */
394 lsp->lsp_header->checksum = checksum;
395 lsp->lsp_header->rem_lifetime = rem_lifetime;
3f045a08
JB
396}
397
d62a17ae 398void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num)
eb5d44eb 399{
d62a17ae 400 u_int32_t newseq;
401
402 if (seq_num == 0 || ntohl(lsp->lsp_header->seq_num) > seq_num)
403 newseq = ntohl(lsp->lsp_header->seq_num) + 1;
404 else
405 newseq = seq_num + 1;
406
407 lsp->lsp_header->seq_num = htonl(newseq);
408
409 /* Recompute authentication and checksum information */
410 lsp_auth_update(lsp);
411 /* ISO 10589 - 7.3.11 Generation of the checksum
412 * The checksum shall be computed over all fields in the LSP which
413 * appear
414 * after the Remaining Lifetime field. This field (and those appearing
415 * before it) are excluded so that the LSP may be aged by systems
416 * without
417 * requiring recomputation.
418 */
419 fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
420 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
421
422 isis_spf_schedule(lsp->area, lsp->level);
423
424 return;
eb5d44eb 425}
426
427/*
428 * Genetates checksum for LSP and its frags
429 */
d62a17ae 430static void lsp_seqnum_update(struct isis_lsp *lsp0)
eb5d44eb 431{
d62a17ae 432 struct isis_lsp *lsp;
433 struct listnode *node;
f390d2c7 434
d62a17ae 435 lsp_inc_seqnum(lsp0, 0);
eb5d44eb 436
d62a17ae 437 if (!lsp0->lspu.frags)
438 return;
eb5d44eb 439
d62a17ae 440 for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp))
441 lsp_inc_seqnum(lsp, 0);
f390d2c7 442
d62a17ae 443 return;
eb5d44eb 444}
445
d62a17ae 446static u_int8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
e38e0df0 447{
d62a17ae 448 u_int8_t lsp_bits = 0;
449 if (level == IS_LEVEL_1)
450 lsp_bits = IS_LEVEL_1;
451 else
452 lsp_bits = IS_LEVEL_1_AND_2;
453 if (overload_bit)
454 lsp_bits |= overload_bit;
455 if (attached_bit)
456 lsp_bits |= attached_bit;
457 return lsp_bits;
e38e0df0
SV
458}
459
d62a17ae 460static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
461 struct isis_area *area, int level)
eb5d44eb 462{
d62a17ae 463 uint32_t expected = 0, found;
464 int retval;
465
466 /* free the old lsp data */
467 lsp_clear_data(lsp);
468
469 /* copying only the relevant part of our stream */
470 if (lsp->pdu != NULL)
471 stream_free(lsp->pdu);
472 lsp->pdu = stream_dup(stream);
473
474 /* setting pointers to the correct place */
d62a17ae 475 lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
476 + ISIS_FIXED_HDR_LEN);
477 lsp->area = area;
478 lsp->level = level;
479 lsp->age_out = ZERO_AGE_LIFETIME;
480 lsp->installed = time(NULL);
481 /*
482 * Get LSP data i.e. TLVs
483 */
484 expected |= TLVFLAG_AUTH_INFO;
485 expected |= TLVFLAG_AREA_ADDRS;
486 expected |= TLVFLAG_IS_NEIGHS;
487 expected |= TLVFLAG_NLPID;
488 if (area->dynhostname)
489 expected |= TLVFLAG_DYN_HOSTNAME;
490 if (area->newmetric) {
491 expected |= TLVFLAG_TE_IS_NEIGHS;
492 expected |= TLVFLAG_TE_IPV4_REACHABILITY;
493 expected |= TLVFLAG_TE_ROUTER_ID;
494 }
495 expected |= TLVFLAG_MT_ROUTER_INFORMATION;
496 expected |= TLVFLAG_IPV4_ADDR;
497 expected |= TLVFLAG_IPV4_INT_REACHABILITY;
498 expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
499 expected |= TLVFLAG_IPV6_ADDR;
500 expected |= TLVFLAG_IPV6_REACHABILITY;
501
502 retval = parse_tlvs(area->area_tag,
503 STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
504 + ISIS_LSP_HDR_LEN,
505 ntohs(lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
506 - ISIS_LSP_HDR_LEN,
507 &expected, &found, &lsp->tlv_data, NULL);
508 if (retval != ISIS_OK) {
509 zlog_warn("Could not parse LSP");
510 return;
511 }
512
513 if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) {
514 isis_dynhn_insert(lsp->lsp_header->lsp_id,
515 lsp->tlv_data.hostname,
516 (lsp->lsp_header->lsp_bits & LSPBIT_IST)
517 == IS_LEVEL_1_AND_2
518 ? IS_LEVEL_2
519 : IS_LEVEL_1);
520 }
521
522 return;
eb5d44eb 523}
524
d62a17ae 525void lsp_update(struct isis_lsp *lsp, struct stream *stream,
526 struct isis_area *area, int level)
eb5d44eb 527{
d62a17ae 528 dnode_t *dnode = NULL;
529
530 /* Remove old LSP from database. This is required since the
531 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
532 * and will update it with the new data in the stream. */
533 dnode = dict_lookup(area->lspdb[level - 1], lsp->lsp_header->lsp_id);
534 if (dnode)
535 dnode_destroy(dict_delete(area->lspdb[level - 1], dnode));
536
537 if (lsp->own_lsp) {
538 zlog_err(
539 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
540 area->area_tag,
541 rawlspid_print(lsp->lsp_header->lsp_id));
542 lsp_clear_data(lsp);
543 lsp->own_lsp = 0;
544 }
545
546 /* rebuild the lsp data */
547 lsp_update_data(lsp, stream, area, level);
548
549 /* insert the lsp back into the database */
550 lsp_insert(lsp, area->lspdb[level - 1]);
eb5d44eb 551}
552
eb5d44eb 553/* creation of LSP directly from what we received */
d62a17ae 554struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
555 u_int16_t pdu_len,
556 struct isis_lsp *lsp0,
557 struct isis_area *area, int level)
eb5d44eb 558{
d62a17ae 559 struct isis_lsp *lsp;
560
561 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
562 lsp_update_data(lsp, stream, area, level);
563
564 if (lsp0 == NULL) {
565 /*
566 * zero lsp -> create the list for fragments
567 */
568 lsp->lspu.frags = list_new();
569 } else {
570 /*
571 * a fragment -> set the backpointer and add this to zero lsps
572 * frag list
573 */
574 lsp->lspu.zero_lsp = lsp0;
575 listnode_add(lsp0->lspu.frags, lsp);
576 }
577
578 return lsp;
eb5d44eb 579}
580
d62a17ae 581struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
582 u_int16_t rem_lifetime, u_int32_t seq_num,
583 u_int8_t lsp_bits, u_int16_t checksum, int level)
eb5d44eb 584{
d62a17ae 585 struct isis_lsp *lsp;
88f9d911
CF
586 uint8_t pdu_type =
587 (level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
d62a17ae 588
589 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
590 lsp->area = area;
591
592 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
593 if (LSP_FRAGMENT(lsp_id) == 0)
594 lsp->lspu.frags = list_new();
d62a17ae 595
88f9d911 596 fill_fixed_hdr(pdu_type, lsp->pdu);
d62a17ae 597
598 /* now for the LSP HEADER */
599 /* Minimal LSP PDU size */
88f9d911
CF
600 lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
601 + ISIS_FIXED_HDR_LEN);
d62a17ae 602 lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
603 memcpy(lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
17c9dcd5 604 lsp->lsp_header->checksum = htons(checksum);
d62a17ae 605 lsp->lsp_header->seq_num = htonl(seq_num);
606 lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
607 lsp->lsp_header->lsp_bits = lsp_bits;
608 lsp->level = level;
609 lsp->age_out = ZERO_AGE_LIFETIME;
610
611 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
612
613 if (isis->debugs & DEBUG_EVENTS)
614 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
615 sysid_print(lsp_id),
616 LSP_PSEUDO_ID(lsp->lsp_header->lsp_id),
617 LSP_FRAGMENT(lsp->lsp_header->lsp_id),
618 ntohl(lsp->lsp_header->pdu_len),
619 ntohl(lsp->lsp_header->seq_num));
620
621 return lsp;
eb5d44eb 622}
623
d62a17ae 624void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb)
eb5d44eb 625{
d62a17ae 626 dict_alloc_insert(lspdb, lsp->lsp_header->lsp_id, lsp);
627 if (lsp->lsp_header->seq_num != 0) {
628 isis_spf_schedule(lsp->area, lsp->level);
629 }
eb5d44eb 630}
631
632/*
633 * Build a list of LSPs with non-zero ht bounded by start and stop ids
634 */
d62a17ae 635void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
636 struct list *list, dict_t *lspdb)
eb5d44eb 637{
d62a17ae 638 dnode_t *first, *last, *curr;
eb5d44eb 639
d62a17ae 640 first = dict_lower_bound(lspdb, start_id);
641 if (!first)
642 return;
f390d2c7 643
d62a17ae 644 last = dict_upper_bound(lspdb, stop_id);
f390d2c7 645
d62a17ae 646 curr = first;
f390d2c7 647
d62a17ae 648 if (((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime)
649 listnode_add(list, first->dict_data);
eb5d44eb 650
d62a17ae 651 while (curr) {
652 curr = dict_next(lspdb, curr);
653 if (curr
654 && ((struct isis_lsp *)(curr->dict_data))
655 ->lsp_header->rem_lifetime)
656 listnode_add(list, curr->dict_data);
657 if (curr == last)
658 break;
659 }
f390d2c7 660
d62a17ae 661 return;
eb5d44eb 662}
663
d62a17ae 664static void lsp_set_time(struct isis_lsp *lsp)
eb5d44eb 665{
d62a17ae 666 assert(lsp);
f390d2c7 667
d62a17ae 668 if (lsp->lsp_header->rem_lifetime == 0) {
669 if (lsp->age_out > 0)
670 lsp->age_out--;
671 return;
672 }
eb5d44eb 673
d62a17ae 674 lsp->lsp_header->rem_lifetime =
675 htons(ntohs(lsp->lsp_header->rem_lifetime) - 1);
eb5d44eb 676}
677
d62a17ae 678static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
eb5d44eb 679{
d62a17ae 680 struct isis_dynhn *dyn = NULL;
681 u_char id[SYSID_STRLEN];
682
683 if (dynhost)
684 dyn = dynhn_find_by_id(lsp_id);
685 else
686 dyn = NULL;
687
688 if (dyn)
689 sprintf((char *)id, "%.14s", dyn->name.name);
690 else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
691 sprintf((char *)id, "%.14s", unix_hostname());
692 else
693 memcpy(id, sysid_print(lsp_id), 15);
694 if (frag)
695 sprintf((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID(lsp_id),
696 LSP_FRAGMENT(lsp_id));
697 else
698 sprintf((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id));
eb5d44eb 699}
700
f390d2c7 701/* Convert the lsp attribute bits to attribute string */
d62a17ae 702const char *lsp_bits2string(u_char *lsp_bits)
f390d2c7 703{
d62a17ae 704 char *pos = lsp_bits_string;
eb5d44eb 705
d62a17ae 706 if (!*lsp_bits)
707 return " none";
eb5d44eb 708
d62a17ae 709 /* we only focus on the default metric */
710 pos += sprintf(pos, "%d/",
711 ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits) ? 1 : 0);
eb5d44eb 712
d62a17ae 713 pos += sprintf(pos, "%d/",
714 ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits) ? 1 : 0);
f390d2c7 715
d62a17ae 716 pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits) ? 1 : 0);
eb5d44eb 717
d62a17ae 718 *(pos) = '\0';
eb5d44eb 719
d62a17ae 720 return lsp_bits_string;
eb5d44eb 721}
722
723/* this function prints the lsp on show isis database */
d62a17ae 724void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
eb5d44eb 725{
d62a17ae 726 u_char LSPid[255];
727 char age_out[8];
728
729 lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
730 vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
731 vty_out(vty, "%5u ", ntohs(lsp->lsp_header->pdu_len));
732 vty_out(vty, "0x%08x ", ntohl(lsp->lsp_header->seq_num));
733 vty_out(vty, "0x%04x ", ntohs(lsp->lsp_header->checksum));
734 if (ntohs(lsp->lsp_header->rem_lifetime) == 0) {
735 snprintf(age_out, 8, "(%u)", lsp->age_out);
736 age_out[7] = '\0';
737 vty_out(vty, "%7s ", age_out);
738 } else
739 vty_out(vty, " %5u ", ntohs(lsp->lsp_header->rem_lifetime));
740 vty_out(vty, "%s\n", lsp_bits2string(&lsp->lsp_header->lsp_bits));
eb5d44eb 741}
742
d62a17ae 743static void lsp_print_mt_reach(struct list *list, struct vty *vty, char dynhost,
744 uint16_t mtid)
206f4aae 745{
d62a17ae 746 struct listnode *node;
747 struct te_is_neigh *neigh;
748
749 for (ALL_LIST_ELEMENTS_RO(list, node, neigh)) {
750 u_char lspid[255];
751
752 lspid_print(neigh->neigh_id, lspid, dynhost, 0);
753 if (mtid == ISIS_MT_IPV4_UNICAST) {
754 vty_out(vty,
755 " Metric : %-8u IS-Extended : %s\n",
756 GET_TE_METRIC(neigh), lspid);
757 } else {
758 vty_out(vty,
759 " Metric : %-8u MT-Reach : %s %s\n",
760 GET_TE_METRIC(neigh), lspid,
761 isis_mtid2str(mtid));
762 }
763 if (IS_MPLS_TE(isisMplsTE))
764 mpls_te_print_detail(vty, neigh);
765 }
206f4aae
CF
766}
767
d62a17ae 768static void lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty,
769 uint16_t mtid)
c3ae3127 770{
d62a17ae 771 struct listnode *node;
772 struct ipv6_reachability *ipv6_reach;
773 struct in6_addr in6;
774 u_char buff[BUFSIZ];
775
776 for (ALL_LIST_ELEMENTS_RO(list, node, ipv6_reach)) {
777 memset(&in6, 0, sizeof(in6));
778 memcpy(in6.s6_addr, ipv6_reach->prefix,
779 PSIZE(ipv6_reach->prefix_len));
780 inet_ntop(AF_INET6, &in6, (char *)buff, BUFSIZ);
781 if (mtid == ISIS_MT_IPV4_UNICAST) {
782 if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
783 == DISTRIBUTION_INTERNAL)
9d303b37
DL
784 vty_out(vty, " Metric : %-8" PRIu32
785 " IPv6-Internal : %s/%d\n",
d62a17ae 786 ntohl(ipv6_reach->metric), buff,
787 ipv6_reach->prefix_len);
788 else
9d303b37
DL
789 vty_out(vty, " Metric : %-8" PRIu32
790 " IPv6-External : %s/%d\n",
d62a17ae 791 ntohl(ipv6_reach->metric), buff,
792 ipv6_reach->prefix_len);
793 } else {
794 if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
795 == DISTRIBUTION_INTERNAL)
9d303b37
DL
796 vty_out(vty, " Metric : %-8" PRIu32
797 " IPv6-MT-Int : %s/%d %s\n",
d62a17ae 798 ntohl(ipv6_reach->metric), buff,
799 ipv6_reach->prefix_len,
800 isis_mtid2str(mtid));
801 else
9d303b37
DL
802 vty_out(vty, " Metric : %-8" PRIu32
803 " IPv6-MT-Ext : %s/%d %s\n",
d62a17ae 804 ntohl(ipv6_reach->metric), buff,
805 ipv6_reach->prefix_len,
806 isis_mtid2str(mtid));
807 }
808 }
c3ae3127
CF
809}
810
d62a17ae 811static void lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty,
812 uint16_t mtid)
c3ae3127 813{
d62a17ae 814 struct listnode *node;
815 struct te_ipv4_reachability *te_ipv4_reach;
816
817 for (ALL_LIST_ELEMENTS_RO(list, node, te_ipv4_reach)) {
818 if (mtid == ISIS_MT_IPV4_UNICAST) {
819 /* FIXME: There should be better way to output this
820 * stuff. */
9d303b37
DL
821 vty_out(vty, " Metric : %-8" PRIu32
822 " IPv4-Extended : %s/%d\n",
d62a17ae 823 ntohl(te_ipv4_reach->te_metric),
824 inet_ntoa(newprefix2inaddr(
825 &te_ipv4_reach->prefix_start,
826 te_ipv4_reach->control)),
827 te_ipv4_reach->control & 0x3F);
828 } else {
829 /* FIXME: There should be better way to output this
830 * stuff. */
9d303b37
DL
831 vty_out(vty, " Metric : %-8" PRIu32
832 " IPv4-MT : %s/%d %s\n",
d62a17ae 833 ntohl(te_ipv4_reach->te_metric),
834 inet_ntoa(newprefix2inaddr(
835 &te_ipv4_reach->prefix_start,
836 te_ipv4_reach->control)),
837 te_ipv4_reach->control & 0x3F,
838 isis_mtid2str(mtid));
839 }
840 }
c3ae3127
CF
841}
842
d62a17ae 843void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
eb5d44eb 844{
d62a17ae 845 struct area_addr *area_addr;
846 int i;
847 struct listnode *lnode;
848 struct is_neigh *is_neigh;
849 struct ipv4_reachability *ipv4_reach;
850 struct in_addr *ipv4_addr;
851 struct mt_router_info *mt_router_info;
852 struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
853 struct tlv_mt_neighbors *mt_is_neigh;
854 struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
855 u_char LSPid[255];
856 u_char hostname[255];
857 u_char ipv4_reach_prefix[20];
858 u_char ipv4_reach_mask[20];
859 u_char ipv4_address[20];
860
861 lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
862 lsp_print(lsp, vty, dynhost);
863
864 /* for all area address */
865 if (lsp->tlv_data.area_addrs)
866 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.area_addrs, lnode,
867 area_addr)) {
868 vty_out(vty, " Area Address: %s\n",
869 isonet_print(area_addr->area_addr,
870 area_addr->addr_len));
871 }
872
873 /* for the nlpid tlv */
874 if (lsp->tlv_data.nlpids) {
875 for (i = 0; i < lsp->tlv_data.nlpids->count; i++) {
876 switch (lsp->tlv_data.nlpids->nlpids[i]) {
877 case NLPID_IP:
878 case NLPID_IPV6:
879 vty_out(vty, " NLPID : 0x%X\n",
880 lsp->tlv_data.nlpids->nlpids[i]);
881 break;
882 default:
883 vty_out(vty, " NLPID : %s\n", "unknown");
884 break;
885 }
886 }
887 }
888
889 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode,
890 mt_router_info)) {
891 vty_out(vty, " MT : %s%s\n",
892 isis_mtid2str(mt_router_info->mtid),
893 mt_router_info->overload ? " (overload)" : "");
894 }
895
896 /* for the hostname tlv */
897 if (lsp->tlv_data.hostname) {
898 bzero(hostname, sizeof(hostname));
899 memcpy(hostname, lsp->tlv_data.hostname->name,
900 lsp->tlv_data.hostname->namelen);
901 vty_out(vty, " Hostname : %s\n", hostname);
902 }
903
904 /* authentication tlv */
905 if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) {
906 if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
907 vty_out(vty, " Auth type : md5\n");
908 else if (lsp->tlv_data.auth_info.type
909 == ISIS_PASSWD_TYPE_CLEARTXT)
910 vty_out(vty, " Auth type : clear text\n");
911 }
912
913 /* TE router id */
914 if (lsp->tlv_data.router_id) {
915 memcpy(ipv4_address, inet_ntoa(lsp->tlv_data.router_id->id),
916 sizeof(ipv4_address));
917 vty_out(vty, " Router ID : %s\n", ipv4_address);
918 }
919
920 if (lsp->tlv_data.ipv4_addrs)
921 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_addrs, lnode,
922 ipv4_addr)) {
923 memcpy(ipv4_address, inet_ntoa(*ipv4_addr),
924 sizeof(ipv4_address));
925 vty_out(vty, " IPv4 Address: %s\n", ipv4_address);
926 }
927
928 /* for the IS neighbor tlv */
929 if (lsp->tlv_data.is_neighs)
930 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, lnode,
931 is_neigh)) {
932 lspid_print(is_neigh->neigh_id, LSPid, dynhost, 0);
9d303b37
DL
933 vty_out(vty, " Metric : %-8" PRIu8
934 " IS : %s\n",
d62a17ae 935 is_neigh->metrics.metric_default, LSPid);
936 }
937
938 /* for the internal reachable tlv */
939 if (lsp->tlv_data.ipv4_int_reachs)
940 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_int_reachs, lnode,
941 ipv4_reach)) {
942 memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
943 sizeof(ipv4_reach_prefix));
944 memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
945 sizeof(ipv4_reach_mask));
9d303b37
DL
946 vty_out(vty, " Metric : %-8" PRIu8
947 " IPv4-Internal : %s %s\n",
d62a17ae 948 ipv4_reach->metrics.metric_default,
949 ipv4_reach_prefix, ipv4_reach_mask);
950 }
951
952 /* for the external reachable tlv */
953 if (lsp->tlv_data.ipv4_ext_reachs)
954 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_ext_reachs, lnode,
955 ipv4_reach)) {
956 memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
957 sizeof(ipv4_reach_prefix));
958 memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
959 sizeof(ipv4_reach_mask));
9d303b37
DL
960 vty_out(vty, " Metric : %-8" PRIu8
961 " IPv4-External : %s %s\n",
d62a17ae 962 ipv4_reach->metrics.metric_default,
963 ipv4_reach_prefix, ipv4_reach_mask);
964 }
965
966 /* IPv6 tlv */
967 lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
968 ISIS_MT_IPV4_UNICAST);
969
970 /* MT IPv6 reachability tlv */
971 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv6_reachs, lnode,
972 mt_ipv6_reachs))
973 lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty,
974 mt_ipv6_reachs->mtid);
975
976 /* TE IS neighbor tlv */
977 lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, dynhost,
978 ISIS_MT_IPV4_UNICAST);
979
980 /* MT IS neighbor tlv */
981 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_is_neighs, lnode,
982 mt_is_neigh))
983 lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost,
984 mt_is_neigh->mtid);
985
986 /* TE IPv4 tlv */
987 lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
988 ISIS_MT_IPV4_UNICAST);
989
990 /* MT IPv4 reachability tlv */
991 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv4_reachs, lnode,
992 mt_ipv4_reachs))
993 lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty,
994 mt_ipv4_reachs->mtid);
995
996 vty_out(vty, "\n");
997
998 return;
eb5d44eb 999}
1000
1001/* print all the lsps info in the local lspdb */
d62a17ae 1002int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost)
eb5d44eb 1003{
1004
d62a17ae 1005 dnode_t *node = dict_first(lspdb), *next;
1006 int lsp_count = 0;
1007
1008 if (detail == ISIS_UI_LEVEL_BRIEF) {
1009 while (node != NULL) {
1010 /* I think it is unnecessary, so I comment it out */
1011 /* dict_contains (lspdb, node); */
1012 next = dict_next(lspdb, node);
1013 lsp_print(dnode_get(node), vty, dynhost);
1014 node = next;
1015 lsp_count++;
1016 }
1017 } else if (detail == ISIS_UI_LEVEL_DETAIL) {
1018 while (node != NULL) {
1019 next = dict_next(lspdb, node);
1020 lsp_print_detail(dnode_get(node), vty, dynhost);
1021 node = next;
1022 lsp_count++;
1023 }
1024 }
1025
1026 return lsp_count;
eb5d44eb 1027}
1028
d62a17ae 1029static void _lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
1030 struct list **to, int frag_thold,
1031 unsigned int tlv_build_func(struct list *,
1032 struct stream *,
1033 void *arg),
1034 void *arg)
206f4aae 1035{
d62a17ae 1036 while (*from && listcount(*from)) {
1037 unsigned int count;
1038
1039 count = tlv_build_func(*from, lsp->pdu, arg);
1040
1041 if (listcount(*to) != 0 || count != listcount(*from)) {
1042 struct listnode *node, *nnode;
1043 void *elem;
1044
1045 for (ALL_LIST_ELEMENTS(*from, node, nnode, elem)) {
1046 if (!count)
1047 break;
1048 listnode_add(*to, elem);
1049 list_delete_node(*from, node);
1050 --count;
1051 }
1052 } else {
1053 list_free(*to);
1054 *to = *from;
1055 *from = NULL;
1056 }
1057 }
206f4aae
CF
1058}
1059
d62a17ae 1060#define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100)
eb5d44eb 1061
1062/* stream*, area->lsp_frag_threshold, increment */
d62a17ae 1063#define FRAG_NEEDED(S, T, I) \
1064 (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T))
eb5d44eb 1065
aa4376ec 1066/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1067 * variable length (TE TLVs, sub TLVs). */
d62a17ae 1068static void lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
1069 struct list **to, int tlvsize, int frag_thold,
1070 int tlv_build_func(struct list *, struct stream *))
eb5d44eb 1071{
d62a17ae 1072 int count, i;
1073
1074 /* can we fit all ? */
1075 if (!FRAG_NEEDED(lsp->pdu, frag_thold,
1076 listcount(*from) * tlvsize + 2)) {
1077 tlv_build_func(*from, lsp->pdu);
1078 if (listcount(*to) != 0) {
1079 struct listnode *node, *nextnode;
1080 void *elem;
1081
1082 for (ALL_LIST_ELEMENTS(*from, node, nextnode, elem)) {
1083 listnode_add(*to, elem);
1084 list_delete_node(*from, node);
1085 }
1086 } else {
1087 list_free(*to);
1088 *to = *from;
1089 *from = NULL;
1090 }
1091 } else if (!FRAG_NEEDED(lsp->pdu, frag_thold, tlvsize + 2)) {
1092 /* fit all we can */
1093 count = FRAG_THOLD(lsp->pdu, frag_thold) - 2
1094 - (STREAM_SIZE(lsp->pdu) - STREAM_REMAIN(lsp->pdu));
1095 count = count / tlvsize;
1096 if (count > (int)listcount(*from))
1097 count = listcount(*from);
1098 for (i = 0; i < count; i++) {
1099 listnode_add(*to, listgetdata(listhead(*from)));
1100 listnode_delete(*from, listgetdata(listhead(*from)));
1101 }
1102 tlv_build_func(*to, lsp->pdu);
1103 }
1104 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
1105 return;
eb5d44eb 1106}
1107
d62a17ae 1108static u_int16_t lsp_rem_lifetime(struct isis_area *area, int level)
3f045a08 1109{
d62a17ae 1110 u_int16_t rem_lifetime;
3f045a08 1111
d62a17ae 1112 /* Add jitter to configured LSP lifetime */
1113 rem_lifetime =
1114 isis_jitter(area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER);
3f045a08 1115
d62a17ae 1116 /* No jitter if the max refresh will be less than configure gen interval
1117 */
1118 /* N.B. this calucation is acceptable since rem_lifetime is in
1119 * [332,65535] at
1120 * this point */
1121 if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
1122 rem_lifetime = area->max_lsp_lifetime[level - 1];
3f045a08 1123
d62a17ae 1124 return rem_lifetime;
3f045a08
JB
1125}
1126
d62a17ae 1127static u_int16_t lsp_refresh_time(struct isis_lsp *lsp, u_int16_t rem_lifetime)
3f045a08 1128{
d62a17ae 1129 struct isis_area *area = lsp->area;
1130 int level = lsp->level;
1131 u_int16_t refresh_time;
3f045a08 1132
d62a17ae 1133 /* Add jitter to LSP refresh time */
1134 refresh_time =
1135 isis_jitter(area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER);
3f045a08 1136
d62a17ae 1137 /* RFC 4444 : make sure the refresh time is at least less than 300
1138 * of the remaining lifetime and more than gen interval */
1139 if (refresh_time <= area->lsp_gen_interval[level - 1]
1140 || refresh_time > (rem_lifetime - 300))
1141 refresh_time = rem_lifetime - 300;
3f045a08 1142
d62a17ae 1143 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1144 * we accept this violation to satisfy refresh_time <= rem_lifetime -
1145 * 300 */
3f045a08 1146
d62a17ae 1147 return refresh_time;
3f045a08
JB
1148}
1149
d62a17ae 1150static struct isis_lsp *lsp_next_frag(u_char frag_num, struct isis_lsp *lsp0,
1151 struct isis_area *area, int level)
eb5d44eb 1152{
d62a17ae 1153 struct isis_lsp *lsp;
1154 u_char frag_id[ISIS_SYS_ID_LEN + 2];
1155
1156 memcpy(frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1157 LSP_FRAGMENT(frag_id) = frag_num;
1158 /* FIXME add authentication TLV for fragment LSPs */
1159 lsp = lsp_search(frag_id, area->lspdb[level - 1]);
1160 if (lsp) {
1161 /* Clear the TLVs */
1162 lsp_clear_data(lsp);
1163 return lsp;
1164 }
1165 lsp = lsp_new(area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
1166 lsp_bits_generate(level, area->overload_bit,
1167 area->attached_bit),
1168 0, level);
1169 lsp->area = area;
1170 lsp->own_lsp = 1;
1171 lsp_insert(lsp, area->lspdb[level - 1]);
1172 listnode_add(lsp0->lspu.frags, lsp);
1173 lsp->lspu.zero_lsp = lsp0;
1174 return lsp;
eb5d44eb 1175}
1176
d62a17ae 1177static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
1178 struct isis_area *area,
1179 struct tlvs *tlv_data)
f3ccedaa 1180{
d62a17ae 1181 struct route_table *er_table;
1182 struct route_node *rn;
1183 struct prefix_ipv4 *ipv4;
1184 struct isis_ext_info *info;
1185 struct ipv4_reachability *ipreach;
1186 struct te_ipv4_reachability *te_ipreach;
1187
1188 er_table = get_ext_reach(area, AF_INET, lsp->level);
1189 if (!er_table)
1190 return;
1191
1192 for (rn = route_top(er_table); rn; rn = route_next(rn)) {
1193 if (!rn->info)
1194 continue;
1195
1196 ipv4 = (struct prefix_ipv4 *)&rn->p;
1197 info = rn->info;
1198 if (area->oldmetric) {
1199 if (tlv_data->ipv4_ext_reachs == NULL) {
1200 tlv_data->ipv4_ext_reachs = list_new();
1201 tlv_data->ipv4_ext_reachs->del = free_tlv;
1202 }
1203 ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
1204
1205 ipreach->prefix.s_addr = ipv4->prefix.s_addr;
1206 masklen2ip(ipv4->prefixlen, &ipreach->mask);
1207 ipreach->prefix.s_addr &= ipreach->mask.s_addr;
1208
1209 if ((info->metric & 0x3f) != info->metric)
1210 ipreach->metrics.metric_default = 0x3f;
1211 else
1212 ipreach->metrics.metric_default = info->metric;
1213 ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
1214 ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
1215 ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
1216 listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
1217 }
1218 if (area->newmetric) {
1219 if (tlv_data->te_ipv4_reachs == NULL) {
1220 tlv_data->te_ipv4_reachs = list_new();
1221 tlv_data->te_ipv4_reachs->del = free_tlv;
1222 }
1223 te_ipreach = XCALLOC(MTYPE_ISIS_TLV,
1224 sizeof(*te_ipreach) - 1
1225 + PSIZE(ipv4->prefixlen));
1226 if (info->metric > MAX_WIDE_PATH_METRIC)
1227 te_ipreach->te_metric =
1228 htonl(MAX_WIDE_PATH_METRIC);
1229 else
1230 te_ipreach->te_metric = htonl(info->metric);
1231 te_ipreach->control = ipv4->prefixlen & 0x3f;
1232 memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1233 PSIZE(ipv4->prefixlen));
1234 listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
1235 }
1236 }
f3ccedaa
CF
1237}
1238
d62a17ae 1239static struct list *tlv_get_ipv6_reach_list(struct isis_area *area,
1240 struct tlvs *tlv_data)
c3ae3127 1241{
d62a17ae 1242 uint16_t mtid = isis_area_ipv6_topology(area);
1243 if (mtid == ISIS_MT_IPV4_UNICAST) {
1244 if (!tlv_data->ipv6_reachs) {
1245 tlv_data->ipv6_reachs = list_new();
1246 tlv_data->ipv6_reachs->del = free_tlv;
1247 }
1248 return tlv_data->ipv6_reachs;
1249 }
1250
1251 struct tlv_mt_ipv6_reachs *reachs =
1252 tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
1253 return reachs->list;
c3ae3127
CF
1254}
1255
d62a17ae 1256static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
1257 struct isis_area *area,
1258 struct tlvs *tlv_data)
f3ccedaa 1259{
d62a17ae 1260 struct route_table *er_table;
1261 struct route_node *rn;
1262 struct prefix_ipv6 *ipv6;
1263 struct isis_ext_info *info;
1264 struct ipv6_reachability *ip6reach;
1265 struct list *reach_list = NULL;
1266
1267 er_table = get_ext_reach(area, AF_INET6, lsp->level);
1268 if (!er_table)
1269 return;
1270
1271 for (rn = route_top(er_table); rn; rn = route_next(rn)) {
1272 if (!rn->info)
1273 continue;
1274
1275 ipv6 = (struct prefix_ipv6 *)&rn->p;
1276 info = rn->info;
1277
1278 if (!reach_list)
1279 reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
1280
1281 ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
1282 if (info->metric > MAX_WIDE_PATH_METRIC)
1283 ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
1284 else
1285 ip6reach->metric = htonl(info->metric);
1286 ip6reach->control_info = DISTRIBUTION_EXTERNAL;
1287 ip6reach->prefix_len = ipv6->prefixlen;
1288 memcpy(ip6reach->prefix, ipv6->prefix.s6_addr,
1289 sizeof(ip6reach->prefix));
1290 listnode_add(reach_list, ip6reach);
1291 }
f3ccedaa
CF
1292}
1293
d62a17ae 1294static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area,
1295 struct tlvs *tlv_data)
f3ccedaa 1296{
d62a17ae 1297 lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
1298 lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
f3ccedaa
CF
1299}
1300
eb5d44eb 1301/*
d62a17ae 1302 * Builds the LSP data part. This func creates a new frag whenever
eb5d44eb 1303 * area->lsp_frag_threshold is exceeded.
1304 */
d62a17ae 1305static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
eb5d44eb 1306{
d62a17ae 1307 struct is_neigh *is_neigh;
1308 struct te_is_neigh *te_is_neigh;
1309 struct listnode *node, *ipnode;
1310 int level = lsp->level;
1311 struct isis_circuit *circuit;
1312 struct prefix_ipv4 *ipv4;
1313 struct ipv4_reachability *ipreach;
1314 struct te_ipv4_reachability *te_ipreach;
1315 struct isis_adjacency *nei;
1316 struct prefix_ipv6 *ipv6, ip6prefix;
1317 struct list *ipv6_reachs = NULL;
1318 struct ipv6_reachability *ip6reach;
1319 struct tlvs tlv_data;
1320 struct isis_lsp *lsp0 = lsp;
1321 struct in_addr *routerid;
1322 uint32_t expected = 0, found = 0;
1323 uint32_t metric;
1324 u_char zero_id[ISIS_SYS_ID_LEN + 1];
1325 int retval = ISIS_OK;
1326 char buf[BUFSIZ];
1327
1328 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1329 area->area_tag, level);
1330
1331 /*
1332 * Building the zero lsp
1333 */
1334 memset(zero_id, 0, ISIS_SYS_ID_LEN + 1);
1335
1336 /* Reset stream endp. Stream is always there and on every LSP refresh
1337 * only
1338 * TLV part of it is overwritten. So we must seek past header we will
1339 * not
1340 * touch. */
1341 stream_reset(lsp->pdu);
1342 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1343
1344 /*
1345 * Add the authentication info if its present
1346 */
1347 lsp_auth_add(lsp);
1348
1349 /*
1350 * First add the tlvs related to area
1351 */
1352
1353 /* Area addresses */
1354 if (lsp->tlv_data.area_addrs == NULL)
1355 lsp->tlv_data.area_addrs = list_new();
1356 list_add_list(lsp->tlv_data.area_addrs, area->area_addrs);
1357 if (listcount(lsp->tlv_data.area_addrs) > 0)
1358 tlv_add_area_addrs(lsp->tlv_data.area_addrs, lsp->pdu);
1359
1360 /* Protocols Supported */
1361 if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
1362 lsp->tlv_data.nlpids =
1363 XCALLOC(MTYPE_ISIS_TLV, sizeof(struct nlpids));
1364 lsp->tlv_data.nlpids->count = 0;
1365 if (area->ip_circuits > 0) {
1366 lsp_debug(
1367 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1368 area->area_tag);
1369 lsp->tlv_data.nlpids->count++;
1370 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1371 }
1372 if (area->ipv6_circuits > 0) {
1373 lsp_debug(
1374 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1375 area->area_tag);
1376 lsp->tlv_data.nlpids->count++;
1377 lsp->tlv_data.nlpids
1378 ->nlpids[lsp->tlv_data.nlpids->count - 1] =
1379 NLPID_IPV6;
1380 }
1381 tlv_add_nlpid(lsp->tlv_data.nlpids, lsp->pdu);
1382 }
1383
1384 if (area_is_mt(area)) {
1385 lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
1386 lsp->tlv_data.mt_router_info = list_new();
1387 lsp->tlv_data.mt_router_info->del = free_tlv;
1388
1389 struct isis_area_mt_setting **mt_settings;
1390 unsigned int mt_count;
1391
1392 mt_settings = area_mt_settings(area, &mt_count);
1393 for (unsigned int i = 0; i < mt_count; i++) {
1394 struct mt_router_info *info;
1395
1396 info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
1397 info->mtid = mt_settings[i]->mtid;
1398 info->overload = mt_settings[i]->overload;
1399 listnode_add(lsp->tlv_data.mt_router_info, info);
1400 lsp_debug("ISIS (%s): MT %s", area->area_tag,
1401 isis_mtid2str(info->mtid));
aa4376ec 1402 }
d62a17ae 1403 tlv_add_mt_router_info(lsp->tlv_data.mt_router_info, lsp->pdu);
1404 } else {
1405 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
1406 area->area_tag);
1407 }
1408 /* Dynamic Hostname */
1409 if (area->dynhostname) {
1410 const char *hostname = unix_hostname();
1411 size_t hostname_len = strlen(hostname);
1412
1413 lsp->tlv_data.hostname =
1414 XMALLOC(MTYPE_ISIS_TLV, sizeof(struct hostname));
1415
1416 strncpy((char *)lsp->tlv_data.hostname->name, hostname,
1417 sizeof(lsp->tlv_data.hostname->name));
1418 if (hostname_len <= MAX_TLV_LEN)
1419 lsp->tlv_data.hostname->namelen = hostname_len;
1420 else
1421 lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
1422
1423 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'",
1424 area->area_tag, lsp->tlv_data.hostname->namelen,
1425 lsp->tlv_data.hostname->name);
1426 tlv_add_dynamic_hostname(lsp->tlv_data.hostname, lsp->pdu);
1427 } else {
1428 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1429 area->area_tag);
1430 }
1431
1432 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1433 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
1434 * into
1435 * LSP and this address is same as router id. */
1436 if (isis->router_id != 0) {
1437 inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
1438 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
1439 area->area_tag, buf);
1440 if (lsp->tlv_data.ipv4_addrs == NULL) {
1441 lsp->tlv_data.ipv4_addrs = list_new();
1442 lsp->tlv_data.ipv4_addrs->del = free_tlv;
aa4376ec 1443 }
d62a17ae 1444
1445 routerid = XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
1446 routerid->s_addr = isis->router_id;
1447 listnode_add(lsp->tlv_data.ipv4_addrs, routerid);
1448 tlv_add_in_addr(routerid, lsp->pdu, IPV4_ADDR);
1449
1450 /* Exactly same data is put into TE router ID TLV, but only if
1451 * new style
1452 * TLV's are in use. */
1453 if (area->newmetric) {
1454 lsp_debug(
1455 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1456 area->area_tag);
1457 lsp->tlv_data.router_id =
1458 XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
1459 lsp->tlv_data.router_id->id.s_addr = isis->router_id;
1460 tlv_add_in_addr(&lsp->tlv_data.router_id->id, lsp->pdu,
1461 TE_ROUTER_ID);
aa4376ec 1462 }
d62a17ae 1463 } else {
1464 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1465 area->area_tag);
1466 }
1467
1468 memset(&tlv_data, 0, sizeof(struct tlvs));
1469
1470 lsp_debug("ISIS (%s): Adding circuit specific information.",
1471 area->area_tag);
1472
1473 /*
1474 * Then build lists of tlvs related to circuits
1475 */
1476 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
1477 if (!circuit->interface)
1478 lsp_debug(
1479 "ISIS (%s): Processing %s circuit %p with unknown interface",
1480 area->area_tag,
1481 circuit_type2string(circuit->circ_type),
1482 circuit);
1483 else
1484 lsp_debug("ISIS (%s): Processing %s circuit %s",
1485 area->area_tag,
1486 circuit_type2string(circuit->circ_type),
1487 circuit->interface->name);
1488
1489 if (circuit->state != C_STATE_UP) {
1490 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1491 area->area_tag);
1492 continue;
aa4376ec 1493 }
d62a17ae 1494
1495 /*
1496 * Add IPv4 internal reachability of this circuit
1497 */
1498 if (circuit->ip_router && circuit->ip_addrs
1499 && circuit->ip_addrs->count > 0) {
1500 lsp_debug(
1501 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1502 area->area_tag);
1503 if (area->oldmetric) {
1504 if (tlv_data.ipv4_int_reachs == NULL) {
1505 tlv_data.ipv4_int_reachs = list_new();
1506 tlv_data.ipv4_int_reachs->del =
1507 free_tlv;
1508 }
1509 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
1510 ipnode, ipv4)) {
1511 ipreach = XMALLOC(
1512 MTYPE_ISIS_TLV,
1513 sizeof(struct
1514 ipv4_reachability));
1515 ipreach->metrics.metric_default =
1516 circuit->metric[level - 1];
1517 ipreach->metrics.metric_expense =
1518 METRICS_UNSUPPORTED;
1519 ipreach->metrics.metric_error =
1520 METRICS_UNSUPPORTED;
1521 ipreach->metrics.metric_delay =
1522 METRICS_UNSUPPORTED;
1523 masklen2ip(ipv4->prefixlen,
1524 &ipreach->mask);
1525 ipreach->prefix.s_addr =
1526 ((ipreach->mask.s_addr)
1527 & (ipv4->prefix.s_addr));
1528 inet_ntop(AF_INET,
1529 &ipreach->prefix.s_addr, buf,
1530 sizeof(buf));
1531 lsp_debug(
1532 "ISIS (%s): Adding old-style IP reachability for %s/%d",
1533 area->area_tag, buf,
1534 ipv4->prefixlen);
1535 listnode_add(tlv_data.ipv4_int_reachs,
1536 ipreach);
1537 }
1538 }
1539 if (area->newmetric) {
1540 if (tlv_data.te_ipv4_reachs == NULL) {
1541 tlv_data.te_ipv4_reachs = list_new();
1542 tlv_data.te_ipv4_reachs->del = free_tlv;
1543 }
1544 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
1545 ipnode, ipv4)) {
1546 /* FIXME All this assumes that we have
1547 * no sub TLVs. */
1548 te_ipreach = XCALLOC(
1549 MTYPE_ISIS_TLV,
1550 sizeof(struct
1551 te_ipv4_reachability)
1552 + ((ipv4->prefixlen + 7)
1553 / 8)
1554 - 1);
1555
1556 if (area->oldmetric)
1557 te_ipreach->te_metric = htonl(
1558 circuit->metric[level
1559 - 1]);
1560 else
1561 te_ipreach->te_metric = htonl(
1562 circuit->te_metric
1563 [level - 1]);
1564
1565 te_ipreach->control =
1566 (ipv4->prefixlen & 0x3F);
1567 memcpy(&te_ipreach->prefix_start,
1568 &ipv4->prefix.s_addr,
1569 (ipv4->prefixlen + 7) / 8);
1570 inet_ntop(AF_INET, &ipv4->prefix.s_addr,
1571 buf, sizeof(buf));
1572 lsp_debug(
1573 "ISIS (%s): Adding te-style IP reachability for %s/%d",
1574 area->area_tag, buf,
1575 ipv4->prefixlen);
1576 listnode_add(tlv_data.te_ipv4_reachs,
1577 te_ipreach);
1578 }
1579 }
f390d2c7 1580 }
d62a17ae 1581
1582 /*
1583 * Add IPv6 reachability of this circuit
1584 */
1585 if (circuit->ipv6_router && circuit->ipv6_non_link
1586 && circuit->ipv6_non_link->count > 0) {
1587 if (!ipv6_reachs)
1588 ipv6_reachs = tlv_get_ipv6_reach_list(
1589 area, &tlv_data);
1590
1591 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1592 ipnode, ipv6)) {
1593 ip6reach = XCALLOC(
1594 MTYPE_ISIS_TLV,
1595 sizeof(struct ipv6_reachability));
1596
1597 if (area->oldmetric)
1598 ip6reach->metric = htonl(
1599 circuit->metric[level - 1]);
1600 else
1601 ip6reach->metric = htonl(
1602 circuit->te_metric[level - 1]);
1603
1604 ip6reach->control_info = 0;
1605 ip6reach->prefix_len = ipv6->prefixlen;
1606 memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
1607 apply_mask_ipv6(&ip6prefix);
1608
1609 inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr,
1610 buf, sizeof(buf));
1611 lsp_debug(
1612 "ISIS (%s): Adding IPv6 reachability for %s/%d",
1613 area->area_tag, buf, ipv6->prefixlen);
1614
1615 memcpy(ip6reach->prefix,
1616 ip6prefix.prefix.s6_addr,
1617 sizeof(ip6reach->prefix));
1618 listnode_add(ipv6_reachs, ip6reach);
1619 }
aa4376ec 1620 }
d62a17ae 1621
1622 switch (circuit->circ_type) {
1623 case CIRCUIT_T_BROADCAST:
1624 if (level & circuit->is_type) {
1625 if (area->oldmetric) {
1626 if (tlv_data.is_neighs == NULL) {
1627 tlv_data.is_neighs = list_new();
1628 tlv_data.is_neighs->del =
1629 free_tlv;
1630 }
1631 is_neigh = XCALLOC(
1632 MTYPE_ISIS_TLV,
1633 sizeof(struct is_neigh));
1634 if (level == IS_LEVEL_1)
1635 memcpy(is_neigh->neigh_id,
1636 circuit->u.bc
1637 .l1_desig_is,
1638 ISIS_SYS_ID_LEN + 1);
1639 else
1640 memcpy(is_neigh->neigh_id,
1641 circuit->u.bc
1642 .l2_desig_is,
1643 ISIS_SYS_ID_LEN + 1);
1644 is_neigh->metrics.metric_default =
1645 circuit->metric[level - 1];
1646 is_neigh->metrics.metric_expense =
1647 METRICS_UNSUPPORTED;
1648 is_neigh->metrics.metric_error =
1649 METRICS_UNSUPPORTED;
1650 is_neigh->metrics.metric_delay =
1651 METRICS_UNSUPPORTED;
1652 if (!memcmp(is_neigh->neigh_id, zero_id,
1653 ISIS_SYS_ID_LEN + 1)) {
1654 XFREE(MTYPE_ISIS_TLV, is_neigh);
1655 lsp_debug(
1656 "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1657 area->area_tag);
1658 } else {
1659 listnode_add(tlv_data.is_neighs,
1660 is_neigh);
1661 lsp_debug(
1662 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1663 area->area_tag,
1664 sysid_print(
1665 is_neigh->neigh_id),
1666 LSP_PSEUDO_ID(
1667 is_neigh->neigh_id));
1668 }
1669 }
1670 if (area->newmetric) {
1671 if (tlv_data.te_is_neighs == NULL) {
1672 tlv_data.te_is_neighs =
1673 list_new();
1674 tlv_data.te_is_neighs->del =
1675 free_tlv;
1676 }
1677 te_is_neigh = XCALLOC(
1678 MTYPE_ISIS_TLV,
1679 sizeof(struct te_is_neigh));
1680 if (level == IS_LEVEL_1)
1681 memcpy(te_is_neigh->neigh_id,
1682 circuit->u.bc
1683 .l1_desig_is,
1684 ISIS_SYS_ID_LEN + 1);
1685 else
1686 memcpy(te_is_neigh->neigh_id,
1687 circuit->u.bc
1688 .l2_desig_is,
1689 ISIS_SYS_ID_LEN + 1);
1690 if (area->oldmetric)
1691 metric = circuit->metric[level
1692 - 1];
1693 else
1694 metric =
1695 circuit->te_metric[level
1696 - 1];
1697 SET_TE_METRIC(te_is_neigh, metric);
1698 if (!memcmp(te_is_neigh->neigh_id,
1699 zero_id,
1700 ISIS_SYS_ID_LEN + 1)) {
1701 XFREE(MTYPE_ISIS_TLV,
1702 te_is_neigh);
1703 lsp_debug(
1704 "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1705 area->area_tag);
1706 } else {
1707 /* Check if MPLS_TE is activate
1708 */
1709 if (IS_MPLS_TE(isisMplsTE)
1710 && HAS_LINK_PARAMS(
1711 circuit->interface))
1712 /* Add SubTLVs & Adjust
1713 * real size of SubTLVs
1714 */
1715 te_is_neigh
1716 ->sub_tlvs_length = add_te_subtlvs(
1717 te_is_neigh
1718 ->sub_tlvs,
1719 circuit->mtc);
1720 else
1721 /* Or keep only TE
1722 * metric with no
1723 * SubTLVs if MPLS_TE is
1724 * off */
1725 te_is_neigh
1726 ->sub_tlvs_length =
1727 0;
1728
1729 tlvs_add_mt_bcast(
1730 &tlv_data, circuit,
1731 level, te_is_neigh);
1732 XFREE(MTYPE_ISIS_TLV,
1733 te_is_neigh);
1734 }
1735 }
1736 } else {
1737 lsp_debug(
1738 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1739 area->area_tag);
1740 }
1741 break;
1742 case CIRCUIT_T_P2P:
1743 nei = circuit->u.p2p.neighbor;
1744 if (nei && (level & nei->circuit_t)) {
1745 if (area->oldmetric) {
1746 if (tlv_data.is_neighs == NULL) {
1747 tlv_data.is_neighs = list_new();
1748 tlv_data.is_neighs->del =
1749 free_tlv;
1750 }
1751 is_neigh = XCALLOC(
1752 MTYPE_ISIS_TLV,
1753 sizeof(struct is_neigh));
1754 memcpy(is_neigh->neigh_id, nei->sysid,
1755 ISIS_SYS_ID_LEN);
1756 is_neigh->metrics.metric_default =
1757 circuit->metric[level - 1];
1758 is_neigh->metrics.metric_expense =
1759 METRICS_UNSUPPORTED;
1760 is_neigh->metrics.metric_error =
1761 METRICS_UNSUPPORTED;
1762 is_neigh->metrics.metric_delay =
1763 METRICS_UNSUPPORTED;
1764 listnode_add(tlv_data.is_neighs,
1765 is_neigh);
1766 lsp_debug(
1767 "ISIS (%s): Adding old-style is reach for %s",
1768 area->area_tag,
1769 sysid_print(
1770 is_neigh->neigh_id));
1771 }
1772 if (area->newmetric) {
1773 uint32_t metric;
1774
1775 if (tlv_data.te_is_neighs == NULL) {
1776 tlv_data.te_is_neighs =
1777 list_new();
1778 tlv_data.te_is_neighs->del =
1779 free_tlv;
1780 }
1781 te_is_neigh = XCALLOC(
1782 MTYPE_ISIS_TLV,
1783 sizeof(struct te_is_neigh));
1784 memcpy(te_is_neigh->neigh_id,
1785 nei->sysid, ISIS_SYS_ID_LEN);
1786 metric = circuit->te_metric[level - 1];
1787 SET_TE_METRIC(te_is_neigh, metric);
1788 /* Check if MPLS_TE is activate */
1789 if (IS_MPLS_TE(isisMplsTE)
1790 && HAS_LINK_PARAMS(
1791 circuit->interface))
1792 /* Update Local and Remote IP
1793 * address for MPLS TE circuit
1794 * parameters */
1795 /* NOTE sure that it is the
1796 * pertinent place for that
1797 * updates */
1798 /* Local IP address could be
1799 * updated in isis_circuit.c -
1800 * isis_circuit_add_addr() */
1801 /* But, where update remote IP
1802 * address ? in isis_pdu.c -
1803 * process_p2p_hello() ? */
1804
1805 /* Add SubTLVs & Adjust real
1806 * size of SubTLVs */
1807 te_is_neigh->sub_tlvs_length =
1808 add_te_subtlvs(
1809 te_is_neigh
1810 ->sub_tlvs,
1811 circuit->mtc);
1812 else
1813 /* Or keep only TE metric with
1814 * no SubTLVs if MPLS_TE is off
1815 */
1816 te_is_neigh->sub_tlvs_length =
1817 0;
1818
1819 tlvs_add_mt_p2p(&tlv_data, circuit,
1820 te_is_neigh);
1821 XFREE(MTYPE_ISIS_TLV, te_is_neigh);
1822 }
1823 } else {
1824 lsp_debug(
1825 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1826 area->area_tag);
1827 }
1828 break;
1829 case CIRCUIT_T_LOOPBACK:
1830 break;
1831 default:
1832 zlog_warn("lsp_area_create: unknown circuit type");
aa4376ec 1833 }
d62a17ae 1834 }
1835
1836 lsp_build_ext_reach(lsp, area, &tlv_data);
1837
1838 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1839 area->area_tag);
1840
1841 while (tlv_data.ipv4_int_reachs
1842 && listcount(tlv_data.ipv4_int_reachs)) {
1843 if (lsp->tlv_data.ipv4_int_reachs == NULL)
1844 lsp->tlv_data.ipv4_int_reachs = list_new();
1845 lsp_tlv_fit(lsp, &tlv_data.ipv4_int_reachs,
1846 &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN,
1847 area->lsp_frag_threshold, tlv_add_ipv4_int_reachs);
1848 if (tlv_data.ipv4_int_reachs
1849 && listcount(tlv_data.ipv4_int_reachs))
1850 lsp = lsp_next_frag(
1851 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1852 area, level);
1853 }
1854
1855 while (tlv_data.ipv4_ext_reachs
1856 && listcount(tlv_data.ipv4_ext_reachs)) {
1857 if (lsp->tlv_data.ipv4_ext_reachs == NULL)
1858 lsp->tlv_data.ipv4_ext_reachs = list_new();
1859 lsp_tlv_fit(lsp, &tlv_data.ipv4_ext_reachs,
1860 &lsp->tlv_data.ipv4_ext_reachs, IPV4_REACH_LEN,
1861 area->lsp_frag_threshold, tlv_add_ipv4_ext_reachs);
1862 if (tlv_data.ipv4_ext_reachs
1863 && listcount(tlv_data.ipv4_ext_reachs))
1864 lsp = lsp_next_frag(
1865 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1866 area, level);
1867 }
1868
1869 while (tlv_data.te_ipv4_reachs && listcount(tlv_data.te_ipv4_reachs)) {
1870 if (lsp->tlv_data.te_ipv4_reachs == NULL)
1871 lsp->tlv_data.te_ipv4_reachs = list_new();
1872 _lsp_tlv_fit(lsp, &tlv_data.te_ipv4_reachs,
1873 &lsp->tlv_data.te_ipv4_reachs,
1874 area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
1875 NULL);
1876 if (tlv_data.te_ipv4_reachs
1877 && listcount(tlv_data.te_ipv4_reachs))
1878 lsp = lsp_next_frag(
1879 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1880 area, level);
1881 }
1882
1883 struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
1884 for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node,
1885 mt_ipv4_reachs)) {
1886 while (mt_ipv4_reachs->list
1887 && listcount(mt_ipv4_reachs->list)) {
1888 struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
1889
1890 frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(
1891 &lsp->tlv_data, mt_ipv4_reachs->mtid);
1892 _lsp_tlv_fit(lsp, &mt_ipv4_reachs->list,
1893 &frag_mt_ipv4_reachs->list,
1894 area->lsp_frag_threshold,
1895 tlv_add_te_ipv4_reachs,
1896 &mt_ipv4_reachs->mtid);
1897 if (mt_ipv4_reachs->list
1898 && listcount(mt_ipv4_reachs->list))
1899 lsp = lsp_next_frag(
1900 LSP_FRAGMENT(lsp->lsp_header->lsp_id)
1901 + 1,
1902 lsp0, area, level);
f390d2c7 1903 }
d62a17ae 1904 }
1905
1906 while (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) {
1907 if (lsp->tlv_data.ipv6_reachs == NULL)
1908 lsp->tlv_data.ipv6_reachs = list_new();
1909 _lsp_tlv_fit(
1910 lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
1911 area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
1912 if (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs))
1913 lsp = lsp_next_frag(
1914 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1915 area, level);
1916 }
1917
1918 struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
1919 for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node,
1920 mt_ipv6_reachs)) {
1921 while (mt_ipv6_reachs->list
1922 && listcount(mt_ipv6_reachs->list)) {
1923 struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
1924
1925 frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(
1926 &lsp->tlv_data, mt_ipv6_reachs->mtid);
1927 _lsp_tlv_fit(lsp, &mt_ipv6_reachs->list,
1928 &frag_mt_ipv6_reachs->list,
1929 area->lsp_frag_threshold,
1930 tlv_add_ipv6_reachs,
1931 &mt_ipv6_reachs->mtid);
1932 if (mt_ipv6_reachs->list
1933 && listcount(mt_ipv6_reachs->list))
1934 lsp = lsp_next_frag(
1935 LSP_FRAGMENT(lsp->lsp_header->lsp_id)
1936 + 1,
1937 lsp0, area, level);
1938 }
1939 }
1940
1941 while (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) {
1942 if (lsp->tlv_data.is_neighs == NULL)
1943 lsp->tlv_data.is_neighs = list_new();
1944 lsp_tlv_fit(lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
1945 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1946 tlv_add_is_neighs);
1947 if (tlv_data.is_neighs && listcount(tlv_data.is_neighs))
1948 lsp = lsp_next_frag(
1949 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1950 area, level);
1951 }
1952
1953 while (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs)) {
1954 if (lsp->tlv_data.te_is_neighs == NULL)
1955 lsp->tlv_data.te_is_neighs = list_new();
1956 _lsp_tlv_fit(lsp, &tlv_data.te_is_neighs,
1957 &lsp->tlv_data.te_is_neighs,
1958 area->lsp_frag_threshold, tlv_add_te_is_neighs,
1959 NULL);
1960 if (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs))
1961 lsp = lsp_next_frag(
1962 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1963 area, level);
1964 }
1965
1966 struct tlv_mt_neighbors *mt_neighs;
1967 for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs)) {
1968 while (mt_neighs->list && listcount(mt_neighs->list)) {
1969 struct tlv_mt_neighbors *frag_mt_neighs;
1970
1971 frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data,
1972 mt_neighs->mtid);
1973 _lsp_tlv_fit(lsp, &mt_neighs->list,
1974 &frag_mt_neighs->list,
1975 area->lsp_frag_threshold,
1976 tlv_add_te_is_neighs, &mt_neighs->mtid);
1977 if (mt_neighs->list && listcount(mt_neighs->list))
1978 lsp = lsp_next_frag(
1979 LSP_FRAGMENT(lsp->lsp_header->lsp_id)
1980 + 1,
1981 lsp0, area, level);
1982 }
1983 }
1984
1985
1986 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
1987
1988 free_tlvs(&tlv_data);
1989
1990 /* Validate the LSP */
1991 retval = parse_tlvs(area->area_tag,
1992 STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
1993 + ISIS_LSP_HDR_LEN,
1994 stream_get_endp(lsp->pdu) - ISIS_FIXED_HDR_LEN
1995 - ISIS_LSP_HDR_LEN,
1996 &expected, &found, &tlv_data, NULL);
1997 assert(retval == ISIS_OK);
1998
1999 return;
eb5d44eb 2000}
eb5d44eb 2001
2002/*
3f045a08 2003 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
eb5d44eb 2004 */
d62a17ae 2005int lsp_generate(struct isis_area *area, int level)
f390d2c7 2006{
d62a17ae 2007 struct isis_lsp *oldlsp, *newlsp;
2008 u_int32_t seq_num = 0;
2009 u_char lspid[ISIS_SYS_ID_LEN + 2];
2010 u_int16_t rem_lifetime, refresh_time;
2011
2012 if ((area == NULL) || (area->is_type & level) != level)
2013 return ISIS_ERROR;
2014
2015 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
2016 memcpy(&lspid, isis->sysid, ISIS_SYS_ID_LEN);
2017
2018 /* only builds the lsp if the area shares the level */
2019 oldlsp = lsp_search(lspid, area->lspdb[level - 1]);
2020 if (oldlsp) {
2021 /* FIXME: we should actually initiate a purge */
2022 seq_num = ntohl(oldlsp->lsp_header->seq_num);
2023 lsp_search_and_destroy(oldlsp->lsp_header->lsp_id,
2024 area->lspdb[level - 1]);
2025 }
2026 rem_lifetime = lsp_rem_lifetime(area, level);
2027 newlsp =
2028 lsp_new(area, lspid, rem_lifetime, seq_num,
2029 area->is_type | area->overload_bit | area->attached_bit,
2030 0, level);
2031 newlsp->area = area;
2032 newlsp->own_lsp = 1;
2033
2034 lsp_insert(newlsp, area->lspdb[level - 1]);
2035 /* build_lsp_data (newlsp, area); */
2036 lsp_build(newlsp, area);
2037 /* time to calculate our checksum */
2038 lsp_seqnum_update(newlsp);
2039 newlsp->last_generated = time(NULL);
2040 lsp_set_all_srmflags(newlsp);
2041
2042 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
2043
2044 THREAD_TIMER_OFF(area->t_lsp_refresh[level - 1]);
2045 area->lsp_regenerate_pending[level - 1] = 0;
2046 if (level == IS_LEVEL_1)
2047 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
2048 &area->t_lsp_refresh[level - 1]);
2049 else if (level == IS_LEVEL_2)
2050 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
2051 &area->t_lsp_refresh[level - 1]);
2052
2053 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2054 zlog_debug(
2055 "ISIS-Upd (%s): Building L%d LSP %s, len %d, "
2056 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2057 area->area_tag, level,
2058 rawlspid_print(newlsp->lsp_header->lsp_id),
2059 ntohl(newlsp->lsp_header->pdu_len),
2060 ntohl(newlsp->lsp_header->seq_num),
2061 ntohs(newlsp->lsp_header->checksum),
2062 ntohs(newlsp->lsp_header->rem_lifetime), refresh_time);
2063 }
2064 sched_debug(
2065 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2066 area->area_tag, level);
2067
2068 return ISIS_OK;
eb5d44eb 2069}
2070
2071/*
3f045a08 2072 * Search own LSPs, update holding time and set SRM
eb5d44eb 2073 */
d62a17ae 2074static int lsp_regenerate(struct isis_area *area, int level)
eb5d44eb 2075{
d62a17ae 2076 dict_t *lspdb;
2077 struct isis_lsp *lsp, *frag;
2078 struct listnode *node;
2079 u_char lspid[ISIS_SYS_ID_LEN + 2];
2080 u_int16_t rem_lifetime, refresh_time;
2081
2082 if ((area == NULL) || (area->is_type & level) != level)
2083 return ISIS_ERROR;
2084
2085 lspdb = area->lspdb[level - 1];
2086
2087 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
2088 memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
2089
2090 lsp = lsp_search(lspid, lspdb);
2091
2092 if (!lsp) {
2093 zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2094 area->area_tag, level);
2095 return ISIS_ERROR;
2096 }
2097
2098 lsp_clear_data(lsp);
2099 lsp_build(lsp, area);
2100 lsp->lsp_header->lsp_bits = lsp_bits_generate(level, area->overload_bit,
2101 area->attached_bit);
2102 rem_lifetime = lsp_rem_lifetime(area, level);
2103 lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
2104 lsp_seqnum_update(lsp);
2105
2106 lsp->last_generated = time(NULL);
2107 lsp_set_all_srmflags(lsp);
2108 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2109 frag->lsp_header->lsp_bits = lsp_bits_generate(
2110 level, area->overload_bit, area->attached_bit);
2111 /* Set the lifetime values of all the fragments to the same
2112 * value,
2113 * so that no fragment expires before the lsp is refreshed.
2114 */
2115 frag->lsp_header->rem_lifetime = htons(rem_lifetime);
2116 lsp_set_all_srmflags(frag);
2117 }
2118
2119 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
2120 if (level == IS_LEVEL_1)
2121 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
2122 &area->t_lsp_refresh[level - 1]);
2123 else if (level == IS_LEVEL_2)
2124 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
2125 &area->t_lsp_refresh[level - 1]);
2126 area->lsp_regenerate_pending[level - 1] = 0;
2127
2128 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2129 zlog_debug(
2130 "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
2131 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2132 area->area_tag, level,
2133 rawlspid_print(lsp->lsp_header->lsp_id),
2134 ntohl(lsp->lsp_header->pdu_len),
2135 ntohl(lsp->lsp_header->seq_num),
2136 ntohs(lsp->lsp_header->checksum),
2137 ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
2138 }
2139 sched_debug(
2140 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2141 area->area_tag, level);
2142
2143 return ISIS_OK;
eb5d44eb 2144}
2145
eb5d44eb 2146/*
3f045a08 2147 * Something has changed or periodic refresh -> regenerate LSP
eb5d44eb 2148 */
d62a17ae 2149static int lsp_l1_refresh(struct thread *thread)
eb5d44eb 2150{
d62a17ae 2151 struct isis_area *area;
eb5d44eb 2152
d62a17ae 2153 area = THREAD_ARG(thread);
2154 assert(area);
f390d2c7 2155
d62a17ae 2156 area->t_lsp_refresh[0] = NULL;
2157 area->lsp_regenerate_pending[0] = 0;
eb5d44eb 2158
d62a17ae 2159 if ((area->is_type & IS_LEVEL_1) == 0)
2160 return ISIS_ERROR;
d70f99e1 2161
d62a17ae 2162 sched_debug(
2163 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
2164 area->area_tag);
2165 return lsp_regenerate(area, IS_LEVEL_1);
eb5d44eb 2166}
2167
d62a17ae 2168static int lsp_l2_refresh(struct thread *thread)
eb5d44eb 2169{
d62a17ae 2170 struct isis_area *area;
eb5d44eb 2171
d62a17ae 2172 area = THREAD_ARG(thread);
2173 assert(area);
f390d2c7 2174
d62a17ae 2175 area->t_lsp_refresh[1] = NULL;
2176 area->lsp_regenerate_pending[1] = 0;
f390d2c7 2177
d62a17ae 2178 if ((area->is_type & IS_LEVEL_2) == 0)
2179 return ISIS_ERROR;
3f045a08 2180
d62a17ae 2181 sched_debug(
2182 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
2183 area->area_tag);
2184 return lsp_regenerate(area, IS_LEVEL_2);
eb5d44eb 2185}
2186
d62a17ae 2187int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo)
eb5d44eb 2188{
d62a17ae 2189 struct isis_lsp *lsp;
2190 u_char id[ISIS_SYS_ID_LEN + 2];
2191 time_t now, diff;
2192 long timeout;
2193 struct listnode *cnode;
2194 struct isis_circuit *circuit;
2195 int lvl;
2196
2197 if (area == NULL)
2198 return ISIS_ERROR;
2199
2200 sched_debug(
2201 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2202 area->area_tag, circuit_t2string(level),
2203 all_pseudo ? "" : "not ");
2204
2205 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
2206 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
2207 now = time(NULL);
2208
2209 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
2210 if (!((level & lvl) && (area->is_type & lvl)))
2211 continue;
2212
2213 sched_debug(
2214 "ISIS (%s): Checking whether L%d needs to be scheduled",
2215 area->area_tag, lvl);
2216
2217 if (area->lsp_regenerate_pending[lvl - 1]) {
2218 struct timeval remain = thread_timer_remain(
2219 area->t_lsp_refresh[lvl - 1]);
2220 sched_debug(
2221 "ISIS (%s): Regeneration is already pending, nothing todo."
2222 " (Due in %lld.%03lld seconds)",
2223 area->area_tag, (long long)remain.tv_sec,
2224 (long long)remain.tv_usec / 1000);
2225 continue;
2226 }
2227
2228 lsp = lsp_search(id, area->lspdb[lvl - 1]);
2229 if (!lsp) {
2230 sched_debug(
2231 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2232 area->area_tag);
2233 continue;
2234 }
2235
2236 /*
2237 * Throttle avoidance
2238 */
2239 sched_debug(
2240 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2241 area->area_tag, (long long)lsp->last_generated,
2242 (long long)now);
2243 THREAD_TIMER_OFF(area->t_lsp_refresh[lvl - 1]);
2244 diff = now - lsp->last_generated;
2245 if (diff < area->lsp_gen_interval[lvl - 1]) {
2246 timeout =
2247 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
2248 sched_debug(
2249 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2250 area->area_tag, timeout);
2251 } else {
2252 /*
2253 * lsps are not regenerated if lsp_regenerate function
2254 * is called
2255 * directly. However if the lsp_regenerate call is
2256 * queued for
2257 * later execution it works.
2258 */
2259 timeout = 100;
2260 sched_debug(
2261 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2262 " Scheduling for execution in %ld ms.",
2263 area->area_tag, timeout);
2264 }
2265
2266 area->lsp_regenerate_pending[lvl - 1] = 1;
2267 if (lvl == IS_LEVEL_1) {
2268 thread_add_timer_msec(master, lsp_l1_refresh, area,
2269 timeout,
2270 &area->t_lsp_refresh[lvl - 1]);
2271 } else if (lvl == IS_LEVEL_2) {
2272 thread_add_timer_msec(master, lsp_l2_refresh, area,
2273 timeout,
2274 &area->t_lsp_refresh[lvl - 1]);
2275 }
2276 }
2277
2278 if (all_pseudo) {
2279 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
2280 lsp_regenerate_schedule_pseudo(circuit, level);
2281 }
2282
2283 return ISIS_OK;
eb5d44eb 2284}
2285
2286/*
2287 * Funcs for pseudonode LSPs
2288 */
2289
2290/*
d62a17ae 2291 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
eb5d44eb 2292 */
d62a17ae 2293static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
2294 int level)
eb5d44eb 2295{
d62a17ae 2296 struct isis_adjacency *adj;
2297 struct is_neigh *is_neigh;
2298 struct te_is_neigh *te_is_neigh;
2299 struct es_neigh *es_neigh;
2300 struct list *adj_list;
2301 struct listnode *node;
2302 struct isis_area *area = circuit->area;
2303
2304 lsp_debug(
2305 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2306 area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
2307 circuit->interface->name, level);
2308
2309 lsp->level = level;
2310 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2311 lsp->lsp_header->lsp_bits =
2312 lsp_bits_generate(level, 0, circuit->area->attached_bit);
2313
2314 /*
2315 * add self to IS neighbours
2316 */
2317 if (circuit->area->oldmetric) {
2318 if (lsp->tlv_data.is_neighs == NULL) {
2319 lsp->tlv_data.is_neighs = list_new();
2320 lsp->tlv_data.is_neighs->del = free_tlv;
aa4376ec 2321 }
d62a17ae 2322 is_neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct is_neigh));
2323
2324 memcpy(&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2325 listnode_add(lsp->tlv_data.is_neighs, is_neigh);
2326 lsp_debug(
2327 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2328 area->area_tag, sysid_print(is_neigh->neigh_id),
2329 LSP_PSEUDO_ID(is_neigh->neigh_id));
2330 }
2331 if (circuit->area->newmetric) {
2332 if (lsp->tlv_data.te_is_neighs == NULL) {
2333 lsp->tlv_data.te_is_neighs = list_new();
2334 lsp->tlv_data.te_is_neighs->del = free_tlv;
aa4376ec 2335 }
d62a17ae 2336 te_is_neigh =
2337 XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
2338
2339 memcpy(&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2340 listnode_add(lsp->tlv_data.te_is_neighs, te_is_neigh);
2341 lsp_debug(
2342 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2343 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2344 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
2345 }
2346
2347 adj_list = list_new();
2348 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
2349
2350 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
2351 if (adj->level & level) {
2352 if ((level == IS_LEVEL_1
2353 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
2354 || (level == IS_LEVEL_1
2355 && adj->sys_type == ISIS_SYSTYPE_L2_IS
2356 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
2357 || (level == IS_LEVEL_2
2358 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
2359 /* an IS neighbour -> add it */
2360 if (circuit->area->oldmetric) {
2361 is_neigh = XCALLOC(
2362 MTYPE_ISIS_TLV,
2363 sizeof(struct is_neigh));
2364
2365 memcpy(&is_neigh->neigh_id, adj->sysid,
2366 ISIS_SYS_ID_LEN);
2367 listnode_add(lsp->tlv_data.is_neighs,
2368 is_neigh);
2369 lsp_debug(
2370 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2371 area->area_tag,
2372 sysid_print(is_neigh->neigh_id),
2373 LSP_PSEUDO_ID(
2374 is_neigh->neigh_id));
2375 }
2376 if (circuit->area->newmetric) {
2377 te_is_neigh = XCALLOC(
2378 MTYPE_ISIS_TLV,
2379 sizeof(struct te_is_neigh));
2380 memcpy(&te_is_neigh->neigh_id,
2381 adj->sysid, ISIS_SYS_ID_LEN);
2382 listnode_add(lsp->tlv_data.te_is_neighs,
2383 te_is_neigh);
2384 lsp_debug(
2385 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2386 area->area_tag,
2387 sysid_print(
2388 te_is_neigh->neigh_id),
2389 LSP_PSEUDO_ID(
2390 te_is_neigh->neigh_id));
2391 }
2392 } else if (level == IS_LEVEL_1
2393 && adj->sys_type == ISIS_SYSTYPE_ES) {
2394 /* an ES neigbour add it, if we are building
2395 * level 1 LSP */
2396 /* FIXME: the tlv-format is hard to use here */
2397 if (lsp->tlv_data.es_neighs == NULL) {
2398 lsp->tlv_data.es_neighs = list_new();
2399 lsp->tlv_data.es_neighs->del = free_tlv;
2400 }
2401 es_neigh = XCALLOC(MTYPE_ISIS_TLV,
2402 sizeof(struct es_neigh));
2403
2404 memcpy(&es_neigh->first_es_neigh, adj->sysid,
2405 ISIS_SYS_ID_LEN);
2406 listnode_add(lsp->tlv_data.es_neighs, es_neigh);
2407 lsp_debug(
2408 "ISIS (%s): Adding %s as ES neighbor (peer)",
2409 area->area_tag,
2410 sysid_print(es_neigh->first_es_neigh));
2411 } else {
2412 lsp_debug(
2413 "ISIS (%s): Ignoring neighbor %s, level does not match",
2414 area->area_tag,
2415 sysid_print(adj->sysid));
2416 }
2417 } else {
2418 lsp_debug(
2419 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
2420 area->area_tag, sysid_print(adj->sysid));
f390d2c7 2421 }
d62a17ae 2422 }
2423 list_delete(adj_list);
2424
2425 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.",
2426 area->area_tag);
2427
2428 /* Reset endp of stream to overwrite only TLV part of it. */
2429 stream_reset(lsp->pdu);
2430 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2431
2432 /*
2433 * Add the authentication info if it's present
2434 */
2435 lsp_auth_add(lsp);
2436
2437 if (lsp->tlv_data.is_neighs && listcount(lsp->tlv_data.is_neighs) > 0)
2438 tlv_add_is_neighs(lsp->tlv_data.is_neighs, lsp->pdu);
2439
2440 if (lsp->tlv_data.te_is_neighs
2441 && listcount(lsp->tlv_data.te_is_neighs) > 0)
2442 tlv_add_te_is_neighs(lsp->tlv_data.te_is_neighs, lsp->pdu,
2443 NULL);
2444
2445 if (lsp->tlv_data.es_neighs && listcount(lsp->tlv_data.es_neighs) > 0)
2446 tlv_add_is_neighs(lsp->tlv_data.es_neighs, lsp->pdu);
2447
2448 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
2449
2450 /* Recompute authentication and checksum information */
2451 lsp_auth_update(lsp);
2452 fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
2453 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
2454
2455 return;
eb5d44eb 2456}
2457
d62a17ae 2458int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
3f045a08 2459{
d62a17ae 2460 dict_t *lspdb = circuit->area->lspdb[level - 1];
2461 struct isis_lsp *lsp;
2462 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2463 u_int16_t rem_lifetime, refresh_time;
2464
2465 if ((circuit->is_type & level) != level
2466 || (circuit->state != C_STATE_UP)
2467 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
2468 || (circuit->u.bc.is_dr[level - 1] == 0))
2469 return ISIS_ERROR;
2470
2471 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2472 LSP_FRAGMENT(lsp_id) = 0;
2473 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
2474
2475 /*
2476 * If for some reason have a pseudo LSP in the db already -> regenerate
2477 */
2478 if (lsp_search(lsp_id, lspdb))
2479 return lsp_regenerate_schedule_pseudo(circuit, level);
2480
2481 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
2482 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2483 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
2484 circuit->area->is_type | circuit->area->attached_bit, 0,
2485 level);
2486 lsp->area = circuit->area;
2487
2488 lsp_build_pseudo(lsp, circuit, level);
2489
2490 lsp->own_lsp = 1;
2491 lsp_insert(lsp, lspdb);
2492 lsp_set_all_srmflags(lsp);
2493
2494 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
2495 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2496 circuit->lsp_regenerate_pending[level - 1] = 0;
2497 if (level == IS_LEVEL_1)
2498 thread_add_timer(
2499 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
2500 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2501 else if (level == IS_LEVEL_2)
2502 thread_add_timer(
2503 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
2504 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2505
2506 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2507 zlog_debug(
2508 "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2509 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2510 circuit->area->area_tag, level,
2511 rawlspid_print(lsp->lsp_header->lsp_id),
2512 ntohl(lsp->lsp_header->pdu_len),
2513 ntohl(lsp->lsp_header->seq_num),
2514 ntohs(lsp->lsp_header->checksum),
2515 ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
2516 }
2517
2518 return ISIS_OK;
3f045a08
JB
2519}
2520
d62a17ae 2521static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
eb5d44eb 2522{
d62a17ae 2523 dict_t *lspdb = circuit->area->lspdb[level - 1];
2524 struct isis_lsp *lsp;
2525 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2526 u_int16_t rem_lifetime, refresh_time;
2527
2528 if ((circuit->is_type & level) != level
2529 || (circuit->state != C_STATE_UP)
2530 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
2531 || (circuit->u.bc.is_dr[level - 1] == 0))
2532 return ISIS_ERROR;
2533
2534 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2535 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
2536 LSP_FRAGMENT(lsp_id) = 0;
2537
2538 lsp = lsp_search(lsp_id, lspdb);
2539
2540 if (!lsp) {
2541 zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level,
2542 rawlspid_print(lsp_id));
2543 return ISIS_ERROR;
2544 }
2545 lsp_clear_data(lsp);
2546
2547 lsp_build_pseudo(lsp, circuit, level);
2548
2549 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2550 lsp->lsp_header->lsp_bits =
2551 lsp_bits_generate(level, 0, circuit->area->attached_bit);
2552 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
2553 lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
2554 lsp_inc_seqnum(lsp, 0);
2555 lsp->last_generated = time(NULL);
2556 lsp_set_all_srmflags(lsp);
2557
2558 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
2559 if (level == IS_LEVEL_1)
2560 thread_add_timer(
2561 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
2562 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2563 else if (level == IS_LEVEL_2)
2564 thread_add_timer(
2565 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
2566 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2567
2568 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2569 zlog_debug(
2570 "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2571 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2572 circuit->area->area_tag, level,
2573 rawlspid_print(lsp->lsp_header->lsp_id),
2574 ntohl(lsp->lsp_header->pdu_len),
2575 ntohl(lsp->lsp_header->seq_num),
2576 ntohs(lsp->lsp_header->checksum),
2577 ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
2578 }
2579
2580 return ISIS_OK;
eb5d44eb 2581}
2582
3f045a08
JB
2583/*
2584 * Something has changed or periodic refresh -> regenerate pseudo LSP
2585 */
d62a17ae 2586static int lsp_l1_refresh_pseudo(struct thread *thread)
eb5d44eb 2587{
d62a17ae 2588 struct isis_circuit *circuit;
2589 u_char id[ISIS_SYS_ID_LEN + 2];
eb5d44eb 2590
d62a17ae 2591 circuit = THREAD_ARG(thread);
f390d2c7 2592
d62a17ae 2593 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
2594 circuit->lsp_regenerate_pending[0] = 0;
13c48f72 2595
d62a17ae 2596 if ((circuit->u.bc.is_dr[0] == 0)
2597 || (circuit->is_type & IS_LEVEL_1) == 0) {
2598 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
2599 LSP_PSEUDO_ID(id) = circuit->circuit_id;
2600 LSP_FRAGMENT(id) = 0;
2601 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
2602 return ISIS_ERROR;
2603 }
eb5d44eb 2604
d62a17ae 2605 return lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
eb5d44eb 2606}
2607
d62a17ae 2608static int lsp_l2_refresh_pseudo(struct thread *thread)
eb5d44eb 2609{
d62a17ae 2610 struct isis_circuit *circuit;
2611 u_char id[ISIS_SYS_ID_LEN + 2];
f390d2c7 2612
d62a17ae 2613 circuit = THREAD_ARG(thread);
f390d2c7 2614
d62a17ae 2615 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
2616 circuit->lsp_regenerate_pending[1] = 0;
13c48f72 2617
d62a17ae 2618 if ((circuit->u.bc.is_dr[1] == 0)
2619 || (circuit->is_type & IS_LEVEL_2) == 0) {
2620 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
2621 LSP_PSEUDO_ID(id) = circuit->circuit_id;
2622 LSP_FRAGMENT(id) = 0;
2623 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
2624 return ISIS_ERROR;
2625 }
eb5d44eb 2626
d62a17ae 2627 return lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
eb5d44eb 2628}
2629
d62a17ae 2630int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
eb5d44eb 2631{
d62a17ae 2632 struct isis_lsp *lsp;
2633 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2634 time_t now, diff;
2635 long timeout;
2636 int lvl;
2637 struct isis_area *area = circuit->area;
2638
2639 if (circuit->circ_type != CIRCUIT_T_BROADCAST
2640 || circuit->state != C_STATE_UP)
2641 return ISIS_OK;
2642
2643 sched_debug(
2644 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2645 area->area_tag, circuit_t2string(level),
2646 circuit->interface->name);
2647
2648 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2649 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
2650 LSP_FRAGMENT(lsp_id) = 0;
2651 now = time(NULL);
2652
2653 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
2654 sched_debug(
2655 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2656 area->area_tag, lvl);
2657
2658 if (!((level & lvl) && (circuit->is_type & lvl))) {
2659 sched_debug("ISIS (%s): Level is not active on circuit",
2660 area->area_tag);
2661 continue;
2662 }
2663
2664 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
2665 sched_debug(
2666 "ISIS (%s): This IS is not DR, nothing to do.",
2667 area->area_tag);
2668 continue;
2669 }
2670
2671 if (circuit->lsp_regenerate_pending[lvl - 1]) {
2672 struct timeval remain = thread_timer_remain(
2673 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2674 sched_debug(
2675 "ISIS (%s): Regenerate is already pending, nothing todo."
2676 " (Due in %lld.%03lld seconds)",
2677 area->area_tag, (long long)remain.tv_sec,
2678 (long long)remain.tv_usec / 1000);
2679 continue;
2680 }
2681
2682 lsp = lsp_search(lsp_id, circuit->area->lspdb[lvl - 1]);
2683 if (!lsp) {
2684 sched_debug(
2685 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2686 area->area_tag);
2687 continue;
2688 }
2689
2690 /*
2691 * Throttle avoidance
2692 */
2693 sched_debug(
2694 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2695 area->area_tag, (long long)lsp->last_generated,
2696 (long long)now);
2697 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2698 diff = now - lsp->last_generated;
2699 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
9d303b37
DL
2700 timeout =
2701 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
2702 - diff);
d62a17ae 2703 sched_debug(
2704 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2705 area->area_tag, timeout);
2706 } else {
2707 timeout = 100;
2708 sched_debug(
2709 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2710 " Scheduling for execution in %ld ms.",
2711 area->area_tag, timeout);
2712 }
2713
2714 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2715
2716 if (lvl == IS_LEVEL_1) {
2717 thread_add_timer_msec(
2718 master, lsp_l1_refresh_pseudo, circuit, timeout,
2719 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2720 } else if (lvl == IS_LEVEL_2) {
2721 thread_add_timer_msec(
2722 master, lsp_l2_refresh_pseudo, circuit, timeout,
2723 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2724 }
2725 }
2726
2727 return ISIS_OK;
f390d2c7 2728}
eb5d44eb 2729
2730/*
2731 * Walk through LSPs for an area
2732 * - set remaining lifetime
2733 * - set LSPs with SRMflag set for sending
2734 */
d62a17ae 2735int lsp_tick(struct thread *thread)
eb5d44eb 2736{
d62a17ae 2737 struct isis_area *area;
2738 struct isis_circuit *circuit;
2739 struct isis_lsp *lsp;
2740 struct list *lsp_list;
2741 struct listnode *lspnode, *cnode;
2742 dnode_t *dnode, *dnode_next;
2743 int level;
2744 u_int16_t rem_lifetime;
2745
2746 lsp_list = list_new();
2747
2748 area = THREAD_ARG(thread);
2749 assert(area);
2750 area->t_tick = NULL;
2751 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
2752
2753 /*
2754 * Build a list of LSPs with (any) SRMflag set
2755 * and removed the ones that have aged out
2756 */
2757 for (level = 0; level < ISIS_LEVELS; level++) {
2758 if (area->lspdb[level] && dict_count(area->lspdb[level]) > 0) {
2759 for (dnode = dict_first(area->lspdb[level]);
2760 dnode != NULL; dnode = dnode_next) {
2761 dnode_next =
2762 dict_next(area->lspdb[level], dnode);
2763 lsp = dnode_get(dnode);
2764
2765 /*
2766 * The lsp rem_lifetime is kept at 0 for MaxAge
2767 * or
2768 * ZeroAgeLifetime depending on explicit purge
2769 * or
2770 * natural age out. So schedule spf only once
2771 * when
2772 * the first time rem_lifetime becomes 0.
2773 */
2774 rem_lifetime =
2775 ntohs(lsp->lsp_header->rem_lifetime);
2776 lsp_set_time(lsp);
2777
2778 /*
2779 * Schedule may run spf which should be done
2780 * only after
2781 * the lsp rem_lifetime becomes 0 for the first
2782 * time.
2783 * ISO 10589 - 7.3.16.4 first paragraph.
2784 */
2785 if (rem_lifetime == 1
2786 && lsp->lsp_header->seq_num != 0) {
2787 /* 7.3.16.4 a) set SRM flags on all */
2788 lsp_set_all_srmflags(lsp);
2789 /* 7.3.16.4 b) retain only the header
2790 * FIXME */
2791 /* 7.3.16.4 c) record the time to purge
2792 * FIXME */
2793 /* run/schedule spf */
2794 /* isis_spf_schedule is called inside
2795 * lsp_destroy() below;
2796 * so it is not needed here. */
2797 /* isis_spf_schedule (lsp->area,
2798 * lsp->level); */
2799 }
2800
2801 if (lsp->age_out == 0) {
2802 zlog_debug(
2803 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2804 area->area_tag, lsp->level,
2805 rawlspid_print(
2806 lsp->lsp_header
2807 ->lsp_id),
2808 ntohl(lsp->lsp_header
2809 ->seq_num));
2810 lsp_destroy(lsp);
2811 lsp = NULL;
2812 dict_delete_free(area->lspdb[level],
2813 dnode);
2814 } else if (flags_any_set(lsp->SRMflags))
2815 listnode_add(lsp_list, lsp);
2816 }
2817
2818 /*
2819 * Send LSPs on circuits indicated by the SRMflags
2820 */
2821 if (listcount(lsp_list) > 0) {
2822 for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
2823 cnode, circuit)) {
2824 int diff =
2825 time(NULL)
2826 - circuit->lsp_queue_last_cleared;
2827 if (circuit->lsp_queue == NULL
2828 || diff < MIN_LSP_TRANS_INTERVAL)
2829 continue;
2830 for (ALL_LIST_ELEMENTS_RO(
2831 lsp_list, lspnode, lsp)) {
2832 if (circuit->upadjcount
2833 [lsp->level - 1]
2834 && ISIS_CHECK_FLAG(
2835 lsp->SRMflags,
2836 circuit)) {
2837 /* Add the lsp only if
2838 * it is not already in
2839 * lsp
2840 * queue */
2841 if (!listnode_lookup(
2842 circuit->lsp_queue,
2843 lsp)) {
2844 listnode_add(
2845 circuit->lsp_queue,
2846 lsp);
2847 thread_add_event(
2848 master,
2849 send_lsp,
2850 circuit,
2851 0,
2852 NULL);
2853 }
2854 }
2855 }
2856 }
2857 list_delete_all_node(lsp_list);
2858 }
2859 }
2860 }
2861
2862 list_delete(lsp_list);
2863
2864 return ISIS_OK;
eb5d44eb 2865}
2866
d62a17ae 2867void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level)
eb5d44eb 2868{
d62a17ae 2869 struct isis_lsp *lsp;
2870 u_int16_t seq_num;
2871 u_int8_t lsp_bits;
2872
2873 lsp = lsp_search(id, circuit->area->lspdb[level - 1]);
2874 if (!lsp)
2875 return;
2876
2877 /* store old values */
2878 seq_num = lsp->lsp_header->seq_num;
2879 lsp_bits = lsp->lsp_header->lsp_bits;
2880
2881 /* reset stream */
2882 lsp_clear_data(lsp);
2883 stream_reset(lsp->pdu);
2884
2885 /* update header */
2886 lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2887 memcpy(lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
2888 lsp->lsp_header->checksum = 0;
2889 lsp->lsp_header->seq_num = seq_num;
2890 lsp->lsp_header->rem_lifetime = 0;
2891 lsp->lsp_header->lsp_bits = lsp_bits;
2892 lsp->level = level;
2893 lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
2894 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2895
2896 /*
2897 * Add and update the authentication info if its present
2898 */
2899 lsp_auth_add(lsp);
2900 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
2901 lsp_auth_update(lsp);
2902 fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
2903 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
2904
2905 lsp_set_all_srmflags(lsp);
2906
2907 return;
eb5d44eb 2908}
2909
2910/*
d62a17ae 2911 * Purge own LSP that is received and we don't have.
eb5d44eb 2912 * -> Do as in 7.3.16.4
2913 */
d62a17ae 2914void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
2915 struct isis_area *area)
eb5d44eb 2916{
d62a17ae 2917 struct isis_lsp *lsp;
88f9d911
CF
2918 uint8_t pdu_type =
2919 (level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
d62a17ae 2920
2921 /*
2922 * We need to create the LSP to be purged
2923 */
2924 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
2925 lsp->area = area;
2926 lsp->level = level;
2927 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
88f9d911
CF
2928 fill_fixed_hdr(pdu_type, lsp->pdu);
2929
d62a17ae 2930 lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
2931 + ISIS_FIXED_HDR_LEN);
2932 memcpy(lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
2933 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2934
2935 /*
2936 * Set the remaining lifetime to 0
2937 */
2938 lsp->lsp_header->rem_lifetime = 0;
2939
2940 /*
2941 * Add and update the authentication info if its present
2942 */
2943 lsp_auth_add(lsp);
2944 lsp_auth_update(lsp);
2945
2946 /*
2947 * Update the PDU length to header plus any authentication TLV.
2948 */
2949 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
2950
2951 /*
2952 * Put the lsp into LSPdb
2953 */
2954 lsp_insert(lsp, area->lspdb[lsp->level - 1]);
2955
2956 /*
2957 * Send in to whole area
2958 */
2959 lsp_set_all_srmflags(lsp);
2960
2961 return;
eb5d44eb 2962}
2963
d62a17ae 2964void lsp_set_all_srmflags(struct isis_lsp *lsp)
3f045a08 2965{
d62a17ae 2966 struct listnode *node;
2967 struct isis_circuit *circuit;
3f045a08 2968
d62a17ae 2969 assert(lsp);
3f045a08 2970
d62a17ae 2971 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
3f045a08 2972
d62a17ae 2973 if (lsp->area) {
2974 struct list *circuit_list = lsp->area->circuit_list;
2975 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
2976 ISIS_SET_FLAG(lsp->SRMflags, circuit);
2977 }
2978 }
3f045a08 2979}