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