2 * IS-IS Rout(e)ing protocol - isis_lsp.c
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>
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)
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
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
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"
58 /* staticly assigned vars for printing purposes */
59 char lsp_bits_string
[200]; /* FIXME: enough ? */
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
);
67 lsp_id_cmp (u_char
* id1
, u_char
* id2
)
69 return memcmp (id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
77 dict
= dict_create (DICTCOUNT_T_MAX
, (dict_comp_t
) lsp_id_cmp
);
83 lsp_search (u_char
* id
, dict_t
* lspdb
)
90 zlog_debug ("searching db");
91 for (dn
= dict_first (lspdb
); dn
; dn
= dict_next (lspdb
, dn
))
93 zlog_debug ("%s\t%pX", rawlspid_print ((u_char
*) dnode_getkey (dn
)),
96 #endif /* EXTREME DEBUG */
98 node
= dict_lookup (lspdb
, id
);
101 return (struct isis_lsp
*) dnode_get (node
);
107 lsp_clear_data (struct isis_lsp
*lsp
)
112 if (lsp
->tlv_data
.hostname
)
113 isis_dynhn_remove (lsp
->lsp_header
->lsp_id
);
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
);
125 free_tlvs (&lsp
->tlv_data
);
129 lsp_destroy (struct isis_lsp
*lsp
)
131 struct listnode
*cnode
, *lnode
, *lnnode
;
132 struct isis_lsp
*lsp_in_list
;
133 struct isis_circuit
*circuit
;
138 if (lsp
->area
->circuit_list
) {
139 for (ALL_LIST_ELEMENTS_RO (lsp
->area
->circuit_list
, cnode
, circuit
))
141 if (circuit
->lsp_queue
== NULL
)
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
);
148 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
);
149 ISIS_FLAGS_CLEAR_ALL (lsp
->SRMflags
);
151 lsp_clear_data (lsp
);
153 if (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) == 0 && lsp
->lspu
.frags
)
155 list_delete (lsp
->lspu
.frags
);
156 lsp
->lspu
.frags
= NULL
;
159 isis_spf_schedule (lsp
->area
, lsp
->level
);
162 stream_free (lsp
->pdu
);
163 XFREE (MTYPE_ISIS_LSP
, lsp
);
167 lsp_db_destroy (dict_t
* lspdb
)
169 dnode_t
*dnode
, *next
;
170 struct isis_lsp
*lsp
;
172 dnode
= dict_first (lspdb
);
175 next
= dict_next (lspdb
, dnode
);
176 lsp
= dnode_get (dnode
);
178 dict_delete_free (lspdb
, dnode
);
188 * Remove all the frags belonging to the given lsp
191 lsp_remove_frags (struct list
*frags
, dict_t
* lspdb
)
194 struct listnode
*lnode
, *lnnode
;
195 struct isis_lsp
*lsp
;
197 for (ALL_LIST_ELEMENTS (frags
, lnode
, lnnode
, lsp
))
199 dnode
= dict_lookup (lspdb
, lsp
->lsp_header
->lsp_id
);
201 dnode_destroy (dict_delete (lspdb
, dnode
));
204 list_delete_all_node (frags
);
210 lsp_search_and_destroy (u_char
* id
, dict_t
* lspdb
)
213 struct isis_lsp
*lsp
;
215 node
= dict_lookup (lspdb
, id
);
218 node
= dict_delete (lspdb
, node
);
219 lsp
= dnode_get (node
);
221 * If this is a zero lsp, remove all the frags now
223 if (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) == 0)
226 lsp_remove_frags (lsp
->lspu
.frags
, lspdb
);
231 * else just remove this frag, from the zero lsps' frag list
233 if (lsp
->lspu
.zero_lsp
&& lsp
->lspu
.zero_lsp
->lspu
.frags
)
234 listnode_delete (lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
237 dnode_destroy (node
);
242 * Compares a LSP to given values
243 * Params are given in net order
246 lsp_compare (char *areatag
, struct isis_lsp
*lsp
, u_int32_t seq_num
,
247 u_int16_t checksum
, u_int16_t rem_lifetime
)
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)))
256 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
258 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
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",
268 ntohl (seq_num
), ntohs (checksum
), ntohs (rem_lifetime
));
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
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
)))
287 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
289 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
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",
297 ntohl (lsp
->lsp_header
->seq_num
),
298 ntohs (lsp
->lsp_header
->checksum
),
299 ntohs (lsp
->lsp_header
->rem_lifetime
));
303 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
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
));
320 lsp_auth_add (struct isis_lsp
*lsp
)
322 struct isis_passwd
*passwd
;
323 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
326 * Add the authentication info if its present
328 (lsp
->level
== IS_LEVEL_1
) ? (passwd
= &lsp
->area
->area_passwd
) :
329 (passwd
= &lsp
->area
->domain_passwd
);
330 switch (passwd
->type
)
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
);
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
,
348 tlv_add_authinfo (passwd
->type
, ISIS_AUTH_MD5_SIZE
, hmac_md5_hash
,
358 lsp_auth_update (struct isis_lsp
*lsp
)
360 struct isis_passwd
*passwd
;
361 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
362 uint16_t checksum
, rem_lifetime
;
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
)
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.
376 if (lsp
->auth_tlv_offset
== 0)
380 * RFC 5304 set auth value, checksum and remaining lifetime to zero
381 * before computation and reset to old values after computation.
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
,
399 /* Copy back the checksum and remaining lifetime */
400 lsp
->lsp_header
->checksum
= checksum
;
401 lsp
->lsp_header
->rem_lifetime
= rem_lifetime
;
405 lsp_inc_seqnum (struct isis_lsp
*lsp
, u_int32_t seq_num
)
409 if (seq_num
== 0 || ntohl (lsp
->lsp_header
->seq_num
) > seq_num
)
410 newseq
= ntohl (lsp
->lsp_header
->seq_num
) + 1;
412 newseq
= seq_num
+ 1;
414 lsp
->lsp_header
->seq_num
= htonl (newseq
);
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.
424 fletcher_checksum(STREAM_DATA (lsp
->pdu
) + 12,
425 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
427 isis_spf_schedule (lsp
->area
, lsp
->level
);
433 * Genetates checksum for LSP and its frags
436 lsp_seqnum_update (struct isis_lsp
*lsp0
)
438 struct isis_lsp
*lsp
;
439 struct listnode
*node
;
441 lsp_inc_seqnum (lsp0
, 0);
443 if (!lsp0
->lspu
.frags
)
446 for (ALL_LIST_ELEMENTS_RO (lsp0
->lspu
.frags
, node
, lsp
))
447 lsp_inc_seqnum (lsp
, 0);
453 lsp_bits_generate (int level
, int overload_bit
, int attached_bit
)
455 u_int8_t lsp_bits
= 0;
456 if (level
== IS_LEVEL_1
)
457 lsp_bits
= IS_LEVEL_1
;
459 lsp_bits
= IS_LEVEL_1_AND_2
;
461 lsp_bits
|= overload_bit
;
463 lsp_bits
|= attached_bit
;
468 lsp_update_data (struct isis_lsp
*lsp
, struct stream
*stream
,
469 struct isis_area
*area
, int level
)
471 uint32_t expected
= 0, found
;
474 /* free the old lsp data */
475 lsp_clear_data (lsp
);
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
);
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
) +
488 lsp
->age_out
= ZERO_AGE_LIFETIME
;
489 lsp
->installed
= time (NULL
);
491 * Get LSP data i.e. TLVs
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
;
501 expected
|= TLVFLAG_TE_IS_NEIGHS
;
502 expected
|= TLVFLAG_TE_IPV4_REACHABILITY
;
503 expected
|= TLVFLAG_TE_ROUTER_ID
;
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
;
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
,
518 if (retval
!= ISIS_OK
)
520 zlog_warn ("Could not parse LSP");
524 if ((found
& TLVFLAG_DYN_HOSTNAME
) && (area
->dynhostname
))
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
);
535 lsp_update (struct isis_lsp
*lsp
, struct stream
*stream
,
536 struct isis_area
*area
, int level
)
538 dnode_t
*dnode
= NULL
;
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
);
545 dnode_destroy (dict_delete (area
->lspdb
[level
- 1], dnode
));
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
));
555 /* rebuild the lsp data */
556 lsp_update_data (lsp
, stream
, area
, level
);
558 /* insert the lsp back into the database */
559 lsp_insert (lsp
, area
->lspdb
[level
- 1]);
562 /* creation of LSP directly from what we received */
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
)
568 struct isis_lsp
*lsp
;
570 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
571 lsp_update_data (lsp
, stream
, area
, level
);
576 * zero lsp -> create the list for fragments
578 lsp
->lspu
.frags
= list_new ();
583 * a fragment -> set the backpointer and add this to zero lsps frag list
585 lsp
->lspu
.zero_lsp
= lsp0
;
586 listnode_add (lsp0
->lspu
.frags
, 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
)
597 struct isis_lsp
*lsp
;
599 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
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
);
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
);
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
;
622 lsp
->age_out
= ZERO_AGE_LIFETIME
;
624 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
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
));
637 lsp_insert (struct isis_lsp
*lsp
, dict_t
* lspdb
)
639 dict_alloc_insert (lspdb
, lsp
->lsp_header
->lsp_id
, lsp
);
640 if (lsp
->lsp_header
->seq_num
!= 0)
642 isis_spf_schedule (lsp
->area
, lsp
->level
);
647 * Build a list of LSPs with non-zero ht bounded by start and stop ids
650 lsp_build_list_nonzero_ht (u_char
* start_id
, u_char
* stop_id
,
651 struct list
*list
, dict_t
* lspdb
)
653 dnode_t
*first
, *last
, *curr
;
655 first
= dict_lower_bound (lspdb
, start_id
);
659 last
= dict_upper_bound (lspdb
, stop_id
);
663 if (((struct isis_lsp
*) (curr
->dict_data
))->lsp_header
->rem_lifetime
)
664 listnode_add (list
, first
->dict_data
);
668 curr
= dict_next (lspdb
, curr
);
670 ((struct isis_lsp
*) (curr
->dict_data
))->lsp_header
->rem_lifetime
)
671 listnode_add (list
, curr
->dict_data
);
680 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
683 lsp_build_list (u_char
* start_id
, u_char
* stop_id
, u_char num_lsps
,
684 struct list
*list
, dict_t
* lspdb
)
687 dnode_t
*first
, *last
, *curr
;
689 first
= dict_lower_bound (lspdb
, start_id
);
693 last
= dict_upper_bound (lspdb
, stop_id
);
697 listnode_add (list
, first
->dict_data
);
702 curr
= dict_next (lspdb
, curr
);
705 listnode_add (list
, curr
->dict_data
);
708 if (count
== num_lsps
|| curr
== last
)
716 * Build a list of LSPs with SSN flag set for the given circuit
719 lsp_build_list_ssn (struct isis_circuit
*circuit
, u_char num_lsps
,
720 struct list
*list
, dict_t
* lspdb
)
722 dnode_t
*dnode
, *next
;
723 struct isis_lsp
*lsp
;
726 dnode
= dict_first (lspdb
);
727 while (dnode
!= NULL
)
729 next
= dict_next (lspdb
, dnode
);
730 lsp
= dnode_get (dnode
);
731 if (ISIS_CHECK_FLAG (lsp
->SSNflags
, circuit
))
733 listnode_add (list
, lsp
);
736 if (count
== num_lsps
)
745 lsp_set_time (struct isis_lsp
*lsp
)
749 if (lsp
->lsp_header
->rem_lifetime
== 0)
751 if (lsp
->age_out
> 0)
756 lsp
->lsp_header
->rem_lifetime
=
757 htons (ntohs (lsp
->lsp_header
->rem_lifetime
) - 1);
761 lspid_print (u_char
* lsp_id
, u_char
* trg
, char dynhost
, char frag
)
763 struct isis_dynhn
*dyn
= NULL
;
764 u_char id
[SYSID_STRLEN
];
767 dyn
= dynhn_find_by_id (lsp_id
);
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 ());
776 memcpy (id
, sysid_print (lsp_id
), 15);
778 sprintf ((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID (lsp_id
),
779 LSP_FRAGMENT (lsp_id
));
781 sprintf ((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID (lsp_id
));
784 /* Convert the lsp attribute bits to attribute string */
786 lsp_bits2string (u_char
* lsp_bits
)
788 char *pos
= lsp_bits_string
;
793 /* we only focus on the default metric */
794 pos
+= sprintf (pos
, "%d/",
795 ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits
) ? 1 : 0);
797 pos
+= sprintf (pos
, "%d/",
798 ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits
) ? 1 : 0);
800 pos
+= sprintf (pos
, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits
) ? 1 : 0);
804 return lsp_bits_string
;
807 /* this function prints the lsp on show isis database */
809 lsp_print (struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
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)
821 snprintf (age_out
, 8, "(%u)", lsp
->age_out
);
823 vty_out (vty
, "%7s ", age_out
);
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
);
832 lsp_print_mt_reach(struct list
*list
, struct vty
*vty
,
833 char dynhost
, uint16_t mtid
)
835 struct listnode
*node
;
836 struct te_is_neigh
*neigh
;
838 for (ALL_LIST_ELEMENTS_RO (list
, node
, neigh
))
842 lspid_print(neigh
->neigh_id
, lspid
, dynhost
, 0);
843 if (mtid
== ISIS_MT_IPV4_UNICAST
)
845 vty_out(vty
, " Metric : %-8d IS-Extended : %s%s",
846 GET_TE_METRIC(neigh
), lspid
, VTY_NEWLINE
);
850 vty_out(vty
, " Metric : %-8d MT-Reach : %s %s%s",
851 GET_TE_METRIC(neigh
), lspid
,
852 isis_mtid2str(mtid
), VTY_NEWLINE
);
854 if (IS_MPLS_TE(isisMplsTE
))
855 mpls_te_print_detail(vty
, neigh
);
860 lsp_print_mt_ipv6_reach(struct list
*list
, struct vty
*vty
, uint16_t mtid
)
862 struct listnode
*node
;
863 struct ipv6_reachability
*ipv6_reach
;
867 for (ALL_LIST_ELEMENTS_RO (list
, node
, ipv6_reach
))
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
)
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
);
881 vty_out (vty
, " Metric : %-8d IPv6-External : %s/%d%s",
882 ntohl (ipv6_reach
->metric
),
883 buff
, ipv6_reach
->prefix_len
, VTY_NEWLINE
);
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
);
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
);
903 lsp_print_mt_ipv4_reach(struct list
*list
, struct vty
*vty
, uint16_t mtid
)
905 struct listnode
*node
;
906 struct te_ipv4_reachability
*te_ipv4_reach
;
908 for (ALL_LIST_ELEMENTS_RO (list
, node
, te_ipv4_reach
))
910 if (mtid
== ISIS_MT_IPV4_UNICAST
)
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
);
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
);
933 lsp_print_detail (struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
935 struct area_addr
*area_addr
;
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
;
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];
951 lspid_print (lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
952 lsp_print (lsp
, vty
, dynhost
);
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
))
958 vty_out (vty
, " Area Address: %s%s",
959 isonet_print (area_addr
->area_addr
, area_addr
->addr_len
),
963 /* for the nlpid tlv */
964 if (lsp
->tlv_data
.nlpids
)
966 for (i
= 0; i
< lsp
->tlv_data
.nlpids
->count
; i
++)
968 switch (lsp
->tlv_data
.nlpids
->nlpids
[i
])
972 vty_out (vty
, " NLPID : 0x%X%s",
973 lsp
->tlv_data
.nlpids
->nlpids
[i
], VTY_NEWLINE
);
976 vty_out (vty
, " NLPID : %s%s", "unknown", VTY_NEWLINE
);
982 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_router_info
, lnode
, mt_router_info
))
984 vty_out (vty
, " MT : %s%s%s",
985 isis_mtid2str(mt_router_info
->mtid
),
986 mt_router_info
->overload
? " (overload)" : "",
990 /* for the hostname tlv */
991 if (lsp
->tlv_data
.hostname
)
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
);
999 /* authentication tlv */
1000 if (lsp
->tlv_data
.auth_info
.type
!= ISIS_PASSWD_TYPE_UNUSED
)
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
);
1009 if (lsp
->tlv_data
.router_id
)
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
);
1016 if (lsp
->tlv_data
.ipv4_addrs
)
1017 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_addrs
, lnode
, ipv4_addr
))
1019 memcpy (ipv4_address
, inet_ntoa (*ipv4_addr
), sizeof (ipv4_address
));
1020 vty_out (vty
, " IPv4 Address: %s%s", ipv4_address
, VTY_NEWLINE
);
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
))
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
);
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
,
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
);
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
,
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
);
1061 lsp_print_mt_ipv6_reach(lsp
->tlv_data
.ipv6_reachs
, vty
,
1062 ISIS_MT_IPV4_UNICAST
);
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
);
1068 /* TE IS neighbor tlv */
1069 lsp_print_mt_reach(lsp
->tlv_data
.te_is_neighs
, vty
,
1070 dynhost
, ISIS_MT_IPV4_UNICAST
);
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
);
1077 lsp_print_mt_ipv4_reach(lsp
->tlv_data
.te_ipv4_reachs
, vty
,
1078 ISIS_MT_IPV4_UNICAST
);
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
);
1084 vty_out (vty
, "%s", VTY_NEWLINE
);
1089 /* print all the lsps info in the local lspdb */
1091 lsp_print_all (struct vty
*vty
, dict_t
* lspdb
, char detail
, char dynhost
)
1094 dnode_t
*node
= dict_first (lspdb
), *next
;
1097 if (detail
== ISIS_UI_LEVEL_BRIEF
)
1099 while (node
!= NULL
)
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
);
1109 else if (detail
== ISIS_UI_LEVEL_DETAIL
)
1111 while (node
!= NULL
)
1113 next
= dict_next (lspdb
, node
);
1114 lsp_print_detail (dnode_get (node
), vty
, dynhost
);
1124 _lsp_tlv_fit (struct isis_lsp
*lsp
, struct list
**from
, struct list
**to
,
1126 unsigned int tlv_build_func (struct list
*, struct stream
*,
1130 while (*from
&& listcount(*from
))
1134 count
= tlv_build_func(*from
, lsp
->pdu
, arg
);
1136 if (listcount(*to
) != 0 || count
!= listcount(*from
))
1138 struct listnode
*node
, *nnode
;
1141 for (ALL_LIST_ELEMENTS(*from
, node
, nnode
, elem
))
1145 listnode_add (*to
, elem
);
1146 list_delete_node (*from
, node
);
1159 #define FRAG_THOLD(S,T) \
1160 ((STREAM_SIZE(S)*T)/100)
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))
1166 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1167 * variable length (TE TLVs, sub TLVs). */
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
*))
1175 /* can we fit all ? */
1176 if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, listcount (*from
) * tlvsize
+ 2))
1178 tlv_build_func (*from
, lsp
->pdu
);
1179 if (listcount (*to
) != 0)
1181 struct listnode
*node
, *nextnode
;
1184 for (ALL_LIST_ELEMENTS (*from
, node
, nextnode
, elem
))
1186 listnode_add (*to
, elem
);
1187 list_delete_node (*from
, node
);
1197 else if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, tlvsize
+ 2))
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
++)
1207 listnode_add (*to
, listgetdata (listhead (*from
)));
1208 listnode_delete (*from
, listgetdata (listhead (*from
)));
1210 tlv_build_func (*to
, lsp
->pdu
);
1212 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1217 lsp_rem_lifetime (struct isis_area
*area
, int level
)
1219 u_int16_t rem_lifetime
;
1221 /* Add jitter to configured LSP lifetime */
1222 rem_lifetime
= isis_jitter (area
->max_lsp_lifetime
[level
- 1],
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
1228 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
1229 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
1231 return rem_lifetime
;
1235 lsp_refresh_time (struct isis_lsp
*lsp
, u_int16_t rem_lifetime
)
1237 struct isis_area
*area
= lsp
->area
;
1238 int level
= lsp
->level
;
1239 u_int16_t refresh_time
;
1241 /* Add jitter to LSP refresh time */
1242 refresh_time
= isis_jitter (area
->lsp_refresh
[level
- 1],
1243 MAX_LSP_GEN_JITTER
);
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;
1251 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1252 * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
1254 return refresh_time
;
1257 static struct isis_lsp
*
1258 lsp_next_frag (u_char frag_num
, struct isis_lsp
*lsp0
, struct isis_area
*area
,
1261 struct isis_lsp
*lsp
;
1262 u_char frag_id
[ISIS_SYS_ID_LEN
+ 2];
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]);
1270 /* Clear the TLVs */
1271 lsp_clear_data (lsp
);
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
);
1279 lsp_insert (lsp
, area
->lspdb
[level
- 1]);
1280 listnode_add (lsp0
->lspu
.frags
, lsp
);
1281 lsp
->lspu
.zero_lsp
= lsp0
;
1286 lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
, struct isis_area
*area
,
1287 struct tlvs
*tlv_data
)
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
;
1296 er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
1300 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
1305 ipv4
= (struct prefix_ipv4
*)&rn
->p
;
1307 if (area
->oldmetric
)
1309 if (tlv_data
->ipv4_ext_reachs
== NULL
)
1311 tlv_data
->ipv4_ext_reachs
= list_new();
1312 tlv_data
->ipv4_ext_reachs
->del
= free_tlv
;
1314 ipreach
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*ipreach
));
1316 ipreach
->prefix
.s_addr
= ipv4
->prefix
.s_addr
;
1317 masklen2ip(ipv4
->prefixlen
, &ipreach
->mask
);
1318 ipreach
->prefix
.s_addr
&= ipreach
->mask
.s_addr
;
1320 if ((info
->metric
& 0x3f) != info
->metric
)
1321 ipreach
->metrics
.metric_default
= 0x3f;
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
);
1329 if (area
->newmetric
)
1331 if (tlv_data
->te_ipv4_reachs
== NULL
)
1333 tlv_data
->te_ipv4_reachs
= list_new();
1334 tlv_data
->te_ipv4_reachs
->del
= free_tlv
;
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
);
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
);
1351 static struct list
*
1352 tlv_get_ipv6_reach_list(struct isis_area
*area
, struct tlvs
*tlv_data
)
1354 uint16_t mtid
= isis_area_ipv6_topology(area
);
1355 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1357 if (!tlv_data
->ipv6_reachs
)
1359 tlv_data
->ipv6_reachs
= list_new();
1360 tlv_data
->ipv6_reachs
->del
= free_tlv
;
1362 return tlv_data
->ipv6_reachs
;
1365 struct tlv_mt_ipv6_reachs
*reachs
= tlvs_get_mt_ipv6_reachs(tlv_data
, mtid
);
1366 return reachs
->list
;
1370 lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
, struct isis_area
*area
,
1371 struct tlvs
*tlv_data
)
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
;
1380 er_table
= get_ext_reach(area
, AF_INET6
, lsp
->level
);
1384 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
1389 ipv6
= (struct prefix_ipv6
*)&rn
->p
;
1393 reach_list
= tlv_get_ipv6_reach_list(area
, tlv_data
);
1395 ip6reach
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ip6reach
));
1396 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1397 ip6reach
->metric
= htonl(MAX_WIDE_PATH_METRIC
);
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
);
1408 lsp_build_ext_reach (struct isis_lsp
*lsp
, struct isis_area
*area
,
1409 struct tlvs
*tlv_data
)
1411 lsp_build_ext_reach_ipv4(lsp
, area
, tlv_data
);
1412 lsp_build_ext_reach_ipv6(lsp
, area
, tlv_data
);
1416 * Builds the LSP data part. This func creates a new frag whenever
1417 * area->lsp_frag_threshold is exceeded.
1420 lsp_build (struct isis_lsp
*lsp
, struct isis_area
*area
)
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;
1439 u_char zero_id
[ISIS_SYS_ID_LEN
+ 1];
1440 int retval
= ISIS_OK
;
1443 lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area
->area_tag
, level
);
1446 * Building the zero lsp
1448 memset (zero_id
, 0, ISIS_SYS_ID_LEN
+ 1);
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
1453 stream_reset (lsp
->pdu
);
1454 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
1457 * Add the authentication info if its present
1462 * First add the tlvs related to area
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
);
1472 /* Protocols Supported */
1473 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0)
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)
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
;
1483 if (area
->ipv6_circuits
> 0)
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] =
1490 tlv_add_nlpid (lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1493 if (area_is_mt(area
))
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
;
1499 struct isis_area_mt_setting
**mt_settings
;
1500 unsigned int mt_count
;
1502 mt_settings
= area_mt_settings(area
, &mt_count
);
1503 for (unsigned int i
= 0; i
< mt_count
; i
++)
1505 struct mt_router_info
*info
;
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
));
1513 tlv_add_mt_router_info (lsp
->tlv_data
.mt_router_info
, lsp
->pdu
);
1517 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area
->area_tag
);
1519 /* Dynamic Hostname */
1520 if (area
->dynhostname
)
1522 const char *hostname
= unix_hostname();
1523 size_t hostname_len
= strlen(hostname
);
1525 lsp
->tlv_data
.hostname
= XMALLOC (MTYPE_ISIS_TLV
,
1526 sizeof (struct hostname
));
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
;
1533 lsp
->tlv_data
.hostname
->namelen
= MAX_TLV_LEN
;
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
);
1541 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area
->area_tag
);
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)
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
)
1553 lsp
->tlv_data
.ipv4_addrs
= list_new ();
1554 lsp
->tlv_data
.ipv4_addrs
->del
= free_tlv
;
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
);
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
)
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
,
1576 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area
->area_tag
);
1579 memset (&tlv_data
, 0, sizeof (struct tlvs
));
1581 lsp_debug("ISIS (%s): Adding circuit specific information.", area
->area_tag
);
1584 * Then build lists of tlvs related to circuits
1586 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, node
, circuit
))
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
);
1592 lsp_debug("ISIS (%s): Processing %s circuit %s",
1593 area
->area_tag
, circuit_type2string(circuit
->circ_type
), circuit
->interface
->name
);
1595 if (circuit
->state
!= C_STATE_UP
)
1597 lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area
->area_tag
);
1602 * Add IPv4 internal reachability of this circuit
1604 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
1605 circuit
->ip_addrs
->count
> 0)
1607 lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area
->area_tag
);
1608 if (area
->oldmetric
)
1610 if (tlv_data
.ipv4_int_reachs
== NULL
)
1612 tlv_data
.ipv4_int_reachs
= list_new ();
1613 tlv_data
.ipv4_int_reachs
->del
= free_tlv
;
1615 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
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
);
1632 if (area
->newmetric
)
1634 if (tlv_data
.te_ipv4_reachs
== NULL
)
1636 tlv_data
.te_ipv4_reachs
= list_new ();
1637 tlv_data
.te_ipv4_reachs
->del
= free_tlv
;
1639 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
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);
1646 if (area
->oldmetric
)
1647 te_ipreach
->te_metric
= htonl (circuit
->metric
[level
- 1]);
1649 te_ipreach
->te_metric
= htonl (circuit
->te_metric
[level
- 1]);
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
);
1663 * Add IPv6 reachability of this circuit
1665 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
&&
1666 circuit
->ipv6_non_link
->count
> 0)
1669 ipv6_reachs
= tlv_get_ipv6_reach_list(area
, &tlv_data
);
1671 for (ALL_LIST_ELEMENTS_RO (circuit
->ipv6_non_link
, ipnode
, ipv6
))
1674 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv6_reachability
));
1676 if (area
->oldmetric
)
1678 htonl (circuit
->metric
[level
- 1]);
1680 ip6reach
->metric
= htonl (circuit
->te_metric
[level
- 1]);
1682 ip6reach
->control_info
= 0;
1683 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1684 memcpy(&ip6prefix
, ipv6
, sizeof(ip6prefix
));
1685 apply_mask_ipv6(&ip6prefix
);
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
);
1691 memcpy (ip6reach
->prefix
, ip6prefix
.prefix
.s6_addr
,
1692 sizeof (ip6reach
->prefix
));
1693 listnode_add (ipv6_reachs
, ip6reach
);
1697 switch (circuit
->circ_type
)
1699 case CIRCUIT_T_BROADCAST
:
1700 if (level
& circuit
->is_type
)
1702 if (area
->oldmetric
)
1704 if (tlv_data
.is_neighs
== NULL
)
1706 tlv_data
.is_neighs
= list_new ();
1707 tlv_data
.is_neighs
->del
= free_tlv
;
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);
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))
1723 XFREE (MTYPE_ISIS_TLV
, is_neigh
);
1724 lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
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
));
1735 if (area
->newmetric
)
1737 if (tlv_data
.te_is_neighs
== NULL
)
1739 tlv_data
.te_is_neighs
= list_new ();
1740 tlv_data
.te_is_neighs
->del
= free_tlv
;
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);
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];
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))
1758 XFREE (MTYPE_ISIS_TLV
, te_is_neigh
);
1759 lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
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
);
1769 /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1770 te_is_neigh
->sub_tlvs_length
= 0;
1772 tlvs_add_mt_bcast(&tlv_data
, circuit
, level
, te_is_neigh
);
1773 XFREE(MTYPE_ISIS_TLV
, te_is_neigh
);
1779 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1784 nei
= circuit
->u
.p2p
.neighbor
;
1785 if (nei
&& (level
& nei
->circuit_t
))
1787 if (area
->oldmetric
)
1789 if (tlv_data
.is_neighs
== NULL
)
1791 tlv_data
.is_neighs
= list_new ();
1792 tlv_data
.is_neighs
->del
= free_tlv
;
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
));
1804 if (area
->newmetric
)
1808 if (tlv_data
.te_is_neighs
== NULL
)
1810 tlv_data
.te_is_neighs
= list_new ();
1811 tlv_data
.te_is_neighs
->del
= free_tlv
;
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() ? */
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
);
1828 /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1829 te_is_neigh
->sub_tlvs_length
= 0;
1831 tlvs_add_mt_p2p(&tlv_data
, circuit
, te_is_neigh
);
1832 XFREE(MTYPE_ISIS_TLV
, te_is_neigh
);
1837 lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1841 case CIRCUIT_T_LOOPBACK
:
1844 zlog_warn ("lsp_area_create: unknown circuit type");
1848 lsp_build_ext_reach(lsp
, area
, &tlv_data
);
1850 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area
->area_tag
);
1852 while (tlv_data
.ipv4_int_reachs
&& listcount (tlv_data
.ipv4_int_reachs
))
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,
1865 while (tlv_data
.ipv4_ext_reachs
&& listcount (tlv_data
.ipv4_ext_reachs
))
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,
1878 while (tlv_data
.te_ipv4_reachs
&& listcount (tlv_data
.te_ipv4_reachs
))
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,
1889 struct tlv_mt_ipv4_reachs
*mt_ipv4_reachs
;
1890 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv4_reachs
, node
, mt_ipv4_reachs
))
1892 while (mt_ipv4_reachs
->list
&& listcount(mt_ipv4_reachs
->list
))
1894 struct tlv_mt_ipv4_reachs
*frag_mt_ipv4_reachs
;
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,
1906 while (tlv_data
.ipv6_reachs
&& listcount (tlv_data
.ipv6_reachs
))
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,
1917 struct tlv_mt_ipv6_reachs
*mt_ipv6_reachs
;
1918 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv6_reachs
, node
, mt_ipv6_reachs
))
1920 while (mt_ipv6_reachs
->list
&& listcount(mt_ipv6_reachs
->list
))
1922 struct tlv_mt_ipv6_reachs
*frag_mt_ipv6_reachs
;
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,
1934 while (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
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
,
1942 if (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
1943 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1947 while (tlv_data
.te_is_neighs
&& listcount (tlv_data
.te_is_neighs
))
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,
1958 struct tlv_mt_neighbors
*mt_neighs
;
1959 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_is_neighs
, node
, mt_neighs
))
1961 while (mt_neighs
->list
&& listcount(mt_neighs
->list
))
1963 struct tlv_mt_neighbors
*frag_mt_neighs
;
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
,
1969 if (mt_neighs
->list
&& listcount(mt_neighs
->list
))
1970 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1976 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1978 free_tlvs (&tlv_data
);
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
);
1992 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1995 lsp_generate (struct isis_area
*area
, int level
)
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
;
2002 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2005 memset (&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2006 memcpy (&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2008 /* only builds the lsp if the area shares the level */
2009 oldlsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
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]);
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
,
2021 newlsp
->area
= area
;
2022 newlsp
->own_lsp
= 1;
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
);
2032 refresh_time
= lsp_refresh_time (newlsp
, rem_lifetime
);
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]);
2043 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2055 sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2056 area
->area_tag
, level
);
2062 * Search own LSPs, update holding time and set SRM
2065 lsp_regenerate (struct isis_area
*area
, int level
)
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
;
2073 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2076 lspdb
= area
->lspdb
[level
- 1];
2078 memset (lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2079 memcpy (lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2081 lsp
= lsp_search (lspid
, lspdb
);
2085 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2086 area
->area_tag
, level
);
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
);
2098 lsp
->last_generated
= time (NULL
);
2099 lsp_set_all_srmflags (lsp
);
2100 for (ALL_LIST_ELEMENTS_RO (lsp
->lspu
.frags
, node
, frag
))
2102 frag
->lsp_header
->lsp_bits
= lsp_bits_generate (level
,
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.
2108 frag
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
2109 lsp_set_all_srmflags (frag
);
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;
2121 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2133 sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2134 area
->area_tag
, level
);
2140 * Something has changed or periodic refresh -> regenerate LSP
2143 lsp_l1_refresh (struct thread
*thread
)
2145 struct isis_area
*area
;
2147 area
= THREAD_ARG (thread
);
2150 area
->t_lsp_refresh
[0] = NULL
;
2151 area
->lsp_regenerate_pending
[0] = 0;
2153 if ((area
->is_type
& IS_LEVEL_1
) == 0)
2156 sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area
->area_tag
);
2157 return lsp_regenerate (area
, IS_LEVEL_1
);
2161 lsp_l2_refresh (struct thread
*thread
)
2163 struct isis_area
*area
;
2165 area
= THREAD_ARG (thread
);
2168 area
->t_lsp_refresh
[1] = NULL
;
2169 area
->lsp_regenerate_pending
[1] = 0;
2171 if ((area
->is_type
& IS_LEVEL_2
) == 0)
2174 sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area
->area_tag
);
2175 return lsp_regenerate (area
, IS_LEVEL_2
);
2179 lsp_regenerate_schedule (struct isis_area
*area
, int level
, int all_pseudo
)
2181 struct isis_lsp
*lsp
;
2182 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2185 struct listnode
*cnode
;
2186 struct isis_circuit
*circuit
;
2192 sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2193 area
->area_tag
, circuit_t2string(level
), all_pseudo
? "" : "not ");
2195 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2196 LSP_PSEUDO_ID (id
) = LSP_FRAGMENT (id
) = 0;
2199 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++)
2201 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
2204 sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2205 area
->area_tag
, lvl
);
2207 if (area
->lsp_regenerate_pending
[lvl
- 1])
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);
2216 lsp
= lsp_search (id
, area
->lspdb
[lvl
- 1]);
2219 sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2225 * Throttle avoidance
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])
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
);
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.
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
);
2249 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
2250 if (lvl
== IS_LEVEL_1
)
2252 thread_add_timer_msec(master
, lsp_l1_refresh
, area
, timeout
,
2253 &area
->t_lsp_refresh
[lvl
- 1]);
2255 else if (lvl
== IS_LEVEL_2
)
2257 thread_add_timer_msec(master
, lsp_l2_refresh
, area
, timeout
,
2258 &area
->t_lsp_refresh
[lvl
- 1]);
2264 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2265 lsp_regenerate_schedule_pseudo (circuit
, level
);
2272 * Funcs for pseudonode LSPs
2276 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2279 lsp_build_pseudo (struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
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
;
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
);
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
);
2300 * add self to IS neighbours
2302 if (circuit
->area
->oldmetric
)
2304 if (lsp
->tlv_data
.is_neighs
== NULL
)
2306 lsp
->tlv_data
.is_neighs
= list_new ();
2307 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
2309 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
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
));
2317 if (circuit
->area
->newmetric
)
2319 if (lsp
->tlv_data
.te_is_neighs
== NULL
)
2321 lsp
->tlv_data
.te_is_neighs
= list_new ();
2322 lsp
->tlv_data
.te_is_neighs
->del
= free_tlv
;
2324 te_is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct te_is_neigh
));
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
));
2333 adj_list
= list_new ();
2334 isis_adj_build_up_list (circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
2336 for (ALL_LIST_ELEMENTS_RO (adj_list
, node
, adj
))
2338 if (adj
->level
& level
)
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
))
2345 /* an IS neighbour -> add it */
2346 if (circuit
->area
->oldmetric
)
2348 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
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
));
2356 if (circuit
->area
->newmetric
)
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
));
2367 else if (level
== IS_LEVEL_1
&& adj
->sys_type
== ISIS_SYSTYPE_ES
)
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
)
2373 lsp
->tlv_data
.es_neighs
= list_new ();
2374 lsp
->tlv_data
.es_neighs
->del
= free_tlv
;
2376 es_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct es_neigh
));
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
));
2385 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
2386 area
->area_tag
, sysid_print(adj
->sysid
));
2391 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
2392 area
->area_tag
, sysid_print(adj
->sysid
));
2395 list_delete (adj_list
);
2397 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area
->area_tag
);
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
);
2404 * Add the authentication info if it's present
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
);
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
);
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
);
2417 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
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);
2428 lsp_generate_pseudo (struct isis_circuit
*circuit
, int level
)
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
;
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))
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
;
2446 * If for some reason have a pseudo LSP in the db already -> regenerate
2448 if (lsp_search (lsp_id
, lspdb
))
2449 return lsp_regenerate_schedule_pseudo (circuit
, level
);
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
,
2456 lsp
->area
= circuit
->area
;
2458 lsp_build_pseudo (lsp
, circuit
, level
);
2461 lsp_insert (lsp
, lspdb
);
2462 lsp_set_all_srmflags (lsp
);
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]);
2474 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2491 lsp_regenerate_pseudo (struct isis_circuit
*circuit
, int level
)
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
;
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))
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;
2508 lsp
= lsp_search (lsp_id
, lspdb
);
2512 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2513 level
, rawlspid_print (lsp_id
));
2516 lsp_clear_data (lsp
);
2518 lsp_build_pseudo (lsp
, circuit
, level
);
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
);
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]);
2537 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2554 * Something has changed or periodic refresh -> regenerate pseudo LSP
2557 lsp_l1_refresh_pseudo (struct thread
*thread
)
2559 struct isis_circuit
*circuit
;
2560 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2562 circuit
= THREAD_ARG (thread
);
2564 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
2565 circuit
->lsp_regenerate_pending
[0] = 0;
2567 if ((circuit
->u
.bc
.is_dr
[0] == 0) ||
2568 (circuit
->is_type
& IS_LEVEL_1
) == 0)
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
);
2577 return lsp_regenerate_pseudo (circuit
, IS_LEVEL_1
);
2581 lsp_l2_refresh_pseudo (struct thread
*thread
)
2583 struct isis_circuit
*circuit
;
2584 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2586 circuit
= THREAD_ARG (thread
);
2588 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
2589 circuit
->lsp_regenerate_pending
[1] = 0;
2591 if ((circuit
->u
.bc
.is_dr
[1] == 0) ||
2592 (circuit
->is_type
& IS_LEVEL_2
) == 0)
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
);
2601 return lsp_regenerate_pseudo (circuit
, IS_LEVEL_2
);
2605 lsp_regenerate_schedule_pseudo (struct isis_circuit
*circuit
, int level
)
2607 struct isis_lsp
*lsp
;
2608 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2612 struct isis_area
*area
= circuit
->area
;
2614 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
||
2615 circuit
->state
!= C_STATE_UP
)
2618 sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2619 area
->area_tag
, circuit_t2string(level
), circuit
->interface
->name
);
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;
2626 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++)
2628 sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2629 area
->area_tag
, lvl
);
2631 if (!((level
& lvl
) && (circuit
->is_type
& lvl
)))
2633 sched_debug("ISIS (%s): Level is not active on circuit",
2638 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0)
2640 sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
2645 if (circuit
->lsp_regenerate_pending
[lvl
- 1])
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);
2655 lsp
= lsp_search (lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
2658 sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2664 * Throttle avoidance
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])
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
);
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
);
2683 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
2685 if (lvl
== IS_LEVEL_1
)
2687 thread_add_timer_msec(master
, lsp_l1_refresh_pseudo
, circuit
,
2689 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2691 else if (lvl
== IS_LEVEL_2
)
2693 thread_add_timer_msec(master
, lsp_l2_refresh_pseudo
, circuit
,
2695 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2703 * Walk through LSPs for an area
2704 * - set remaining lifetime
2705 * - set LSPs with SRMflag set for sending
2708 lsp_tick (struct thread
*thread
)
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
;
2717 u_int16_t rem_lifetime
;
2719 lsp_list
= list_new ();
2721 area
= THREAD_ARG (thread
);
2723 area
->t_tick
= NULL
;
2724 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
2727 * Build a list of LSPs with (any) SRMflag set
2728 * and removed the ones that have aged out
2730 for (level
= 0; level
< ISIS_LEVELS
; level
++)
2732 if (area
->lspdb
[level
] && dict_count (area
->lspdb
[level
]) > 0)
2734 for (dnode
= dict_first (area
->lspdb
[level
]);
2735 dnode
!= NULL
; dnode
= dnode_next
)
2737 dnode_next
= dict_next (area
->lspdb
[level
], dnode
);
2738 lsp
= dnode_get (dnode
);
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.
2746 rem_lifetime
= ntohs(lsp
->lsp_header
->rem_lifetime
);
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.
2754 if (rem_lifetime
== 1 && lsp
->lsp_header
->seq_num
!= 0)
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); */
2766 if (lsp
->age_out
== 0)
2768 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2771 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2772 ntohl (lsp
->lsp_header
->seq_num
));
2775 dict_delete_free (area
->lspdb
[level
], dnode
);
2777 else if (flags_any_set (lsp
->SRMflags
))
2778 listnode_add (lsp_list
, lsp
);
2782 * Send LSPs on circuits indicated by the SRMflags
2784 if (listcount (lsp_list
) > 0)
2786 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2788 int diff
= time (NULL
) - circuit
->lsp_queue_last_cleared
;
2789 if (circuit
->lsp_queue
== NULL
||
2790 diff
< MIN_LSP_TRANS_INTERVAL
)
2792 for (ALL_LIST_ELEMENTS_RO (lsp_list
, lspnode
, lsp
))
2794 if (circuit
->upadjcount
[lsp
->level
- 1] &&
2795 ISIS_CHECK_FLAG (lsp
->SRMflags
, circuit
))
2797 /* Add the lsp only if it is not already in lsp
2799 if (! listnode_lookup (circuit
->lsp_queue
, lsp
))
2801 listnode_add (circuit
->lsp_queue
, lsp
);
2802 thread_add_event(master
, send_lsp
, circuit
, 0,
2808 list_delete_all_node (lsp_list
);
2813 list_delete (lsp_list
);
2819 lsp_purge_pseudo (u_char
* id
, struct isis_circuit
*circuit
, int level
)
2821 struct isis_lsp
*lsp
;
2825 lsp
= lsp_search (id
, circuit
->area
->lspdb
[level
- 1]);
2829 /* store old values */
2830 seq_num
= lsp
->lsp_header
->seq_num
;
2831 lsp_bits
= lsp
->lsp_header
->lsp_bits
;
2834 lsp_clear_data (lsp
);
2835 stream_reset (lsp
->pdu
);
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
;
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
);
2849 * Add and update the authentication info if its present
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);
2857 lsp_set_all_srmflags (lsp
);
2863 * Purge own LSP that is received and we don't have.
2864 * -> Do as in 7.3.16.4
2867 lsp_purge_non_exist (int level
,
2868 struct isis_link_state_hdr
*lsp_hdr
,
2869 struct isis_area
*area
)
2871 struct isis_lsp
*lsp
;
2874 * We need to create the LSP to be purged
2876 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
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
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
);
2889 * Set the remaining lifetime to 0
2891 lsp
->lsp_header
->rem_lifetime
= 0;
2894 * Add and update the authentication info if its present
2897 lsp_auth_update (lsp
);
2900 * Update the PDU length to header plus any authentication TLV.
2902 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
2905 * Put the lsp into LSPdb
2907 lsp_insert (lsp
, area
->lspdb
[lsp
->level
- 1]);
2910 * Send in to whole area
2912 lsp_set_all_srmflags (lsp
);
2917 void lsp_set_all_srmflags (struct isis_lsp
*lsp
)
2919 struct listnode
*node
;
2920 struct isis_circuit
*circuit
;
2924 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
2928 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2929 for (ALL_LIST_ELEMENTS_RO (circuit_list
, node
, circuit
))
2931 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);