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