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