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_outln (vty
, "%s",
828 lsp_bits2string(&lsp
->lsp_header
->lsp_bits
));
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_outln(vty
, " Metric : %-8u IS-Extended : %s",
846 GET_TE_METRIC(neigh
), lspid
);
850 vty_outln(vty
, " Metric : %-8u MT-Reach : %s %s",
851 GET_TE_METRIC(neigh
), lspid
,
852 isis_mtid2str(mtid
));
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_outln (vty
, " Metric : %-8" PRIu32
" IPv6-Internal : %s/%d",
878 ntohl (ipv6_reach
->metric
),
879 buff
, ipv6_reach
->prefix_len
);
881 vty_outln (vty
, " Metric : %-8" PRIu32
" IPv6-External : %s/%d",
882 ntohl (ipv6_reach
->metric
),
883 buff
, ipv6_reach
->prefix_len
);
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
));
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
));
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_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);
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
));
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_outln (vty
, " Area Address: %s",
959 isonet_print(area_addr
->area_addr
, area_addr
->addr_len
));
962 /* for the nlpid tlv */
963 if (lsp
->tlv_data
.nlpids
)
965 for (i
= 0; i
< lsp
->tlv_data
.nlpids
->count
; i
++)
967 switch (lsp
->tlv_data
.nlpids
->nlpids
[i
])
971 vty_outln (vty
, " NLPID : 0x%X",
972 lsp
->tlv_data
.nlpids
->nlpids
[i
]);
975 vty_outln (vty
, " NLPID : %s", "unknown");
981 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_router_info
, lnode
, mt_router_info
))
983 vty_outln (vty
, " MT : %s%s",
984 isis_mtid2str(mt_router_info
->mtid
),
985 mt_router_info
->overload
? " (overload)" : "");
988 /* for the hostname tlv */
989 if (lsp
->tlv_data
.hostname
)
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
);
997 /* authentication tlv */
998 if (lsp
->tlv_data
.auth_info
.type
!= ISIS_PASSWD_TYPE_UNUSED
)
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");
1007 if (lsp
->tlv_data
.router_id
)
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
);
1014 if (lsp
->tlv_data
.ipv4_addrs
)
1015 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_addrs
, lnode
, ipv4_addr
))
1017 memcpy (ipv4_address
, inet_ntoa (*ipv4_addr
), sizeof (ipv4_address
));
1018 vty_outln (vty
, " IPv4 Address: %s", ipv4_address
);
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
))
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
);
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
,
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
,
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
,
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
,
1059 lsp_print_mt_ipv6_reach(lsp
->tlv_data
.ipv6_reachs
, vty
,
1060 ISIS_MT_IPV4_UNICAST
);
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
);
1066 /* TE IS neighbor tlv */
1067 lsp_print_mt_reach(lsp
->tlv_data
.te_is_neighs
, vty
,
1068 dynhost
, ISIS_MT_IPV4_UNICAST
);
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
);
1075 lsp_print_mt_ipv4_reach(lsp
->tlv_data
.te_ipv4_reachs
, vty
,
1076 ISIS_MT_IPV4_UNICAST
);
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
);
1082 vty_outln (vty
, "");
1087 /* print all the lsps info in the local lspdb */
1089 lsp_print_all (struct vty
*vty
, dict_t
* lspdb
, char detail
, char dynhost
)
1092 dnode_t
*node
= dict_first (lspdb
), *next
;
1095 if (detail
== ISIS_UI_LEVEL_BRIEF
)
1097 while (node
!= NULL
)
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
);
1107 else if (detail
== ISIS_UI_LEVEL_DETAIL
)
1109 while (node
!= NULL
)
1111 next
= dict_next (lspdb
, node
);
1112 lsp_print_detail (dnode_get (node
), vty
, dynhost
);
1122 _lsp_tlv_fit (struct isis_lsp
*lsp
, struct list
**from
, struct list
**to
,
1124 unsigned int tlv_build_func (struct list
*, struct stream
*,
1128 while (*from
&& listcount(*from
))
1132 count
= tlv_build_func(*from
, lsp
->pdu
, arg
);
1134 if (listcount(*to
) != 0 || count
!= listcount(*from
))
1136 struct listnode
*node
, *nnode
;
1139 for (ALL_LIST_ELEMENTS(*from
, node
, nnode
, elem
))
1143 listnode_add (*to
, elem
);
1144 list_delete_node (*from
, node
);
1157 #define FRAG_THOLD(S,T) \
1158 ((STREAM_SIZE(S)*T)/100)
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))
1164 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1165 * variable length (TE TLVs, sub TLVs). */
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
*))
1173 /* can we fit all ? */
1174 if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, listcount (*from
) * tlvsize
+ 2))
1176 tlv_build_func (*from
, lsp
->pdu
);
1177 if (listcount (*to
) != 0)
1179 struct listnode
*node
, *nextnode
;
1182 for (ALL_LIST_ELEMENTS (*from
, node
, nextnode
, elem
))
1184 listnode_add (*to
, elem
);
1185 list_delete_node (*from
, node
);
1195 else if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, tlvsize
+ 2))
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
++)
1205 listnode_add (*to
, listgetdata (listhead (*from
)));
1206 listnode_delete (*from
, listgetdata (listhead (*from
)));
1208 tlv_build_func (*to
, lsp
->pdu
);
1210 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1215 lsp_rem_lifetime (struct isis_area
*area
, int level
)
1217 u_int16_t rem_lifetime
;
1219 /* Add jitter to configured LSP lifetime */
1220 rem_lifetime
= isis_jitter (area
->max_lsp_lifetime
[level
- 1],
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
1226 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
1227 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
1229 return rem_lifetime
;
1233 lsp_refresh_time (struct isis_lsp
*lsp
, u_int16_t rem_lifetime
)
1235 struct isis_area
*area
= lsp
->area
;
1236 int level
= lsp
->level
;
1237 u_int16_t refresh_time
;
1239 /* Add jitter to LSP refresh time */
1240 refresh_time
= isis_jitter (area
->lsp_refresh
[level
- 1],
1241 MAX_LSP_GEN_JITTER
);
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;
1249 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1250 * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
1252 return refresh_time
;
1255 static struct isis_lsp
*
1256 lsp_next_frag (u_char frag_num
, struct isis_lsp
*lsp0
, struct isis_area
*area
,
1259 struct isis_lsp
*lsp
;
1260 u_char frag_id
[ISIS_SYS_ID_LEN
+ 2];
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]);
1268 /* Clear the TLVs */
1269 lsp_clear_data (lsp
);
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
);
1277 lsp_insert (lsp
, area
->lspdb
[level
- 1]);
1278 listnode_add (lsp0
->lspu
.frags
, lsp
);
1279 lsp
->lspu
.zero_lsp
= lsp0
;
1284 lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
, struct isis_area
*area
,
1285 struct tlvs
*tlv_data
)
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
;
1294 er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
1298 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
1303 ipv4
= (struct prefix_ipv4
*)&rn
->p
;
1305 if (area
->oldmetric
)
1307 if (tlv_data
->ipv4_ext_reachs
== NULL
)
1309 tlv_data
->ipv4_ext_reachs
= list_new();
1310 tlv_data
->ipv4_ext_reachs
->del
= free_tlv
;
1312 ipreach
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*ipreach
));
1314 ipreach
->prefix
.s_addr
= ipv4
->prefix
.s_addr
;
1315 masklen2ip(ipv4
->prefixlen
, &ipreach
->mask
);
1316 ipreach
->prefix
.s_addr
&= ipreach
->mask
.s_addr
;
1318 if ((info
->metric
& 0x3f) != info
->metric
)
1319 ipreach
->metrics
.metric_default
= 0x3f;
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
);
1327 if (area
->newmetric
)
1329 if (tlv_data
->te_ipv4_reachs
== NULL
)
1331 tlv_data
->te_ipv4_reachs
= list_new();
1332 tlv_data
->te_ipv4_reachs
->del
= free_tlv
;
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
);
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
);
1349 static struct list
*
1350 tlv_get_ipv6_reach_list(struct isis_area
*area
, struct tlvs
*tlv_data
)
1352 uint16_t mtid
= isis_area_ipv6_topology(area
);
1353 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1355 if (!tlv_data
->ipv6_reachs
)
1357 tlv_data
->ipv6_reachs
= list_new();
1358 tlv_data
->ipv6_reachs
->del
= free_tlv
;
1360 return tlv_data
->ipv6_reachs
;
1363 struct tlv_mt_ipv6_reachs
*reachs
= tlvs_get_mt_ipv6_reachs(tlv_data
, mtid
);
1364 return reachs
->list
;
1368 lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
, struct isis_area
*area
,
1369 struct tlvs
*tlv_data
)
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
;
1378 er_table
= get_ext_reach(area
, AF_INET6
, lsp
->level
);
1382 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
1387 ipv6
= (struct prefix_ipv6
*)&rn
->p
;
1391 reach_list
= tlv_get_ipv6_reach_list(area
, tlv_data
);
1393 ip6reach
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ip6reach
));
1394 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1395 ip6reach
->metric
= htonl(MAX_WIDE_PATH_METRIC
);
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
);
1406 lsp_build_ext_reach (struct isis_lsp
*lsp
, struct isis_area
*area
,
1407 struct tlvs
*tlv_data
)
1409 lsp_build_ext_reach_ipv4(lsp
, area
, tlv_data
);
1410 lsp_build_ext_reach_ipv6(lsp
, area
, tlv_data
);
1414 * Builds the LSP data part. This func creates a new frag whenever
1415 * area->lsp_frag_threshold is exceeded.
1418 lsp_build (struct isis_lsp
*lsp
, struct isis_area
*area
)
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;
1437 u_char zero_id
[ISIS_SYS_ID_LEN
+ 1];
1438 int retval
= ISIS_OK
;
1441 lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area
->area_tag
, level
);
1444 * Building the zero lsp
1446 memset (zero_id
, 0, ISIS_SYS_ID_LEN
+ 1);
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
1451 stream_reset (lsp
->pdu
);
1452 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
1455 * Add the authentication info if its present
1460 * First add the tlvs related to area
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
);
1470 /* Protocols Supported */
1471 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0)
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)
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
;
1481 if (area
->ipv6_circuits
> 0)
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] =
1488 tlv_add_nlpid (lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1491 if (area_is_mt(area
))
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
;
1497 struct isis_area_mt_setting
**mt_settings
;
1498 unsigned int mt_count
;
1500 mt_settings
= area_mt_settings(area
, &mt_count
);
1501 for (unsigned int i
= 0; i
< mt_count
; i
++)
1503 struct mt_router_info
*info
;
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
));
1511 tlv_add_mt_router_info (lsp
->tlv_data
.mt_router_info
, lsp
->pdu
);
1515 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area
->area_tag
);
1517 /* Dynamic Hostname */
1518 if (area
->dynhostname
)
1520 const char *hostname
= unix_hostname();
1521 size_t hostname_len
= strlen(hostname
);
1523 lsp
->tlv_data
.hostname
= XMALLOC (MTYPE_ISIS_TLV
,
1524 sizeof (struct hostname
));
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
;
1531 lsp
->tlv_data
.hostname
->namelen
= MAX_TLV_LEN
;
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
);
1539 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area
->area_tag
);
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)
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
)
1551 lsp
->tlv_data
.ipv4_addrs
= list_new ();
1552 lsp
->tlv_data
.ipv4_addrs
->del
= free_tlv
;
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
);
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
)
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
,
1574 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area
->area_tag
);
1577 memset (&tlv_data
, 0, sizeof (struct tlvs
));
1579 lsp_debug("ISIS (%s): Adding circuit specific information.", area
->area_tag
);
1582 * Then build lists of tlvs related to circuits
1584 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, node
, circuit
))
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
);
1590 lsp_debug("ISIS (%s): Processing %s circuit %s",
1591 area
->area_tag
, circuit_type2string(circuit
->circ_type
), circuit
->interface
->name
);
1593 if (circuit
->state
!= C_STATE_UP
)
1595 lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area
->area_tag
);
1600 * Add IPv4 internal reachability of this circuit
1602 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
1603 circuit
->ip_addrs
->count
> 0)
1605 lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area
->area_tag
);
1606 if (area
->oldmetric
)
1608 if (tlv_data
.ipv4_int_reachs
== NULL
)
1610 tlv_data
.ipv4_int_reachs
= list_new ();
1611 tlv_data
.ipv4_int_reachs
->del
= free_tlv
;
1613 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
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
);
1630 if (area
->newmetric
)
1632 if (tlv_data
.te_ipv4_reachs
== NULL
)
1634 tlv_data
.te_ipv4_reachs
= list_new ();
1635 tlv_data
.te_ipv4_reachs
->del
= free_tlv
;
1637 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
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);
1644 if (area
->oldmetric
)
1645 te_ipreach
->te_metric
= htonl (circuit
->metric
[level
- 1]);
1647 te_ipreach
->te_metric
= htonl (circuit
->te_metric
[level
- 1]);
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
);
1661 * Add IPv6 reachability of this circuit
1663 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
&&
1664 circuit
->ipv6_non_link
->count
> 0)
1667 ipv6_reachs
= tlv_get_ipv6_reach_list(area
, &tlv_data
);
1669 for (ALL_LIST_ELEMENTS_RO (circuit
->ipv6_non_link
, ipnode
, ipv6
))
1672 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv6_reachability
));
1674 if (area
->oldmetric
)
1676 htonl (circuit
->metric
[level
- 1]);
1678 ip6reach
->metric
= htonl (circuit
->te_metric
[level
- 1]);
1680 ip6reach
->control_info
= 0;
1681 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1682 memcpy(&ip6prefix
, ipv6
, sizeof(ip6prefix
));
1683 apply_mask_ipv6(&ip6prefix
);
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
);
1689 memcpy (ip6reach
->prefix
, ip6prefix
.prefix
.s6_addr
,
1690 sizeof (ip6reach
->prefix
));
1691 listnode_add (ipv6_reachs
, ip6reach
);
1695 switch (circuit
->circ_type
)
1697 case CIRCUIT_T_BROADCAST
:
1698 if (level
& circuit
->is_type
)
1700 if (area
->oldmetric
)
1702 if (tlv_data
.is_neighs
== NULL
)
1704 tlv_data
.is_neighs
= list_new ();
1705 tlv_data
.is_neighs
->del
= free_tlv
;
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);
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))
1721 XFREE (MTYPE_ISIS_TLV
, is_neigh
);
1722 lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
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
));
1733 if (area
->newmetric
)
1735 if (tlv_data
.te_is_neighs
== NULL
)
1737 tlv_data
.te_is_neighs
= list_new ();
1738 tlv_data
.te_is_neighs
->del
= free_tlv
;
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);
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];
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))
1756 XFREE (MTYPE_ISIS_TLV
, te_is_neigh
);
1757 lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
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
);
1767 /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1768 te_is_neigh
->sub_tlvs_length
= 0;
1770 tlvs_add_mt_bcast(&tlv_data
, circuit
, level
, te_is_neigh
);
1771 XFREE(MTYPE_ISIS_TLV
, te_is_neigh
);
1777 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1782 nei
= circuit
->u
.p2p
.neighbor
;
1783 if (nei
&& (level
& nei
->circuit_t
))
1785 if (area
->oldmetric
)
1787 if (tlv_data
.is_neighs
== NULL
)
1789 tlv_data
.is_neighs
= list_new ();
1790 tlv_data
.is_neighs
->del
= free_tlv
;
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
));
1802 if (area
->newmetric
)
1806 if (tlv_data
.te_is_neighs
== NULL
)
1808 tlv_data
.te_is_neighs
= list_new ();
1809 tlv_data
.te_is_neighs
->del
= free_tlv
;
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() ? */
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
);
1826 /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1827 te_is_neigh
->sub_tlvs_length
= 0;
1829 tlvs_add_mt_p2p(&tlv_data
, circuit
, te_is_neigh
);
1830 XFREE(MTYPE_ISIS_TLV
, te_is_neigh
);
1835 lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1839 case CIRCUIT_T_LOOPBACK
:
1842 zlog_warn ("lsp_area_create: unknown circuit type");
1846 lsp_build_ext_reach(lsp
, area
, &tlv_data
);
1848 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area
->area_tag
);
1850 while (tlv_data
.ipv4_int_reachs
&& listcount (tlv_data
.ipv4_int_reachs
))
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,
1863 while (tlv_data
.ipv4_ext_reachs
&& listcount (tlv_data
.ipv4_ext_reachs
))
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,
1876 while (tlv_data
.te_ipv4_reachs
&& listcount (tlv_data
.te_ipv4_reachs
))
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,
1887 struct tlv_mt_ipv4_reachs
*mt_ipv4_reachs
;
1888 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv4_reachs
, node
, mt_ipv4_reachs
))
1890 while (mt_ipv4_reachs
->list
&& listcount(mt_ipv4_reachs
->list
))
1892 struct tlv_mt_ipv4_reachs
*frag_mt_ipv4_reachs
;
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,
1904 while (tlv_data
.ipv6_reachs
&& listcount (tlv_data
.ipv6_reachs
))
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,
1915 struct tlv_mt_ipv6_reachs
*mt_ipv6_reachs
;
1916 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv6_reachs
, node
, mt_ipv6_reachs
))
1918 while (mt_ipv6_reachs
->list
&& listcount(mt_ipv6_reachs
->list
))
1920 struct tlv_mt_ipv6_reachs
*frag_mt_ipv6_reachs
;
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,
1932 while (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
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
,
1940 if (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
1941 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1945 while (tlv_data
.te_is_neighs
&& listcount (tlv_data
.te_is_neighs
))
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,
1956 struct tlv_mt_neighbors
*mt_neighs
;
1957 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_is_neighs
, node
, mt_neighs
))
1959 while (mt_neighs
->list
&& listcount(mt_neighs
->list
))
1961 struct tlv_mt_neighbors
*frag_mt_neighs
;
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
,
1967 if (mt_neighs
->list
&& listcount(mt_neighs
->list
))
1968 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1974 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1976 free_tlvs (&tlv_data
);
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
);
1990 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1993 lsp_generate (struct isis_area
*area
, int level
)
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
;
2000 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2003 memset (&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2004 memcpy (&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2006 /* only builds the lsp if the area shares the level */
2007 oldlsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
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]);
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
,
2019 newlsp
->area
= area
;
2020 newlsp
->own_lsp
= 1;
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
);
2030 refresh_time
= lsp_refresh_time (newlsp
, rem_lifetime
);
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]);
2041 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2053 sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2054 area
->area_tag
, level
);
2060 * Search own LSPs, update holding time and set SRM
2063 lsp_regenerate (struct isis_area
*area
, int level
)
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
;
2071 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2074 lspdb
= area
->lspdb
[level
- 1];
2076 memset (lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2077 memcpy (lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2079 lsp
= lsp_search (lspid
, lspdb
);
2083 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2084 area
->area_tag
, level
);
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
);
2096 lsp
->last_generated
= time (NULL
);
2097 lsp_set_all_srmflags (lsp
);
2098 for (ALL_LIST_ELEMENTS_RO (lsp
->lspu
.frags
, node
, frag
))
2100 frag
->lsp_header
->lsp_bits
= lsp_bits_generate (level
,
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.
2106 frag
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
2107 lsp_set_all_srmflags (frag
);
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;
2119 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2131 sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2132 area
->area_tag
, level
);
2138 * Something has changed or periodic refresh -> regenerate LSP
2141 lsp_l1_refresh (struct thread
*thread
)
2143 struct isis_area
*area
;
2145 area
= THREAD_ARG (thread
);
2148 area
->t_lsp_refresh
[0] = NULL
;
2149 area
->lsp_regenerate_pending
[0] = 0;
2151 if ((area
->is_type
& IS_LEVEL_1
) == 0)
2154 sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area
->area_tag
);
2155 return lsp_regenerate (area
, IS_LEVEL_1
);
2159 lsp_l2_refresh (struct thread
*thread
)
2161 struct isis_area
*area
;
2163 area
= THREAD_ARG (thread
);
2166 area
->t_lsp_refresh
[1] = NULL
;
2167 area
->lsp_regenerate_pending
[1] = 0;
2169 if ((area
->is_type
& IS_LEVEL_2
) == 0)
2172 sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area
->area_tag
);
2173 return lsp_regenerate (area
, IS_LEVEL_2
);
2177 lsp_regenerate_schedule (struct isis_area
*area
, int level
, int all_pseudo
)
2179 struct isis_lsp
*lsp
;
2180 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2183 struct listnode
*cnode
;
2184 struct isis_circuit
*circuit
;
2190 sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2191 area
->area_tag
, circuit_t2string(level
), all_pseudo
? "" : "not ");
2193 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2194 LSP_PSEUDO_ID (id
) = LSP_FRAGMENT (id
) = 0;
2197 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++)
2199 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
2202 sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2203 area
->area_tag
, lvl
);
2205 if (area
->lsp_regenerate_pending
[lvl
- 1])
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);
2214 lsp
= lsp_search (id
, area
->lspdb
[lvl
- 1]);
2217 sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2223 * Throttle avoidance
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])
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
);
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.
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
);
2247 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
2248 if (lvl
== IS_LEVEL_1
)
2250 thread_add_timer_msec(master
, lsp_l1_refresh
, area
, timeout
,
2251 &area
->t_lsp_refresh
[lvl
- 1]);
2253 else if (lvl
== IS_LEVEL_2
)
2255 thread_add_timer_msec(master
, lsp_l2_refresh
, area
, timeout
,
2256 &area
->t_lsp_refresh
[lvl
- 1]);
2262 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2263 lsp_regenerate_schedule_pseudo (circuit
, level
);
2270 * Funcs for pseudonode LSPs
2274 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2277 lsp_build_pseudo (struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
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
;
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
);
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
);
2298 * add self to IS neighbours
2300 if (circuit
->area
->oldmetric
)
2302 if (lsp
->tlv_data
.is_neighs
== NULL
)
2304 lsp
->tlv_data
.is_neighs
= list_new ();
2305 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
2307 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
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
));
2315 if (circuit
->area
->newmetric
)
2317 if (lsp
->tlv_data
.te_is_neighs
== NULL
)
2319 lsp
->tlv_data
.te_is_neighs
= list_new ();
2320 lsp
->tlv_data
.te_is_neighs
->del
= free_tlv
;
2322 te_is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct te_is_neigh
));
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
));
2331 adj_list
= list_new ();
2332 isis_adj_build_up_list (circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
2334 for (ALL_LIST_ELEMENTS_RO (adj_list
, node
, adj
))
2336 if (adj
->level
& level
)
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
))
2343 /* an IS neighbour -> add it */
2344 if (circuit
->area
->oldmetric
)
2346 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
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
));
2354 if (circuit
->area
->newmetric
)
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
));
2365 else if (level
== IS_LEVEL_1
&& adj
->sys_type
== ISIS_SYSTYPE_ES
)
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
)
2371 lsp
->tlv_data
.es_neighs
= list_new ();
2372 lsp
->tlv_data
.es_neighs
->del
= free_tlv
;
2374 es_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct es_neigh
));
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
));
2383 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
2384 area
->area_tag
, sysid_print(adj
->sysid
));
2389 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
2390 area
->area_tag
, sysid_print(adj
->sysid
));
2393 list_delete (adj_list
);
2395 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area
->area_tag
);
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
);
2402 * Add the authentication info if it's present
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
);
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
);
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
);
2415 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
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);
2426 lsp_generate_pseudo (struct isis_circuit
*circuit
, int level
)
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
;
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))
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
;
2444 * If for some reason have a pseudo LSP in the db already -> regenerate
2446 if (lsp_search (lsp_id
, lspdb
))
2447 return lsp_regenerate_schedule_pseudo (circuit
, level
);
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
,
2454 lsp
->area
= circuit
->area
;
2456 lsp_build_pseudo (lsp
, circuit
, level
);
2459 lsp_insert (lsp
, lspdb
);
2460 lsp_set_all_srmflags (lsp
);
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]);
2472 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2489 lsp_regenerate_pseudo (struct isis_circuit
*circuit
, int level
)
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
;
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))
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;
2506 lsp
= lsp_search (lsp_id
, lspdb
);
2510 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2511 level
, rawlspid_print (lsp_id
));
2514 lsp_clear_data (lsp
);
2516 lsp_build_pseudo (lsp
, circuit
, level
);
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
);
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]);
2535 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
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
),
2552 * Something has changed or periodic refresh -> regenerate pseudo LSP
2555 lsp_l1_refresh_pseudo (struct thread
*thread
)
2557 struct isis_circuit
*circuit
;
2558 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2560 circuit
= THREAD_ARG (thread
);
2562 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
2563 circuit
->lsp_regenerate_pending
[0] = 0;
2565 if ((circuit
->u
.bc
.is_dr
[0] == 0) ||
2566 (circuit
->is_type
& IS_LEVEL_1
) == 0)
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
);
2575 return lsp_regenerate_pseudo (circuit
, IS_LEVEL_1
);
2579 lsp_l2_refresh_pseudo (struct thread
*thread
)
2581 struct isis_circuit
*circuit
;
2582 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2584 circuit
= THREAD_ARG (thread
);
2586 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
2587 circuit
->lsp_regenerate_pending
[1] = 0;
2589 if ((circuit
->u
.bc
.is_dr
[1] == 0) ||
2590 (circuit
->is_type
& IS_LEVEL_2
) == 0)
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
);
2599 return lsp_regenerate_pseudo (circuit
, IS_LEVEL_2
);
2603 lsp_regenerate_schedule_pseudo (struct isis_circuit
*circuit
, int level
)
2605 struct isis_lsp
*lsp
;
2606 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2610 struct isis_area
*area
= circuit
->area
;
2612 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
||
2613 circuit
->state
!= C_STATE_UP
)
2616 sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2617 area
->area_tag
, circuit_t2string(level
), circuit
->interface
->name
);
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;
2624 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++)
2626 sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2627 area
->area_tag
, lvl
);
2629 if (!((level
& lvl
) && (circuit
->is_type
& lvl
)))
2631 sched_debug("ISIS (%s): Level is not active on circuit",
2636 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0)
2638 sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
2643 if (circuit
->lsp_regenerate_pending
[lvl
- 1])
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);
2653 lsp
= lsp_search (lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
2656 sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2662 * Throttle avoidance
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])
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
);
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
);
2681 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
2683 if (lvl
== IS_LEVEL_1
)
2685 thread_add_timer_msec(master
, lsp_l1_refresh_pseudo
, circuit
,
2687 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2689 else if (lvl
== IS_LEVEL_2
)
2691 thread_add_timer_msec(master
, lsp_l2_refresh_pseudo
, circuit
,
2693 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2701 * Walk through LSPs for an area
2702 * - set remaining lifetime
2703 * - set LSPs with SRMflag set for sending
2706 lsp_tick (struct thread
*thread
)
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
;
2715 u_int16_t rem_lifetime
;
2717 lsp_list
= list_new ();
2719 area
= THREAD_ARG (thread
);
2721 area
->t_tick
= NULL
;
2722 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
2725 * Build a list of LSPs with (any) SRMflag set
2726 * and removed the ones that have aged out
2728 for (level
= 0; level
< ISIS_LEVELS
; level
++)
2730 if (area
->lspdb
[level
] && dict_count (area
->lspdb
[level
]) > 0)
2732 for (dnode
= dict_first (area
->lspdb
[level
]);
2733 dnode
!= NULL
; dnode
= dnode_next
)
2735 dnode_next
= dict_next (area
->lspdb
[level
], dnode
);
2736 lsp
= dnode_get (dnode
);
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.
2744 rem_lifetime
= ntohs(lsp
->lsp_header
->rem_lifetime
);
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.
2752 if (rem_lifetime
== 1 && lsp
->lsp_header
->seq_num
!= 0)
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); */
2764 if (lsp
->age_out
== 0)
2766 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2769 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2770 ntohl (lsp
->lsp_header
->seq_num
));
2773 dict_delete_free (area
->lspdb
[level
], dnode
);
2775 else if (flags_any_set (lsp
->SRMflags
))
2776 listnode_add (lsp_list
, lsp
);
2780 * Send LSPs on circuits indicated by the SRMflags
2782 if (listcount (lsp_list
) > 0)
2784 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2786 int diff
= time (NULL
) - circuit
->lsp_queue_last_cleared
;
2787 if (circuit
->lsp_queue
== NULL
||
2788 diff
< MIN_LSP_TRANS_INTERVAL
)
2790 for (ALL_LIST_ELEMENTS_RO (lsp_list
, lspnode
, lsp
))
2792 if (circuit
->upadjcount
[lsp
->level
- 1] &&
2793 ISIS_CHECK_FLAG (lsp
->SRMflags
, circuit
))
2795 /* Add the lsp only if it is not already in lsp
2797 if (! listnode_lookup (circuit
->lsp_queue
, lsp
))
2799 listnode_add (circuit
->lsp_queue
, lsp
);
2800 thread_add_event(master
, send_lsp
, circuit
, 0,
2806 list_delete_all_node (lsp_list
);
2811 list_delete (lsp_list
);
2817 lsp_purge_pseudo (u_char
* id
, struct isis_circuit
*circuit
, int level
)
2819 struct isis_lsp
*lsp
;
2823 lsp
= lsp_search (id
, circuit
->area
->lspdb
[level
- 1]);
2827 /* store old values */
2828 seq_num
= lsp
->lsp_header
->seq_num
;
2829 lsp_bits
= lsp
->lsp_header
->lsp_bits
;
2832 lsp_clear_data (lsp
);
2833 stream_reset (lsp
->pdu
);
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
;
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
);
2847 * Add and update the authentication info if its present
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);
2855 lsp_set_all_srmflags (lsp
);
2861 * Purge own LSP that is received and we don't have.
2862 * -> Do as in 7.3.16.4
2865 lsp_purge_non_exist (int level
,
2866 struct isis_link_state_hdr
*lsp_hdr
,
2867 struct isis_area
*area
)
2869 struct isis_lsp
*lsp
;
2872 * We need to create the LSP to be purged
2874 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
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
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
);
2887 * Set the remaining lifetime to 0
2889 lsp
->lsp_header
->rem_lifetime
= 0;
2892 * Add and update the authentication info if its present
2895 lsp_auth_update (lsp
);
2898 * Update the PDU length to header plus any authentication TLV.
2900 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
2903 * Put the lsp into LSPdb
2905 lsp_insert (lsp
, area
->lspdb
[lsp
->level
- 1]);
2908 * Send in to whole area
2910 lsp_set_all_srmflags (lsp
);
2915 void lsp_set_all_srmflags (struct isis_lsp
*lsp
)
2917 struct listnode
*node
;
2918 struct isis_circuit
*circuit
;
2922 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
2926 struct list
*circuit_list
= lsp
->area
->circuit_list
;
2927 for (ALL_LIST_ELEMENTS_RO (circuit_list
, node
, circuit
))
2929 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);