]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
*: use vty_outln
[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_outln (vty, "%s",
828 lsp_bits2string(&lsp->lsp_header->lsp_bits));
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_outln(vty, " Metric : %-8u IS-Extended : %s",
846 GET_TE_METRIC(neigh), lspid);
847 }
848 else
849 {
850 vty_outln(vty, " Metric : %-8u MT-Reach : %s %s",
851 GET_TE_METRIC(neigh), lspid,
852 isis_mtid2str(mtid));
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_outln (vty, " Metric : %-8" PRIu32 " IPv6-Internal : %s/%d",
878 ntohl (ipv6_reach->metric),
879 buff, ipv6_reach->prefix_len);
880 else
881 vty_outln (vty, " Metric : %-8" PRIu32 " IPv6-External : %s/%d",
882 ntohl (ipv6_reach->metric),
883 buff, ipv6_reach->prefix_len);
884 }
885 else
886 {
887 if ((ipv6_reach->control_info &
888 CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
889 vty_outln (vty, " Metric : %-8" PRIu32 " IPv6-MT-Int : %s/%d %s",
890 ntohl (ipv6_reach->metric),
891 buff, ipv6_reach->prefix_len,
892 isis_mtid2str(mtid));
893 else
894 vty_outln (vty, " Metric : %-8" PRIu32 " IPv6-MT-Ext : %s/%d %s",
895 ntohl (ipv6_reach->metric),
896 buff, ipv6_reach->prefix_len,
897 isis_mtid2str(mtid));
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_outln (vty, " Metric : %-8" PRIu32 " IPv4-Extended : %s/%d",
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);
918 }
919 else
920 {
921 /* FIXME: There should be better way to output this stuff. */
922 vty_outln (vty, " Metric : %-8" PRIu32 " IPv4-MT : %s/%d %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));
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_outln (vty, " Area Address: %s",
959 isonet_print(area_addr->area_addr, area_addr->addr_len));
960 }
961
962 /* for the nlpid tlv */
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:
971 vty_outln (vty, " NLPID : 0x%X",
972 lsp->tlv_data.nlpids->nlpids[i]);
973 break;
974 default:
975 vty_outln (vty, " NLPID : %s", "unknown");
976 break;
977 }
978 }
979 }
980
981 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
982 {
983 vty_outln (vty, " MT : %s%s",
984 isis_mtid2str(mt_router_info->mtid),
985 mt_router_info->overload ? " (overload)" : "");
986 }
987
988 /* for the hostname tlv */
989 if (lsp->tlv_data.hostname)
990 {
991 bzero (hostname, sizeof (hostname));
992 memcpy (hostname, lsp->tlv_data.hostname->name,
993 lsp->tlv_data.hostname->namelen);
994 vty_outln (vty, " Hostname : %s", hostname);
995 }
996
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)
1001 vty_outln (vty, " Auth type : md5");
1002 else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
1003 vty_outln (vty, " Auth type : clear text");
1004 }
1005
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));
1011 vty_outln (vty, " Router ID : %s", ipv4_address);
1012 }
1013
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));
1018 vty_outln (vty, " IPv4 Address: %s", ipv4_address);
1019 }
1020
1021 /* for the IS neighbor tlv */
1022 if (lsp->tlv_data.is_neighs)
1023 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
1024 {
1025 lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
1026 vty_outln (vty, " Metric : %-8" PRIu8 " IS : %s",
1027 is_neigh->metrics.metric_default, LSPid);
1028 }
1029
1030 /* for the internal reachable tlv */
1031 if (lsp->tlv_data.ipv4_int_reachs)
1032 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
1033 ipv4_reach))
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));
1039 vty_outln (vty, " Metric : %-8" PRIu8 " IPv4-Internal : %s %s",
1040 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
1041 ipv4_reach_mask);
1042 }
1043
1044 /* for the external reachable tlv */
1045 if (lsp->tlv_data.ipv4_ext_reachs)
1046 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode,
1047 ipv4_reach))
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));
1053 vty_outln (vty, " Metric : %-8" PRIu8 " IPv4-External : %s %s",
1054 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
1055 ipv4_reach_mask);
1056 }
1057
1058 /* IPv6 tlv */
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);
1065
1066 /* TE IS neighbor tlv */
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);
1073
1074 /* TE IPv4 tlv */
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
1082 vty_outln (vty, "");
1083
1084 return;
1085 }
1086
1087 /* print all the lsps info in the local lspdb */
1088 int
1089 lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
1090 {
1091
1092 dnode_t *node = dict_first (lspdb), *next;
1093 int lsp_count = 0;
1094
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);
1102 lsp_print (dnode_get (node), vty, dynhost);
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);
1112 lsp_print_detail (dnode_get (node), vty, dynhost);
1113 node = next;
1114 lsp_count++;
1115 }
1116 }
1117
1118 return lsp_count;
1119 }
1120
1121 static 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
1157 #define FRAG_THOLD(S,T) \
1158 ((STREAM_SIZE(S)*T)/100)
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
1164 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1165 * variable length (TE TLVs, sub TLVs). */
1166 static void
1167 lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
1168 int tlvsize, int frag_thold,
1169 int tlv_build_func (struct list *, struct stream *))
1170 {
1171 int count, i;
1172
1173 /* can we fit all ? */
1174 if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
1175 {
1176 tlv_build_func (*from, lsp->pdu);
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 }
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));
1200 count = count / tlvsize;
1201 if (count > (int)listcount (*from))
1202 count = listcount (*from);
1203 for (i = 0; i < count; i++)
1204 {
1205 listnode_add (*to, listgetdata (listhead (*from)));
1206 listnode_delete (*from, listgetdata (listhead (*from)));
1207 }
1208 tlv_build_func (*to, lsp->pdu);
1209 }
1210 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
1211 return;
1212 }
1213
1214 static u_int16_t
1215 lsp_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 */
1224 /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at
1225 * this point */
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
1232 static u_int16_t
1233 lsp_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
1249 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1250 * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
1251
1252 return refresh_time;
1253 }
1254
1255 static struct isis_lsp *
1256 lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
1257 int level)
1258 {
1259 struct isis_lsp *lsp;
1260 u_char frag_id[ISIS_SYS_ID_LEN + 2];
1261
1262 memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1263 LSP_FRAGMENT (frag_id) = frag_num;
1264 /* FIXME add authentication TLV for fragment LSPs */
1265 lsp = lsp_search (frag_id, area->lspdb[level - 1]);
1266 if (lsp)
1267 {
1268 /* Clear the TLVs */
1269 lsp_clear_data (lsp);
1270 return lsp;
1271 }
1272 lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
1273 lsp_bits_generate (level, area->overload_bit,
1274 area->attached_bit), 0, level);
1275 lsp->area = area;
1276 lsp->own_lsp = 1;
1277 lsp_insert (lsp, area->lspdb[level - 1]);
1278 listnode_add (lsp0->lspu.frags, lsp);
1279 lsp->lspu.zero_lsp = lsp0;
1280 return lsp;
1281 }
1282
1283 static void
1284 lsp_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
1349 static struct list *
1350 tlv_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
1367 static void
1368 lsp_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;
1376 struct list *reach_list = NULL;
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
1390 if (!reach_list)
1391 reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
1392
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));
1401 listnode_add(reach_list, ip6reach);
1402 }
1403 }
1404
1405 static void
1406 lsp_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
1413 /*
1414 * Builds the LSP data part. This func creates a new frag whenever
1415 * area->lsp_frag_threshold is exceeded.
1416 */
1417 static void
1418 lsp_build (struct isis_lsp *lsp, struct isis_area *area)
1419 {
1420 struct is_neigh *is_neigh;
1421 struct te_is_neigh *te_is_neigh;
1422 struct listnode *node, *ipnode;
1423 int level = lsp->level;
1424 struct isis_circuit *circuit;
1425 struct prefix_ipv4 *ipv4;
1426 struct ipv4_reachability *ipreach;
1427 struct te_ipv4_reachability *te_ipreach;
1428 struct isis_adjacency *nei;
1429 struct prefix_ipv6 *ipv6, ip6prefix;
1430 struct list *ipv6_reachs = NULL;
1431 struct ipv6_reachability *ip6reach;
1432 struct tlvs tlv_data;
1433 struct isis_lsp *lsp0 = lsp;
1434 struct in_addr *routerid;
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;
1439 char buf[BUFSIZ];
1440
1441 lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level);
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);
1458
1459 /*
1460 * First add the tlvs related to area
1461 */
1462
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);
1467 if (listcount (lsp->tlv_data.area_addrs) > 0)
1468 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
1469
1470 /* Protocols Supported */
1471 if (area->ip_circuits > 0 || area->ipv6_circuits > 0)
1472 {
1473 lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
1474 lsp->tlv_data.nlpids->count = 0;
1475 if (area->ip_circuits > 0)
1476 {
1477 lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag);
1478 lsp->tlv_data.nlpids->count++;
1479 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1480 }
1481 if (area->ipv6_circuits > 0)
1482 {
1483 lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag);
1484 lsp->tlv_data.nlpids->count++;
1485 lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
1486 NLPID_IPV6;
1487 }
1488 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
1489 }
1490
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 }
1517 /* Dynamic Hostname */
1518 if (area->dynhostname)
1519 {
1520 const char *hostname = unix_hostname();
1521 size_t hostname_len = strlen(hostname);
1522
1523 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
1524 sizeof (struct hostname));
1525
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
1533 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag,
1534 lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name);
1535 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
1536 }
1537 else
1538 {
1539 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag);
1540 }
1541
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. */
1545 if (isis->router_id != 0)
1546 {
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);
1549 if (lsp->tlv_data.ipv4_addrs == NULL)
1550 {
1551 lsp->tlv_data.ipv4_addrs = list_new ();
1552 lsp->tlv_data.ipv4_addrs->del = free_tlv;
1553 }
1554
1555 routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
1556 routerid->s_addr = isis->router_id;
1557 listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
1558 tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
1559
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 {
1564 lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag);
1565 lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
1566 sizeof (struct in_addr));
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);
1570 }
1571 }
1572 else
1573 {
1574 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag);
1575 }
1576
1577 memset (&tlv_data, 0, sizeof (struct tlvs));
1578
1579 lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag);
1580
1581 /*
1582 * Then build lists of tlvs related to circuits
1583 */
1584 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
1585 {
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
1593 if (circuit->state != C_STATE_UP)
1594 {
1595 lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag);
1596 continue;
1597 }
1598
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 {
1605 lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag);
1606 if (area->oldmetric)
1607 {
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 }
1613 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
1614 {
1615 ipreach =
1616 XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
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;
1621 masklen2ip (ipv4->prefixlen, &ipreach->mask);
1622 ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
1623 (ipv4->prefix.s_addr));
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);
1627 listnode_add (tlv_data.ipv4_int_reachs, ipreach);
1628 }
1629 }
1630 if (area->newmetric)
1631 {
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 }
1637 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
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);
1643
1644 if (area->oldmetric)
1645 te_ipreach->te_metric = htonl (circuit->metric[level - 1]);
1646 else
1647 te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
1648
1649 te_ipreach->control = (ipv4->prefixlen & 0x3F);
1650 memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1651 (ipv4->prefixlen + 7)/8);
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);
1655 listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
1656 }
1657 }
1658 }
1659
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 {
1666 if (!ipv6_reachs)
1667 ipv6_reachs = tlv_get_ipv6_reach_list(area, &tlv_data);
1668
1669 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
1670 {
1671 ip6reach =
1672 XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
1673
1674 if (area->oldmetric)
1675 ip6reach->metric =
1676 htonl (circuit->metric[level - 1]);
1677 else
1678 ip6reach->metric = htonl (circuit->te_metric[level - 1]);
1679
1680 ip6reach->control_info = 0;
1681 ip6reach->prefix_len = ipv6->prefixlen;
1682 memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
1683 apply_mask_ipv6(&ip6prefix);
1684
1685 inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf));
1686 lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
1687 area->area_tag, buf, ipv6->prefixlen);
1688
1689 memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
1690 sizeof (ip6reach->prefix));
1691 listnode_add (ipv6_reachs, ip6reach);
1692 }
1693 }
1694
1695 switch (circuit->circ_type)
1696 {
1697 case CIRCUIT_T_BROADCAST:
1698 if (level & circuit->is_type)
1699 {
1700 if (area->oldmetric)
1701 {
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));
1708 if (level == IS_LEVEL_1)
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);
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;
1718 if (!memcmp (is_neigh->neigh_id, zero_id,
1719 ISIS_SYS_ID_LEN + 1))
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 }
1725 else
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 }
1732 }
1733 if (area->newmetric)
1734 {
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));
1742 if (level == IS_LEVEL_1)
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);
1748 if (area->oldmetric)
1749 metric = circuit->metric[level - 1];
1750 else
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))
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 }
1760 else
1761 {
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
1770 tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh);
1771 XFREE(MTYPE_ISIS_TLV, te_is_neigh);
1772 }
1773 }
1774 }
1775 else
1776 {
1777 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1778 area->area_tag);
1779 }
1780 break;
1781 case CIRCUIT_T_P2P:
1782 nei = circuit->u.p2p.neighbor;
1783 if (nei && (level & nei->circuit_t))
1784 {
1785 if (area->oldmetric)
1786 {
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);
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;
1798 listnode_add (tlv_data.is_neighs, is_neigh);
1799 lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag,
1800 sysid_print(is_neigh->neigh_id));
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);
1814 metric = circuit->te_metric[level - 1];
1815 SET_TE_METRIC(te_is_neigh, metric);
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;
1828
1829 tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh);
1830 XFREE(MTYPE_ISIS_TLV, te_is_neigh);
1831 }
1832 }
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 }
1838 break;
1839 case CIRCUIT_T_LOOPBACK:
1840 break;
1841 default:
1842 zlog_warn ("lsp_area_create: unknown circuit type");
1843 }
1844 }
1845
1846 lsp_build_ext_reach(lsp, area, &tlv_data);
1847
1848 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag);
1849
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,
1857 tlv_add_ipv4_int_reachs);
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 }
1862
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
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 ();
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);
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 }
1886
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
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 ();
1908 _lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
1909 area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
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 }
1914
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
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 }
1944
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 ();
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);
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 }
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
1974 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
1975
1976 free_tlvs (&tlv_data);
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
1986 return;
1987 }
1988
1989 /*
1990 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1991 */
1992 int
1993 lsp_generate (struct isis_area *area, int level)
1994 {
1995 struct isis_lsp *oldlsp, *newlsp;
1996 u_int32_t seq_num = 0;
1997 u_char lspid[ISIS_SYS_ID_LEN + 2];
1998 u_int16_t rem_lifetime, refresh_time;
1999
2000 if ((area == NULL) || (area->is_type & level) != level)
2001 return ISIS_ERROR;
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 */
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);
2016 newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
2017 area->is_type | area->overload_bit | area->attached_bit,
2018 0, level);
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);
2027 newlsp->last_generated = time(NULL);
2028 lsp_set_all_srmflags (newlsp);
2029
2030 refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
2031
2032 THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
2033 area->lsp_regenerate_pending[level - 1] = 0;
2034 if (level == IS_LEVEL_1)
2035 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
2036 &area->t_lsp_refresh[level - 1]);
2037 else if (level == IS_LEVEL_2)
2038 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
2039 &area->t_lsp_refresh[level - 1]);
2040
2041 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2042 {
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);
2052 }
2053 sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2054 area->area_tag, level);
2055
2056 return ISIS_OK;
2057 }
2058
2059 /*
2060 * Search own LSPs, update holding time and set SRM
2061 */
2062 static int
2063 lsp_regenerate (struct isis_area *area, int level)
2064 {
2065 dict_t *lspdb;
2066 struct isis_lsp *lsp, *frag;
2067 struct listnode *node;
2068 u_char lspid[ISIS_SYS_ID_LEN + 2];
2069 u_int16_t rem_lifetime, refresh_time;
2070
2071 if ((area == NULL) || (area->is_type & level) != level)
2072 return ISIS_ERROR;
2073
2074 lspdb = area->lspdb[level - 1];
2075
2076 memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
2077 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
2078
2079 lsp = lsp_search (lspid, lspdb);
2080
2081 if (!lsp)
2082 {
2083 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2084 area->area_tag, level);
2085 return ISIS_ERROR;
2086 }
2087
2088 lsp_clear_data (lsp);
2089 lsp_build (lsp, area);
2090 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit,
2091 area->attached_bit);
2092 rem_lifetime = lsp_rem_lifetime (area, level);
2093 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
2094 lsp_seqnum_update (lsp);
2095
2096 lsp->last_generated = time (NULL);
2097 lsp_set_all_srmflags (lsp);
2098 for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
2099 {
2100 frag->lsp_header->lsp_bits = lsp_bits_generate (level,
2101 area->overload_bit,
2102 area->attached_bit);
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);
2108 }
2109
2110 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2111 if (level == IS_LEVEL_1)
2112 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
2113 &area->t_lsp_refresh[level - 1]);
2114 else if (level == IS_LEVEL_2)
2115 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
2116 &area->t_lsp_refresh[level - 1]);
2117 area->lsp_regenerate_pending[level - 1] = 0;
2118
2119 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2120 {
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);
2130 }
2131 sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2132 area->area_tag, level);
2133
2134 return ISIS_OK;
2135 }
2136
2137 /*
2138 * Something has changed or periodic refresh -> regenerate LSP
2139 */
2140 static int
2141 lsp_l1_refresh (struct thread *thread)
2142 {
2143 struct isis_area *area;
2144
2145 area = THREAD_ARG (thread);
2146 assert (area);
2147
2148 area->t_lsp_refresh[0] = NULL;
2149 area->lsp_regenerate_pending[0] = 0;
2150
2151 if ((area->is_type & IS_LEVEL_1) == 0)
2152 return ISIS_ERROR;
2153
2154 sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag);
2155 return lsp_regenerate (area, IS_LEVEL_1);
2156 }
2157
2158 static int
2159 lsp_l2_refresh (struct thread *thread)
2160 {
2161 struct isis_area *area;
2162
2163 area = THREAD_ARG (thread);
2164 assert (area);
2165
2166 area->t_lsp_refresh[1] = NULL;
2167 area->lsp_regenerate_pending[1] = 0;
2168
2169 if ((area->is_type & IS_LEVEL_2) == 0)
2170 return ISIS_ERROR;
2171
2172 sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag);
2173 return lsp_regenerate (area, IS_LEVEL_2);
2174 }
2175
2176 int
2177 lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
2178 {
2179 struct isis_lsp *lsp;
2180 u_char id[ISIS_SYS_ID_LEN + 2];
2181 time_t now, diff;
2182 long timeout;
2183 struct listnode *cnode;
2184 struct isis_circuit *circuit;
2185 int lvl;
2186
2187 if (area == NULL)
2188 return ISIS_ERROR;
2189
2190 sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2191 area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not ");
2192
2193 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2194 LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
2195 now = time (NULL);
2196
2197 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2198 {
2199 if (!((level & lvl) && (area->is_type & lvl)))
2200 continue;
2201
2202 sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2203 area->area_tag, lvl);
2204
2205 if (area->lsp_regenerate_pending[lvl - 1])
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 }
2213
2214 lsp = lsp_search (id, area->lspdb[lvl - 1]);
2215 if (!lsp)
2216 {
2217 sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2218 area->area_tag);
2219 continue;
2220 }
2221
2222 /*
2223 * Throttle avoidance
2224 */
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);
2227 THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
2228 diff = now - lsp->last_generated;
2229 if (diff < area->lsp_gen_interval[lvl - 1])
2230 {
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);
2234 }
2235 else
2236 {
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 */
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 {
2250 thread_add_timer_msec(master, lsp_l1_refresh, area, timeout,
2251 &area->t_lsp_refresh[lvl - 1]);
2252 }
2253 else if (lvl == IS_LEVEL_2)
2254 {
2255 thread_add_timer_msec(master, lsp_l2_refresh, area, timeout,
2256 &area->t_lsp_refresh[lvl - 1]);
2257 }
2258 }
2259
2260 if (all_pseudo)
2261 {
2262 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
2263 lsp_regenerate_schedule_pseudo (circuit, level);
2264 }
2265
2266 return ISIS_OK;
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 */
2276 static void
2277 lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
2278 int level)
2279 {
2280 struct isis_adjacency *adj;
2281 struct is_neigh *is_neigh;
2282 struct te_is_neigh *te_is_neigh;
2283 struct es_neigh *es_neigh;
2284 struct list *adj_list;
2285 struct listnode *node;
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);
2291
2292 lsp->level = level;
2293 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2294 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2295 circuit->area->attached_bit);
2296
2297 /*
2298 * add self to IS neighbours
2299 */
2300 if (circuit->area->oldmetric)
2301 {
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);
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));
2314 }
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));
2323
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);
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));
2329 }
2330
2331 adj_list = list_new ();
2332 isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list);
2333
2334 for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
2335 {
2336 if (adj->level & level)
2337 {
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 &&
2340 adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
2341 (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
2342 {
2343 /* an IS neighbour -> add it */
2344 if (circuit->area->oldmetric)
2345 {
2346 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
2347
2348 memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2349 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
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));
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);
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));
2363 }
2364 }
2365 else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
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 }
2374 es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
2375
2376 memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
2377 listnode_add (lsp->tlv_data.es_neighs, es_neigh);
2378 lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
2379 area->area_tag, sysid_print(es_neigh->first_es_neigh));
2380 }
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));
2391 }
2392 }
2393 list_delete (adj_list);
2394
2395 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag);
2396
2397 /* Reset endp of stream to overwrite only TLV part of it. */
2398 stream_reset (lsp->pdu);
2399 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2400
2401 /*
2402 * Add the authentication info if it's present
2403 */
2404 lsp_auth_add (lsp);
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
2409 if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
2410 tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu, NULL);
2411
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
2415 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2416
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);
2421
2422 return;
2423 }
2424
2425 int
2426 lsp_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 */
2451 lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1,
2452 circuit->area->is_type | circuit->area->attached_bit,
2453 0, level);
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)
2466 thread_add_timer(master, lsp_l1_refresh_pseudo, circuit, refresh_time,
2467 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2468 else if (level == IS_LEVEL_2)
2469 thread_add_timer(master, lsp_l2_refresh_pseudo, circuit, refresh_time,
2470 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
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
2488 static int
2489 lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
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];
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;
2501
2502 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2503 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2504 LSP_FRAGMENT (lsp_id) = 0;
2505
2506 lsp = lsp_search (lsp_id, lspdb);
2507
2508 if (!lsp)
2509 {
2510 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2511 level, rawlspid_print (lsp_id));
2512 return ISIS_ERROR;
2513 }
2514 lsp_clear_data (lsp);
2515
2516 lsp_build_pseudo (lsp, circuit, level);
2517
2518 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2519 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2520 circuit->area->attached_bit);
2521 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2522 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
2523 lsp_inc_seqnum (lsp, 0);
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)
2529 thread_add_timer(master, lsp_l1_refresh_pseudo, circuit, refresh_time,
2530 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2531 else if (level == IS_LEVEL_2)
2532 thread_add_timer(master, lsp_l2_refresh_pseudo, circuit, refresh_time,
2533 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2534
2535 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2536 {
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);
2546 }
2547
2548 return ISIS_OK;
2549 }
2550
2551 /*
2552 * Something has changed or periodic refresh -> regenerate pseudo LSP
2553 */
2554 static int
2555 lsp_l1_refresh_pseudo (struct thread *thread)
2556 {
2557 struct isis_circuit *circuit;
2558 u_char id[ISIS_SYS_ID_LEN + 2];
2559
2560 circuit = THREAD_ARG (thread);
2561
2562 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
2563 circuit->lsp_regenerate_pending[0] = 0;
2564
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 }
2574
2575 return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
2576 }
2577
2578 static int
2579 lsp_l2_refresh_pseudo (struct thread *thread)
2580 {
2581 struct isis_circuit *circuit;
2582 u_char id[ISIS_SYS_ID_LEN + 2];
2583
2584 circuit = THREAD_ARG (thread);
2585
2586 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
2587 circuit->lsp_regenerate_pending[1] = 0;
2588
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 }
2598
2599 return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
2600 }
2601
2602 int
2603 lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
2604 {
2605 struct isis_lsp *lsp;
2606 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2607 time_t now, diff;
2608 long timeout;
2609 int lvl;
2610 struct isis_area *area = circuit->area;
2611
2612 if (circuit->circ_type != CIRCUIT_T_BROADCAST ||
2613 circuit->state != C_STATE_UP)
2614 return ISIS_OK;
2615
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
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);
2623
2624 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2625 {
2626 sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2627 area->area_tag, lvl);
2628
2629 if (!((level & lvl) && (circuit->is_type & lvl)))
2630 {
2631 sched_debug("ISIS (%s): Level is not active on circuit",
2632 area->area_tag);
2633 continue;
2634 }
2635
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 }
2652
2653 lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
2654 if (!lsp)
2655 {
2656 sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2657 area->area_tag);
2658 continue;
2659 }
2660
2661 /*
2662 * Throttle avoidance
2663 */
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);
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 {
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);
2673 }
2674 else
2675 {
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 {
2685 thread_add_timer_msec(master, lsp_l1_refresh_pseudo, circuit,
2686 timeout,
2687 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2688 }
2689 else if (lvl == IS_LEVEL_2)
2690 {
2691 thread_add_timer_msec(master, lsp_l2_refresh_pseudo, circuit,
2692 timeout,
2693 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2694 }
2695 }
2696
2697 return ISIS_OK;
2698 }
2699
2700 /*
2701 * Walk through LSPs for an area
2702 * - set remaining lifetime
2703 * - set LSPs with SRMflag set for sending
2704 */
2705 int
2706 lsp_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;
2712 struct listnode *lspnode, *cnode;
2713 dnode_t *dnode, *dnode_next;
2714 int level;
2715 u_int16_t rem_lifetime;
2716
2717 lsp_list = list_new ();
2718
2719 area = THREAD_ARG (thread);
2720 assert (area);
2721 area->t_tick = NULL;
2722 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
2723
2724 /*
2725 * Build a list of LSPs with (any) SRMflag set
2726 * and removed the ones that have aged out
2727 */
2728 for (level = 0; level < ISIS_LEVELS; level++)
2729 {
2730 if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
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));
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 {
2784 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
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;
2790 for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
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);
2800 thread_add_event(master, send_lsp, circuit, 0,
2801 NULL);
2802 }
2803 }
2804 }
2805 }
2806 list_delete_all_node (lsp_list);
2807 }
2808 }
2809 }
2810
2811 list_delete (lsp_list);
2812
2813 return ISIS_OK;
2814 }
2815
2816 void
2817 lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
2818 {
2819 struct isis_lsp *lsp;
2820 u_int16_t seq_num;
2821 u_int8_t lsp_bits;
2822
2823 lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
2824 if (!lsp)
2825 return;
2826
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);
2856
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 */
2864 void
2865 lsp_purge_non_exist (int level,
2866 struct isis_link_state_hdr *lsp_hdr,
2867 struct isis_area *area)
2868 {
2869 struct isis_lsp *lsp;
2870
2871 /*
2872 * We need to create the LSP to be purged
2873 */
2874 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
2875 lsp->area = area;
2876 lsp->level = level;
2877 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
2878 lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
2879 fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
2880 : L2_LINK_STATE);
2881 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
2882 ISIS_FIXED_HDR_LEN);
2883 memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
2884 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2885
2886 /*
2887 * Set the remaining lifetime to 0
2888 */
2889 lsp->lsp_header->rem_lifetime = 0;
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
2902 /*
2903 * Put the lsp into LSPdb
2904 */
2905 lsp_insert (lsp, area->lspdb[lsp->level - 1]);
2906
2907 /*
2908 * Send in to whole area
2909 */
2910 lsp_set_all_srmflags (lsp);
2911
2912 return;
2913 }
2914
2915 void 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 }