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
);
66 int lsp_id_cmp(u_char
*id1
, u_char
*id2
)
68 return memcmp(id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
71 dict_t
*lsp_db_init(void)
75 dict
= dict_create(DICTCOUNT_T_MAX
, (dict_comp_t
)lsp_id_cmp
);
80 struct isis_lsp
*lsp_search(u_char
*id
, dict_t
*lspdb
)
87 zlog_debug("searching db");
88 for (dn
= dict_first(lspdb
); dn
; dn
= dict_next(lspdb
, dn
)) {
90 rawlspid_print((u_char
*)dnode_getkey(dn
)),
93 #endif /* EXTREME DEBUG */
95 node
= dict_lookup(lspdb
, id
);
98 return (struct isis_lsp
*)dnode_get(node
);
103 static void lsp_clear_data(struct isis_lsp
*lsp
)
108 if (lsp
->tlv_data
.hostname
)
109 isis_dynhn_remove(lsp
->lsp_header
->lsp_id
);
112 if (lsp
->tlv_data
.nlpids
)
113 XFREE(MTYPE_ISIS_TLV
, lsp
->tlv_data
.nlpids
);
114 if (lsp
->tlv_data
.hostname
)
115 XFREE(MTYPE_ISIS_TLV
, lsp
->tlv_data
.hostname
);
116 if (lsp
->tlv_data
.router_id
)
117 XFREE(MTYPE_ISIS_TLV
, lsp
->tlv_data
.router_id
);
120 free_tlvs(&lsp
->tlv_data
);
123 static void lsp_destroy(struct isis_lsp
*lsp
)
125 struct listnode
*cnode
, *lnode
, *lnnode
;
126 struct isis_lsp
*lsp_in_list
;
127 struct isis_circuit
*circuit
;
132 if (lsp
->area
->circuit_list
) {
133 for (ALL_LIST_ELEMENTS_RO(lsp
->area
->circuit_list
, cnode
,
135 if (circuit
->lsp_queue
== NULL
)
137 for (ALL_LIST_ELEMENTS(circuit
->lsp_queue
, lnode
,
138 lnnode
, lsp_in_list
))
139 if (lsp_in_list
== lsp
)
140 list_delete_node(circuit
->lsp_queue
,
144 ISIS_FLAGS_CLEAR_ALL(lsp
->SSNflags
);
145 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
149 if (LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) == 0 && lsp
->lspu
.frags
) {
150 list_delete(lsp
->lspu
.frags
);
151 lsp
->lspu
.frags
= NULL
;
154 isis_spf_schedule(lsp
->area
, lsp
->level
);
157 stream_free(lsp
->pdu
);
158 XFREE(MTYPE_ISIS_LSP
, lsp
);
161 void lsp_db_destroy(dict_t
*lspdb
)
163 dnode_t
*dnode
, *next
;
164 struct isis_lsp
*lsp
;
166 dnode
= dict_first(lspdb
);
168 next
= dict_next(lspdb
, dnode
);
169 lsp
= dnode_get(dnode
);
171 dict_delete_free(lspdb
, dnode
);
181 * Remove all the frags belonging to the given lsp
183 static void lsp_remove_frags(struct list
*frags
, dict_t
*lspdb
)
186 struct listnode
*lnode
, *lnnode
;
187 struct isis_lsp
*lsp
;
189 for (ALL_LIST_ELEMENTS(frags
, lnode
, lnnode
, lsp
)) {
190 dnode
= dict_lookup(lspdb
, lsp
->lsp_header
->lsp_id
);
192 dnode_destroy(dict_delete(lspdb
, dnode
));
195 list_delete_all_node(frags
);
200 void lsp_search_and_destroy(u_char
*id
, dict_t
*lspdb
)
203 struct isis_lsp
*lsp
;
205 node
= dict_lookup(lspdb
, id
);
207 node
= dict_delete(lspdb
, node
);
208 lsp
= dnode_get(node
);
210 * If this is a zero lsp, remove all the frags now
212 if (LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) == 0) {
214 lsp_remove_frags(lsp
->lspu
.frags
, lspdb
);
217 * else just remove this frag, from the zero lsps' frag
220 if (lsp
->lspu
.zero_lsp
221 && lsp
->lspu
.zero_lsp
->lspu
.frags
)
222 listnode_delete(lsp
->lspu
.zero_lsp
->lspu
.frags
,
231 * Compares a LSP to given values
232 * Params are given in net order
234 int lsp_compare(char *areatag
, struct isis_lsp
*lsp
, u_int32_t seq_num
,
235 u_int16_t checksum
, u_int16_t rem_lifetime
)
237 /* no point in double ntohl on seqnum */
238 if (lsp
->lsp_header
->seq_num
== seq_num
239 && lsp
->lsp_header
->checksum
== checksum
&&
240 /*comparing with 0, no need to do ntohl */
241 ((lsp
->lsp_header
->rem_lifetime
== 0 && rem_lifetime
== 0)
242 || (lsp
->lsp_header
->rem_lifetime
!= 0 && rem_lifetime
!= 0))) {
243 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
245 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
248 rawlspid_print(lsp
->lsp_header
->lsp_id
),
249 ntohl(lsp
->lsp_header
->seq_num
),
250 ntohs(lsp
->lsp_header
->checksum
),
251 ntohs(lsp
->lsp_header
->rem_lifetime
));
253 "ISIS-Snp (%s): is equal to ours seq 0x%08x,"
254 " cksum 0x%04x, lifetime %us",
255 areatag
, ntohl(seq_num
), ntohs(checksum
),
256 ntohs(rem_lifetime
));
262 * LSPs with identical checksums should only be treated as newer if:
263 * a) The current LSP has a remaining lifetime != 0 and the other LSP
265 * remaining lifetime == 0. In this case, we should participate in
267 * and should not treat the current LSP with remaining lifetime == 0
269 * b) The LSP has an incorrect checksum. In this case, we need to react
273 if (ntohl(seq_num
) > ntohl(lsp
->lsp_header
->seq_num
)
274 || (ntohl(seq_num
) == ntohl(lsp
->lsp_header
->seq_num
)
275 && ((lsp
->lsp_header
->rem_lifetime
!= 0 && rem_lifetime
== 0)
276 || lsp
->lsp_header
->checksum
!= checksum
))) {
277 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
279 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
282 rawlspid_print(lsp
->lsp_header
->lsp_id
),
283 ntohl(seq_num
), ntohs(checksum
),
284 ntohs(rem_lifetime
));
286 "ISIS-Snp (%s): is newer than ours seq 0x%08x, "
287 "cksum 0x%04x, lifetime %us",
288 areatag
, ntohl(lsp
->lsp_header
->seq_num
),
289 ntohs(lsp
->lsp_header
->checksum
),
290 ntohs(lsp
->lsp_header
->rem_lifetime
));
294 if (isis
->debugs
& DEBUG_SNP_PACKETS
) {
296 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
297 areatag
, rawlspid_print(lsp
->lsp_header
->lsp_id
),
298 ntohl(seq_num
), ntohs(checksum
), ntohs(rem_lifetime
));
300 "ISIS-Snp (%s): is older than ours seq 0x%08x,"
301 " cksum 0x%04x, lifetime %us",
302 areatag
, ntohl(lsp
->lsp_header
->seq_num
),
303 ntohs(lsp
->lsp_header
->checksum
),
304 ntohs(lsp
->lsp_header
->rem_lifetime
));
310 static void lsp_auth_add(struct isis_lsp
*lsp
)
312 struct isis_passwd
*passwd
;
313 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
316 * Add the authentication info if its present
318 (lsp
->level
== IS_LEVEL_1
) ? (passwd
= &lsp
->area
->area_passwd
)
319 : (passwd
= &lsp
->area
->domain_passwd
);
320 switch (passwd
->type
) {
322 case ISIS_PASSWD_TYPE_CLEARTXT
:
323 memcpy(&lsp
->tlv_data
.auth_info
, passwd
,
324 sizeof(struct isis_passwd
));
325 tlv_add_authinfo(passwd
->type
, passwd
->len
, passwd
->passwd
,
330 case ISIS_PASSWD_TYPE_HMAC_MD5
:
331 /* Remember where TLV is written so we can later
332 * overwrite the MD5 hash */
333 lsp
->auth_tlv_offset
= stream_get_endp(lsp
->pdu
);
334 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
335 lsp
->tlv_data
.auth_info
.type
= ISIS_PASSWD_TYPE_HMAC_MD5
;
336 lsp
->tlv_data
.auth_info
.len
= ISIS_AUTH_MD5_SIZE
;
337 memcpy(&lsp
->tlv_data
.auth_info
.passwd
, hmac_md5_hash
,
339 tlv_add_authinfo(passwd
->type
, ISIS_AUTH_MD5_SIZE
,
340 hmac_md5_hash
, lsp
->pdu
);
348 static void lsp_auth_update(struct isis_lsp
*lsp
)
350 struct isis_passwd
*passwd
;
351 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
352 uint16_t checksum
, rem_lifetime
;
354 /* For HMAC MD5 we need to recompute the md5 hash and store it */
355 (lsp
->level
== IS_LEVEL_1
) ? (passwd
= &lsp
->area
->area_passwd
)
356 : (passwd
= &lsp
->area
->domain_passwd
);
357 if (passwd
->type
!= ISIS_PASSWD_TYPE_HMAC_MD5
)
361 * In transient conditions (when net is configured where authentication
362 * config and lsp regenerate schedule is not yet run), there could be
363 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
364 * return, when lsp_regenerate is run, lsp will have auth tlv.
366 if (lsp
->auth_tlv_offset
== 0)
370 * RFC 5304 set auth value, checksum and remaining lifetime to zero
371 * before computation and reset to old values after computation.
373 checksum
= lsp
->lsp_header
->checksum
;
374 rem_lifetime
= lsp
->lsp_header
->rem_lifetime
;
375 lsp
->lsp_header
->checksum
= 0;
376 lsp
->lsp_header
->rem_lifetime
= 0;
377 /* Set the authentication value as well to zero */
378 memset(STREAM_DATA(lsp
->pdu
) + lsp
->auth_tlv_offset
+ 3, 0,
380 /* Compute autentication value */
381 hmac_md5(STREAM_DATA(lsp
->pdu
), stream_get_endp(lsp
->pdu
),
382 (unsigned char *)&passwd
->passwd
, passwd
->len
,
383 (unsigned char *)&hmac_md5_hash
);
384 /* Copy the hash into the stream */
385 memcpy(STREAM_DATA(lsp
->pdu
) + lsp
->auth_tlv_offset
+ 3, hmac_md5_hash
,
387 memcpy(&lsp
->tlv_data
.auth_info
.passwd
, hmac_md5_hash
,
389 /* Copy back the checksum and remaining lifetime */
390 lsp
->lsp_header
->checksum
= checksum
;
391 lsp
->lsp_header
->rem_lifetime
= rem_lifetime
;
394 void lsp_inc_seqnum(struct isis_lsp
*lsp
, u_int32_t seq_num
)
398 if (seq_num
== 0 || ntohl(lsp
->lsp_header
->seq_num
) > seq_num
)
399 newseq
= ntohl(lsp
->lsp_header
->seq_num
) + 1;
401 newseq
= seq_num
+ 1;
403 lsp
->lsp_header
->seq_num
= htonl(newseq
);
405 /* Recompute authentication and checksum information */
406 lsp_auth_update(lsp
);
407 /* ISO 10589 - 7.3.11 Generation of the checksum
408 * The checksum shall be computed over all fields in the LSP which
410 * after the Remaining Lifetime field. This field (and those appearing
411 * before it) are excluded so that the LSP may be aged by systems
413 * requiring recomputation.
415 fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
416 ntohs(lsp
->lsp_header
->pdu_len
) - 12, 12);
418 isis_spf_schedule(lsp
->area
, lsp
->level
);
424 * Genetates checksum for LSP and its frags
426 static void lsp_seqnum_update(struct isis_lsp
*lsp0
)
428 struct isis_lsp
*lsp
;
429 struct listnode
*node
;
431 lsp_inc_seqnum(lsp0
, 0);
433 if (!lsp0
->lspu
.frags
)
436 for (ALL_LIST_ELEMENTS_RO(lsp0
->lspu
.frags
, node
, lsp
))
437 lsp_inc_seqnum(lsp
, 0);
442 static u_int8_t
lsp_bits_generate(int level
, int overload_bit
, int attached_bit
)
444 u_int8_t lsp_bits
= 0;
445 if (level
== IS_LEVEL_1
)
446 lsp_bits
= IS_LEVEL_1
;
448 lsp_bits
= IS_LEVEL_1_AND_2
;
450 lsp_bits
|= overload_bit
;
452 lsp_bits
|= attached_bit
;
456 static void lsp_update_data(struct isis_lsp
*lsp
, struct stream
*stream
,
457 struct isis_area
*area
, int level
)
459 uint32_t expected
= 0, found
;
462 /* free the old lsp data */
465 /* copying only the relevant part of our stream */
466 if (lsp
->pdu
!= NULL
)
467 stream_free(lsp
->pdu
);
468 lsp
->pdu
= stream_dup(stream
);
470 /* setting pointers to the correct place */
471 lsp
->lsp_header
= (struct isis_link_state_hdr
*)(STREAM_DATA(lsp
->pdu
)
472 + ISIS_FIXED_HDR_LEN
);
475 lsp
->age_out
= ZERO_AGE_LIFETIME
;
476 lsp
->installed
= time(NULL
);
478 * Get LSP data i.e. TLVs
480 expected
|= TLVFLAG_AUTH_INFO
;
481 expected
|= TLVFLAG_AREA_ADDRS
;
482 expected
|= TLVFLAG_IS_NEIGHS
;
483 expected
|= TLVFLAG_NLPID
;
484 if (area
->dynhostname
)
485 expected
|= TLVFLAG_DYN_HOSTNAME
;
486 if (area
->newmetric
) {
487 expected
|= TLVFLAG_TE_IS_NEIGHS
;
488 expected
|= TLVFLAG_TE_IPV4_REACHABILITY
;
489 expected
|= TLVFLAG_TE_ROUTER_ID
;
491 expected
|= TLVFLAG_MT_ROUTER_INFORMATION
;
492 expected
|= TLVFLAG_IPV4_ADDR
;
493 expected
|= TLVFLAG_IPV4_INT_REACHABILITY
;
494 expected
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
495 expected
|= TLVFLAG_IPV6_ADDR
;
496 expected
|= TLVFLAG_IPV6_REACHABILITY
;
498 retval
= parse_tlvs(area
->area_tag
,
499 STREAM_DATA(lsp
->pdu
) + ISIS_FIXED_HDR_LEN
501 ntohs(lsp
->lsp_header
->pdu_len
) - ISIS_FIXED_HDR_LEN
503 &expected
, &found
, &lsp
->tlv_data
, NULL
);
504 if (retval
!= ISIS_OK
) {
505 zlog_warn("Could not parse LSP");
509 if ((found
& TLVFLAG_DYN_HOSTNAME
) && (area
->dynhostname
)) {
510 isis_dynhn_insert(lsp
->lsp_header
->lsp_id
,
511 lsp
->tlv_data
.hostname
,
512 (lsp
->lsp_header
->lsp_bits
& LSPBIT_IST
)
521 void lsp_update(struct isis_lsp
*lsp
, struct stream
*stream
,
522 struct isis_area
*area
, int level
)
524 dnode_t
*dnode
= NULL
;
526 /* Remove old LSP from database. This is required since the
527 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
528 * and will update it with the new data in the stream. */
529 dnode
= dict_lookup(area
->lspdb
[level
- 1], lsp
->lsp_header
->lsp_id
);
531 dnode_destroy(dict_delete(area
->lspdb
[level
- 1], dnode
));
535 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
537 rawlspid_print(lsp
->lsp_header
->lsp_id
));
542 /* rebuild the lsp data */
543 lsp_update_data(lsp
, stream
, area
, level
);
545 /* insert the lsp back into the database */
546 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
549 /* creation of LSP directly from what we received */
550 struct isis_lsp
*lsp_new_from_stream_ptr(struct stream
*stream
,
552 struct isis_lsp
*lsp0
,
553 struct isis_area
*area
, int level
)
555 struct isis_lsp
*lsp
;
557 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
558 lsp_update_data(lsp
, stream
, area
, level
);
562 * zero lsp -> create the list for fragments
564 lsp
->lspu
.frags
= list_new();
567 * a fragment -> set the backpointer and add this to zero lsps
570 lsp
->lspu
.zero_lsp
= lsp0
;
571 listnode_add(lsp0
->lspu
.frags
, lsp
);
577 struct isis_lsp
*lsp_new(struct isis_area
*area
, u_char
*lsp_id
,
578 u_int16_t rem_lifetime
, u_int32_t seq_num
,
579 u_int8_t lsp_bits
, u_int16_t checksum
, int level
)
581 struct isis_lsp
*lsp
;
583 (level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
585 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
588 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
589 if (LSP_FRAGMENT(lsp_id
) == 0)
590 lsp
->lspu
.frags
= list_new();
592 fill_fixed_hdr(pdu_type
, lsp
->pdu
);
594 /* now for the LSP HEADER */
595 /* Minimal LSP PDU size */
596 lsp
->lsp_header
= (struct isis_link_state_hdr
*)(STREAM_DATA(lsp
->pdu
)
597 + ISIS_FIXED_HDR_LEN
);
598 lsp
->lsp_header
->pdu_len
= htons(ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
599 memcpy(lsp
->lsp_header
->lsp_id
, lsp_id
, ISIS_SYS_ID_LEN
+ 2);
600 lsp
->lsp_header
->checksum
= checksum
; /* Provided in network order */
601 lsp
->lsp_header
->seq_num
= htonl(seq_num
);
602 lsp
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
603 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
605 lsp
->age_out
= ZERO_AGE_LIFETIME
;
607 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
609 if (isis
->debugs
& DEBUG_EVENTS
)
610 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
612 LSP_PSEUDO_ID(lsp
->lsp_header
->lsp_id
),
613 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
),
614 ntohl(lsp
->lsp_header
->pdu_len
),
615 ntohl(lsp
->lsp_header
->seq_num
));
620 void lsp_insert(struct isis_lsp
*lsp
, dict_t
*lspdb
)
622 dict_alloc_insert(lspdb
, lsp
->lsp_header
->lsp_id
, lsp
);
623 if (lsp
->lsp_header
->seq_num
!= 0) {
624 isis_spf_schedule(lsp
->area
, lsp
->level
);
629 * Build a list of LSPs with non-zero ht bounded by start and stop ids
631 void lsp_build_list_nonzero_ht(u_char
*start_id
, u_char
*stop_id
,
632 struct list
*list
, dict_t
*lspdb
)
634 dnode_t
*first
, *last
, *curr
;
636 first
= dict_lower_bound(lspdb
, start_id
);
640 last
= dict_upper_bound(lspdb
, stop_id
);
644 if (((struct isis_lsp
*)(curr
->dict_data
))->lsp_header
->rem_lifetime
)
645 listnode_add(list
, first
->dict_data
);
648 curr
= dict_next(lspdb
, curr
);
650 && ((struct isis_lsp
*)(curr
->dict_data
))
651 ->lsp_header
->rem_lifetime
)
652 listnode_add(list
, curr
->dict_data
);
661 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
663 void lsp_build_list(u_char
*start_id
, u_char
*stop_id
, u_char num_lsps
,
664 struct list
*list
, dict_t
*lspdb
)
667 dnode_t
*first
, *last
, *curr
;
669 first
= dict_lower_bound(lspdb
, start_id
);
673 last
= dict_upper_bound(lspdb
, stop_id
);
677 listnode_add(list
, first
->dict_data
);
681 curr
= dict_next(lspdb
, curr
);
683 listnode_add(list
, curr
->dict_data
);
686 if (count
== num_lsps
|| curr
== last
)
694 * Build a list of LSPs with SSN flag set for the given circuit
696 void lsp_build_list_ssn(struct isis_circuit
*circuit
, u_char num_lsps
,
697 struct list
*list
, dict_t
*lspdb
)
699 dnode_t
*dnode
, *next
;
700 struct isis_lsp
*lsp
;
703 dnode
= dict_first(lspdb
);
704 while (dnode
!= NULL
) {
705 next
= dict_next(lspdb
, dnode
);
706 lsp
= dnode_get(dnode
);
707 if (ISIS_CHECK_FLAG(lsp
->SSNflags
, circuit
)) {
708 listnode_add(list
, lsp
);
711 if (count
== num_lsps
)
719 static void lsp_set_time(struct isis_lsp
*lsp
)
723 if (lsp
->lsp_header
->rem_lifetime
== 0) {
724 if (lsp
->age_out
> 0)
729 lsp
->lsp_header
->rem_lifetime
=
730 htons(ntohs(lsp
->lsp_header
->rem_lifetime
) - 1);
733 static void lspid_print(u_char
*lsp_id
, u_char
*trg
, char dynhost
, char frag
)
735 struct isis_dynhn
*dyn
= NULL
;
736 u_char id
[SYSID_STRLEN
];
739 dyn
= dynhn_find_by_id(lsp_id
);
744 sprintf((char *)id
, "%.14s", dyn
->name
.name
);
745 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
746 sprintf((char *)id
, "%.14s", unix_hostname());
748 memcpy(id
, sysid_print(lsp_id
), 15);
750 sprintf((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
751 LSP_FRAGMENT(lsp_id
));
753 sprintf((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
756 /* Convert the lsp attribute bits to attribute string */
757 const char *lsp_bits2string(u_char
*lsp_bits
)
759 char *pos
= lsp_bits_string
;
764 /* we only focus on the default metric */
765 pos
+= sprintf(pos
, "%d/",
766 ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits
) ? 1 : 0);
768 pos
+= sprintf(pos
, "%d/",
769 ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits
) ? 1 : 0);
771 pos
+= sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits
) ? 1 : 0);
775 return lsp_bits_string
;
778 /* this function prints the lsp on show isis database */
779 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
784 lspid_print(lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
785 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
786 vty_out(vty
, "%5u ", ntohs(lsp
->lsp_header
->pdu_len
));
787 vty_out(vty
, "0x%08x ", ntohl(lsp
->lsp_header
->seq_num
));
788 vty_out(vty
, "0x%04x ", ntohs(lsp
->lsp_header
->checksum
));
789 if (ntohs(lsp
->lsp_header
->rem_lifetime
) == 0) {
790 snprintf(age_out
, 8, "(%u)", lsp
->age_out
);
792 vty_out(vty
, "%7s ", age_out
);
794 vty_out(vty
, " %5u ", ntohs(lsp
->lsp_header
->rem_lifetime
));
795 vty_out(vty
, "%s\n", lsp_bits2string(&lsp
->lsp_header
->lsp_bits
));
798 static void lsp_print_mt_reach(struct list
*list
, struct vty
*vty
, char dynhost
,
801 struct listnode
*node
;
802 struct te_is_neigh
*neigh
;
804 for (ALL_LIST_ELEMENTS_RO(list
, node
, neigh
)) {
807 lspid_print(neigh
->neigh_id
, lspid
, dynhost
, 0);
808 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
810 " Metric : %-8u IS-Extended : %s\n",
811 GET_TE_METRIC(neigh
), lspid
);
814 " Metric : %-8u MT-Reach : %s %s\n",
815 GET_TE_METRIC(neigh
), lspid
,
816 isis_mtid2str(mtid
));
818 if (IS_MPLS_TE(isisMplsTE
))
819 mpls_te_print_detail(vty
, neigh
);
823 static void lsp_print_mt_ipv6_reach(struct list
*list
, struct vty
*vty
,
826 struct listnode
*node
;
827 struct ipv6_reachability
*ipv6_reach
;
831 for (ALL_LIST_ELEMENTS_RO(list
, node
, ipv6_reach
)) {
832 memset(&in6
, 0, sizeof(in6
));
833 memcpy(in6
.s6_addr
, ipv6_reach
->prefix
,
834 PSIZE(ipv6_reach
->prefix_len
));
835 inet_ntop(AF_INET6
, &in6
, (char *)buff
, BUFSIZ
);
836 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
837 if ((ipv6_reach
->control_info
& CTRL_INFO_DISTRIBUTION
)
838 == DISTRIBUTION_INTERNAL
)
839 vty_out(vty
, " Metric : %-8" PRIu32
840 " IPv6-Internal : %s/%d\n",
841 ntohl(ipv6_reach
->metric
), buff
,
842 ipv6_reach
->prefix_len
);
844 vty_out(vty
, " Metric : %-8" PRIu32
845 " IPv6-External : %s/%d\n",
846 ntohl(ipv6_reach
->metric
), buff
,
847 ipv6_reach
->prefix_len
);
849 if ((ipv6_reach
->control_info
& CTRL_INFO_DISTRIBUTION
)
850 == DISTRIBUTION_INTERNAL
)
851 vty_out(vty
, " Metric : %-8" PRIu32
852 " IPv6-MT-Int : %s/%d %s\n",
853 ntohl(ipv6_reach
->metric
), buff
,
854 ipv6_reach
->prefix_len
,
855 isis_mtid2str(mtid
));
857 vty_out(vty
, " Metric : %-8" PRIu32
858 " IPv6-MT-Ext : %s/%d %s\n",
859 ntohl(ipv6_reach
->metric
), buff
,
860 ipv6_reach
->prefix_len
,
861 isis_mtid2str(mtid
));
866 static void lsp_print_mt_ipv4_reach(struct list
*list
, struct vty
*vty
,
869 struct listnode
*node
;
870 struct te_ipv4_reachability
*te_ipv4_reach
;
872 for (ALL_LIST_ELEMENTS_RO(list
, node
, te_ipv4_reach
)) {
873 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
874 /* FIXME: There should be better way to output this
876 vty_out(vty
, " Metric : %-8" PRIu32
877 " IPv4-Extended : %s/%d\n",
878 ntohl(te_ipv4_reach
->te_metric
),
879 inet_ntoa(newprefix2inaddr(
880 &te_ipv4_reach
->prefix_start
,
881 te_ipv4_reach
->control
)),
882 te_ipv4_reach
->control
& 0x3F);
884 /* FIXME: There should be better way to output this
886 vty_out(vty
, " Metric : %-8" PRIu32
887 " IPv4-MT : %s/%d %s\n",
888 ntohl(te_ipv4_reach
->te_metric
),
889 inet_ntoa(newprefix2inaddr(
890 &te_ipv4_reach
->prefix_start
,
891 te_ipv4_reach
->control
)),
892 te_ipv4_reach
->control
& 0x3F,
893 isis_mtid2str(mtid
));
898 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
900 struct area_addr
*area_addr
;
902 struct listnode
*lnode
;
903 struct is_neigh
*is_neigh
;
904 struct ipv4_reachability
*ipv4_reach
;
905 struct in_addr
*ipv4_addr
;
906 struct mt_router_info
*mt_router_info
;
907 struct tlv_mt_ipv6_reachs
*mt_ipv6_reachs
;
908 struct tlv_mt_neighbors
*mt_is_neigh
;
909 struct tlv_mt_ipv4_reachs
*mt_ipv4_reachs
;
911 u_char hostname
[255];
912 u_char ipv4_reach_prefix
[20];
913 u_char ipv4_reach_mask
[20];
914 u_char ipv4_address
[20];
916 lspid_print(lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
917 lsp_print(lsp
, vty
, dynhost
);
919 /* for all area address */
920 if (lsp
->tlv_data
.area_addrs
)
921 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.area_addrs
, lnode
,
923 vty_out(vty
, " Area Address: %s\n",
924 isonet_print(area_addr
->area_addr
,
925 area_addr
->addr_len
));
928 /* for the nlpid tlv */
929 if (lsp
->tlv_data
.nlpids
) {
930 for (i
= 0; i
< lsp
->tlv_data
.nlpids
->count
; i
++) {
931 switch (lsp
->tlv_data
.nlpids
->nlpids
[i
]) {
934 vty_out(vty
, " NLPID : 0x%X\n",
935 lsp
->tlv_data
.nlpids
->nlpids
[i
]);
938 vty_out(vty
, " NLPID : %s\n", "unknown");
944 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_router_info
, lnode
,
946 vty_out(vty
, " MT : %s%s\n",
947 isis_mtid2str(mt_router_info
->mtid
),
948 mt_router_info
->overload
? " (overload)" : "");
951 /* for the hostname tlv */
952 if (lsp
->tlv_data
.hostname
) {
953 bzero(hostname
, sizeof(hostname
));
954 memcpy(hostname
, lsp
->tlv_data
.hostname
->name
,
955 lsp
->tlv_data
.hostname
->namelen
);
956 vty_out(vty
, " Hostname : %s\n", hostname
);
959 /* authentication tlv */
960 if (lsp
->tlv_data
.auth_info
.type
!= ISIS_PASSWD_TYPE_UNUSED
) {
961 if (lsp
->tlv_data
.auth_info
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
962 vty_out(vty
, " Auth type : md5\n");
963 else if (lsp
->tlv_data
.auth_info
.type
964 == ISIS_PASSWD_TYPE_CLEARTXT
)
965 vty_out(vty
, " Auth type : clear text\n");
969 if (lsp
->tlv_data
.router_id
) {
970 memcpy(ipv4_address
, inet_ntoa(lsp
->tlv_data
.router_id
->id
),
971 sizeof(ipv4_address
));
972 vty_out(vty
, " Router ID : %s\n", ipv4_address
);
975 if (lsp
->tlv_data
.ipv4_addrs
)
976 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.ipv4_addrs
, lnode
,
978 memcpy(ipv4_address
, inet_ntoa(*ipv4_addr
),
979 sizeof(ipv4_address
));
980 vty_out(vty
, " IPv4 Address: %s\n", ipv4_address
);
983 /* for the IS neighbor tlv */
984 if (lsp
->tlv_data
.is_neighs
)
985 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.is_neighs
, lnode
,
987 lspid_print(is_neigh
->neigh_id
, LSPid
, dynhost
, 0);
988 vty_out(vty
, " Metric : %-8" PRIu8
990 is_neigh
->metrics
.metric_default
, LSPid
);
993 /* for the internal reachable tlv */
994 if (lsp
->tlv_data
.ipv4_int_reachs
)
995 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.ipv4_int_reachs
, lnode
,
997 memcpy(ipv4_reach_prefix
, inet_ntoa(ipv4_reach
->prefix
),
998 sizeof(ipv4_reach_prefix
));
999 memcpy(ipv4_reach_mask
, inet_ntoa(ipv4_reach
->mask
),
1000 sizeof(ipv4_reach_mask
));
1001 vty_out(vty
, " Metric : %-8" PRIu8
1002 " IPv4-Internal : %s %s\n",
1003 ipv4_reach
->metrics
.metric_default
,
1004 ipv4_reach_prefix
, ipv4_reach_mask
);
1007 /* for the external reachable tlv */
1008 if (lsp
->tlv_data
.ipv4_ext_reachs
)
1009 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.ipv4_ext_reachs
, lnode
,
1011 memcpy(ipv4_reach_prefix
, inet_ntoa(ipv4_reach
->prefix
),
1012 sizeof(ipv4_reach_prefix
));
1013 memcpy(ipv4_reach_mask
, inet_ntoa(ipv4_reach
->mask
),
1014 sizeof(ipv4_reach_mask
));
1015 vty_out(vty
, " Metric : %-8" PRIu8
1016 " IPv4-External : %s %s\n",
1017 ipv4_reach
->metrics
.metric_default
,
1018 ipv4_reach_prefix
, ipv4_reach_mask
);
1022 lsp_print_mt_ipv6_reach(lsp
->tlv_data
.ipv6_reachs
, vty
,
1023 ISIS_MT_IPV4_UNICAST
);
1025 /* MT IPv6 reachability tlv */
1026 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_ipv6_reachs
, lnode
,
1028 lsp_print_mt_ipv6_reach(mt_ipv6_reachs
->list
, vty
,
1029 mt_ipv6_reachs
->mtid
);
1031 /* TE IS neighbor tlv */
1032 lsp_print_mt_reach(lsp
->tlv_data
.te_is_neighs
, vty
, dynhost
,
1033 ISIS_MT_IPV4_UNICAST
);
1035 /* MT IS neighbor tlv */
1036 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_is_neighs
, lnode
,
1038 lsp_print_mt_reach(mt_is_neigh
->list
, vty
, dynhost
,
1042 lsp_print_mt_ipv4_reach(lsp
->tlv_data
.te_ipv4_reachs
, vty
,
1043 ISIS_MT_IPV4_UNICAST
);
1045 /* MT IPv4 reachability tlv */
1046 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_ipv4_reachs
, lnode
,
1048 lsp_print_mt_ipv4_reach(mt_ipv4_reachs
->list
, vty
,
1049 mt_ipv4_reachs
->mtid
);
1056 /* print all the lsps info in the local lspdb */
1057 int lsp_print_all(struct vty
*vty
, dict_t
*lspdb
, char detail
, char dynhost
)
1060 dnode_t
*node
= dict_first(lspdb
), *next
;
1063 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
1064 while (node
!= NULL
) {
1065 /* I think it is unnecessary, so I comment it out */
1066 /* dict_contains (lspdb, node); */
1067 next
= dict_next(lspdb
, node
);
1068 lsp_print(dnode_get(node
), vty
, dynhost
);
1072 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
1073 while (node
!= NULL
) {
1074 next
= dict_next(lspdb
, node
);
1075 lsp_print_detail(dnode_get(node
), vty
, dynhost
);
1084 static void _lsp_tlv_fit(struct isis_lsp
*lsp
, struct list
**from
,
1085 struct list
**to
, int frag_thold
,
1086 unsigned int tlv_build_func(struct list
*,
1091 while (*from
&& listcount(*from
)) {
1094 count
= tlv_build_func(*from
, lsp
->pdu
, arg
);
1096 if (listcount(*to
) != 0 || count
!= listcount(*from
)) {
1097 struct listnode
*node
, *nnode
;
1100 for (ALL_LIST_ELEMENTS(*from
, node
, nnode
, elem
)) {
1103 listnode_add(*to
, elem
);
1104 list_delete_node(*from
, node
);
1115 #define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100)
1117 /* stream*, area->lsp_frag_threshold, increment */
1118 #define FRAG_NEEDED(S, T, I) \
1119 (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T))
1121 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1122 * variable length (TE TLVs, sub TLVs). */
1123 static void lsp_tlv_fit(struct isis_lsp
*lsp
, struct list
**from
,
1124 struct list
**to
, int tlvsize
, int frag_thold
,
1125 int tlv_build_func(struct list
*, struct stream
*))
1129 /* can we fit all ? */
1130 if (!FRAG_NEEDED(lsp
->pdu
, frag_thold
,
1131 listcount(*from
) * tlvsize
+ 2)) {
1132 tlv_build_func(*from
, lsp
->pdu
);
1133 if (listcount(*to
) != 0) {
1134 struct listnode
*node
, *nextnode
;
1137 for (ALL_LIST_ELEMENTS(*from
, node
, nextnode
, elem
)) {
1138 listnode_add(*to
, elem
);
1139 list_delete_node(*from
, node
);
1146 } else if (!FRAG_NEEDED(lsp
->pdu
, frag_thold
, tlvsize
+ 2)) {
1147 /* fit all we can */
1148 count
= FRAG_THOLD(lsp
->pdu
, frag_thold
) - 2
1149 - (STREAM_SIZE(lsp
->pdu
) - STREAM_REMAIN(lsp
->pdu
));
1150 count
= count
/ tlvsize
;
1151 if (count
> (int)listcount(*from
))
1152 count
= listcount(*from
);
1153 for (i
= 0; i
< count
; i
++) {
1154 listnode_add(*to
, listgetdata(listhead(*from
)));
1155 listnode_delete(*from
, listgetdata(listhead(*from
)));
1157 tlv_build_func(*to
, lsp
->pdu
);
1159 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
1163 static u_int16_t
lsp_rem_lifetime(struct isis_area
*area
, int level
)
1165 u_int16_t rem_lifetime
;
1167 /* Add jitter to configured LSP lifetime */
1169 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
1171 /* No jitter if the max refresh will be less than configure gen interval
1173 /* N.B. this calucation is acceptable since rem_lifetime is in
1176 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
1177 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
1179 return rem_lifetime
;
1182 static u_int16_t
lsp_refresh_time(struct isis_lsp
*lsp
, u_int16_t rem_lifetime
)
1184 struct isis_area
*area
= lsp
->area
;
1185 int level
= lsp
->level
;
1186 u_int16_t refresh_time
;
1188 /* Add jitter to LSP refresh time */
1190 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
1192 /* RFC 4444 : make sure the refresh time is at least less than 300
1193 * of the remaining lifetime and more than gen interval */
1194 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
1195 || refresh_time
> (rem_lifetime
- 300))
1196 refresh_time
= rem_lifetime
- 300;
1198 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1199 * we accept this violation to satisfy refresh_time <= rem_lifetime -
1202 return refresh_time
;
1205 static struct isis_lsp
*lsp_next_frag(u_char frag_num
, struct isis_lsp
*lsp0
,
1206 struct isis_area
*area
, int level
)
1208 struct isis_lsp
*lsp
;
1209 u_char frag_id
[ISIS_SYS_ID_LEN
+ 2];
1211 memcpy(frag_id
, lsp0
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1212 LSP_FRAGMENT(frag_id
) = frag_num
;
1213 /* FIXME add authentication TLV for fragment LSPs */
1214 lsp
= lsp_search(frag_id
, area
->lspdb
[level
- 1]);
1216 /* Clear the TLVs */
1217 lsp_clear_data(lsp
);
1220 lsp
= lsp_new(area
, frag_id
, ntohs(lsp0
->lsp_header
->rem_lifetime
), 0,
1221 lsp_bits_generate(level
, area
->overload_bit
,
1222 area
->attached_bit
),
1226 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
1227 listnode_add(lsp0
->lspu
.frags
, lsp
);
1228 lsp
->lspu
.zero_lsp
= lsp0
;
1232 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
1233 struct isis_area
*area
,
1234 struct tlvs
*tlv_data
)
1236 struct route_table
*er_table
;
1237 struct route_node
*rn
;
1238 struct prefix_ipv4
*ipv4
;
1239 struct isis_ext_info
*info
;
1240 struct ipv4_reachability
*ipreach
;
1241 struct te_ipv4_reachability
*te_ipreach
;
1243 er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
1247 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
)) {
1251 ipv4
= (struct prefix_ipv4
*)&rn
->p
;
1253 if (area
->oldmetric
) {
1254 if (tlv_data
->ipv4_ext_reachs
== NULL
) {
1255 tlv_data
->ipv4_ext_reachs
= list_new();
1256 tlv_data
->ipv4_ext_reachs
->del
= free_tlv
;
1258 ipreach
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*ipreach
));
1260 ipreach
->prefix
.s_addr
= ipv4
->prefix
.s_addr
;
1261 masklen2ip(ipv4
->prefixlen
, &ipreach
->mask
);
1262 ipreach
->prefix
.s_addr
&= ipreach
->mask
.s_addr
;
1264 if ((info
->metric
& 0x3f) != info
->metric
)
1265 ipreach
->metrics
.metric_default
= 0x3f;
1267 ipreach
->metrics
.metric_default
= info
->metric
;
1268 ipreach
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1269 ipreach
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1270 ipreach
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1271 listnode_add(tlv_data
->ipv4_ext_reachs
, ipreach
);
1273 if (area
->newmetric
) {
1274 if (tlv_data
->te_ipv4_reachs
== NULL
) {
1275 tlv_data
->te_ipv4_reachs
= list_new();
1276 tlv_data
->te_ipv4_reachs
->del
= free_tlv
;
1278 te_ipreach
= XCALLOC(MTYPE_ISIS_TLV
,
1279 sizeof(*te_ipreach
) - 1
1280 + PSIZE(ipv4
->prefixlen
));
1281 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1282 te_ipreach
->te_metric
=
1283 htonl(MAX_WIDE_PATH_METRIC
);
1285 te_ipreach
->te_metric
= htonl(info
->metric
);
1286 te_ipreach
->control
= ipv4
->prefixlen
& 0x3f;
1287 memcpy(&te_ipreach
->prefix_start
, &ipv4
->prefix
.s_addr
,
1288 PSIZE(ipv4
->prefixlen
));
1289 listnode_add(tlv_data
->te_ipv4_reachs
, te_ipreach
);
1294 static struct list
*tlv_get_ipv6_reach_list(struct isis_area
*area
,
1295 struct tlvs
*tlv_data
)
1297 uint16_t mtid
= isis_area_ipv6_topology(area
);
1298 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1299 if (!tlv_data
->ipv6_reachs
) {
1300 tlv_data
->ipv6_reachs
= list_new();
1301 tlv_data
->ipv6_reachs
->del
= free_tlv
;
1303 return tlv_data
->ipv6_reachs
;
1306 struct tlv_mt_ipv6_reachs
*reachs
=
1307 tlvs_get_mt_ipv6_reachs(tlv_data
, mtid
);
1308 return reachs
->list
;
1311 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
1312 struct isis_area
*area
,
1313 struct tlvs
*tlv_data
)
1315 struct route_table
*er_table
;
1316 struct route_node
*rn
;
1317 struct prefix_ipv6
*ipv6
;
1318 struct isis_ext_info
*info
;
1319 struct ipv6_reachability
*ip6reach
;
1320 struct list
*reach_list
= NULL
;
1322 er_table
= get_ext_reach(area
, AF_INET6
, lsp
->level
);
1326 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
)) {
1330 ipv6
= (struct prefix_ipv6
*)&rn
->p
;
1334 reach_list
= tlv_get_ipv6_reach_list(area
, tlv_data
);
1336 ip6reach
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ip6reach
));
1337 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1338 ip6reach
->metric
= htonl(MAX_WIDE_PATH_METRIC
);
1340 ip6reach
->metric
= htonl(info
->metric
);
1341 ip6reach
->control_info
= DISTRIBUTION_EXTERNAL
;
1342 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1343 memcpy(ip6reach
->prefix
, ipv6
->prefix
.s6_addr
,
1344 sizeof(ip6reach
->prefix
));
1345 listnode_add(reach_list
, ip6reach
);
1349 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
,
1350 struct tlvs
*tlv_data
)
1352 lsp_build_ext_reach_ipv4(lsp
, area
, tlv_data
);
1353 lsp_build_ext_reach_ipv6(lsp
, area
, tlv_data
);
1357 * Builds the LSP data part. This func creates a new frag whenever
1358 * area->lsp_frag_threshold is exceeded.
1360 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
1362 struct is_neigh
*is_neigh
;
1363 struct te_is_neigh
*te_is_neigh
;
1364 struct listnode
*node
, *ipnode
;
1365 int level
= lsp
->level
;
1366 struct isis_circuit
*circuit
;
1367 struct prefix_ipv4
*ipv4
;
1368 struct ipv4_reachability
*ipreach
;
1369 struct te_ipv4_reachability
*te_ipreach
;
1370 struct isis_adjacency
*nei
;
1371 struct prefix_ipv6
*ipv6
, ip6prefix
;
1372 struct list
*ipv6_reachs
= NULL
;
1373 struct ipv6_reachability
*ip6reach
;
1374 struct tlvs tlv_data
;
1375 struct isis_lsp
*lsp0
= lsp
;
1376 struct in_addr
*routerid
;
1377 uint32_t expected
= 0, found
= 0;
1379 u_char zero_id
[ISIS_SYS_ID_LEN
+ 1];
1380 int retval
= ISIS_OK
;
1383 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1384 area
->area_tag
, level
);
1387 * Building the zero lsp
1389 memset(zero_id
, 0, ISIS_SYS_ID_LEN
+ 1);
1391 /* Reset stream endp. Stream is always there and on every LSP refresh
1393 * TLV part of it is overwritten. So we must seek past header we will
1396 stream_reset(lsp
->pdu
);
1397 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
1400 * Add the authentication info if its present
1405 * First add the tlvs related to area
1408 /* Area addresses */
1409 if (lsp
->tlv_data
.area_addrs
== NULL
)
1410 lsp
->tlv_data
.area_addrs
= list_new();
1411 list_add_list(lsp
->tlv_data
.area_addrs
, area
->area_addrs
);
1412 if (listcount(lsp
->tlv_data
.area_addrs
) > 0)
1413 tlv_add_area_addrs(lsp
->tlv_data
.area_addrs
, lsp
->pdu
);
1415 /* Protocols Supported */
1416 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
1417 lsp
->tlv_data
.nlpids
=
1418 XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct nlpids
));
1419 lsp
->tlv_data
.nlpids
->count
= 0;
1420 if (area
->ip_circuits
> 0) {
1422 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1424 lsp
->tlv_data
.nlpids
->count
++;
1425 lsp
->tlv_data
.nlpids
->nlpids
[0] = NLPID_IP
;
1427 if (area
->ipv6_circuits
> 0) {
1429 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1431 lsp
->tlv_data
.nlpids
->count
++;
1432 lsp
->tlv_data
.nlpids
1433 ->nlpids
[lsp
->tlv_data
.nlpids
->count
- 1] =
1436 tlv_add_nlpid(lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1439 if (area_is_mt(area
)) {
1440 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
1441 lsp
->tlv_data
.mt_router_info
= list_new();
1442 lsp
->tlv_data
.mt_router_info
->del
= free_tlv
;
1444 struct isis_area_mt_setting
**mt_settings
;
1445 unsigned int mt_count
;
1447 mt_settings
= area_mt_settings(area
, &mt_count
);
1448 for (unsigned int i
= 0; i
< mt_count
; i
++) {
1449 struct mt_router_info
*info
;
1451 info
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*info
));
1452 info
->mtid
= mt_settings
[i
]->mtid
;
1453 info
->overload
= mt_settings
[i
]->overload
;
1454 listnode_add(lsp
->tlv_data
.mt_router_info
, info
);
1455 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
1456 isis_mtid2str(info
->mtid
));
1458 tlv_add_mt_router_info(lsp
->tlv_data
.mt_router_info
, lsp
->pdu
);
1460 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
1463 /* Dynamic Hostname */
1464 if (area
->dynhostname
) {
1465 const char *hostname
= unix_hostname();
1466 size_t hostname_len
= strlen(hostname
);
1468 lsp
->tlv_data
.hostname
=
1469 XMALLOC(MTYPE_ISIS_TLV
, sizeof(struct hostname
));
1471 strncpy((char *)lsp
->tlv_data
.hostname
->name
, hostname
,
1472 sizeof(lsp
->tlv_data
.hostname
->name
));
1473 if (hostname_len
<= MAX_TLV_LEN
)
1474 lsp
->tlv_data
.hostname
->namelen
= hostname_len
;
1476 lsp
->tlv_data
.hostname
->namelen
= MAX_TLV_LEN
;
1478 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'",
1479 area
->area_tag
, lsp
->tlv_data
.hostname
->namelen
,
1480 lsp
->tlv_data
.hostname
->name
);
1481 tlv_add_dynamic_hostname(lsp
->tlv_data
.hostname
, lsp
->pdu
);
1483 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1487 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1488 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
1490 * LSP and this address is same as router id. */
1491 if (isis
->router_id
!= 0) {
1492 inet_ntop(AF_INET
, &isis
->router_id
, buf
, sizeof(buf
));
1493 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
1494 area
->area_tag
, buf
);
1495 if (lsp
->tlv_data
.ipv4_addrs
== NULL
) {
1496 lsp
->tlv_data
.ipv4_addrs
= list_new();
1497 lsp
->tlv_data
.ipv4_addrs
->del
= free_tlv
;
1500 routerid
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(struct in_addr
));
1501 routerid
->s_addr
= isis
->router_id
;
1502 listnode_add(lsp
->tlv_data
.ipv4_addrs
, routerid
);
1503 tlv_add_in_addr(routerid
, lsp
->pdu
, IPV4_ADDR
);
1505 /* Exactly same data is put into TE router ID TLV, but only if
1507 * TLV's are in use. */
1508 if (area
->newmetric
) {
1510 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1512 lsp
->tlv_data
.router_id
=
1513 XMALLOC(MTYPE_ISIS_TLV
, sizeof(struct in_addr
));
1514 lsp
->tlv_data
.router_id
->id
.s_addr
= isis
->router_id
;
1515 tlv_add_in_addr(&lsp
->tlv_data
.router_id
->id
, lsp
->pdu
,
1519 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1523 memset(&tlv_data
, 0, sizeof(struct tlvs
));
1525 lsp_debug("ISIS (%s): Adding circuit specific information.",
1529 * Then build lists of tlvs related to circuits
1531 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
1532 if (!circuit
->interface
)
1534 "ISIS (%s): Processing %s circuit %p with unknown interface",
1536 circuit_type2string(circuit
->circ_type
),
1539 lsp_debug("ISIS (%s): Processing %s circuit %s",
1541 circuit_type2string(circuit
->circ_type
),
1542 circuit
->interface
->name
);
1544 if (circuit
->state
!= C_STATE_UP
) {
1545 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1551 * Add IPv4 internal reachability of this circuit
1553 if (circuit
->ip_router
&& circuit
->ip_addrs
1554 && circuit
->ip_addrs
->count
> 0) {
1556 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1558 if (area
->oldmetric
) {
1559 if (tlv_data
.ipv4_int_reachs
== NULL
) {
1560 tlv_data
.ipv4_int_reachs
= list_new();
1561 tlv_data
.ipv4_int_reachs
->del
=
1564 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
,
1569 ipv4_reachability
));
1570 ipreach
->metrics
.metric_default
=
1571 circuit
->metric
[level
- 1];
1572 ipreach
->metrics
.metric_expense
=
1573 METRICS_UNSUPPORTED
;
1574 ipreach
->metrics
.metric_error
=
1575 METRICS_UNSUPPORTED
;
1576 ipreach
->metrics
.metric_delay
=
1577 METRICS_UNSUPPORTED
;
1578 masklen2ip(ipv4
->prefixlen
,
1580 ipreach
->prefix
.s_addr
=
1581 ((ipreach
->mask
.s_addr
)
1582 & (ipv4
->prefix
.s_addr
));
1584 &ipreach
->prefix
.s_addr
, buf
,
1587 "ISIS (%s): Adding old-style IP reachability for %s/%d",
1588 area
->area_tag
, buf
,
1590 listnode_add(tlv_data
.ipv4_int_reachs
,
1594 if (area
->newmetric
) {
1595 if (tlv_data
.te_ipv4_reachs
== NULL
) {
1596 tlv_data
.te_ipv4_reachs
= list_new();
1597 tlv_data
.te_ipv4_reachs
->del
= free_tlv
;
1599 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
,
1601 /* FIXME All this assumes that we have
1603 te_ipreach
= XCALLOC(
1606 te_ipv4_reachability
)
1607 + ((ipv4
->prefixlen
+ 7)
1611 if (area
->oldmetric
)
1612 te_ipreach
->te_metric
= htonl(
1613 circuit
->metric
[level
1616 te_ipreach
->te_metric
= htonl(
1620 te_ipreach
->control
=
1621 (ipv4
->prefixlen
& 0x3F);
1622 memcpy(&te_ipreach
->prefix_start
,
1623 &ipv4
->prefix
.s_addr
,
1624 (ipv4
->prefixlen
+ 7) / 8);
1625 inet_ntop(AF_INET
, &ipv4
->prefix
.s_addr
,
1628 "ISIS (%s): Adding te-style IP reachability for %s/%d",
1629 area
->area_tag
, buf
,
1631 listnode_add(tlv_data
.te_ipv4_reachs
,
1638 * Add IPv6 reachability of this circuit
1640 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1641 && circuit
->ipv6_non_link
->count
> 0) {
1643 ipv6_reachs
= tlv_get_ipv6_reach_list(
1646 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1650 sizeof(struct ipv6_reachability
));
1652 if (area
->oldmetric
)
1653 ip6reach
->metric
= htonl(
1654 circuit
->metric
[level
- 1]);
1656 ip6reach
->metric
= htonl(
1657 circuit
->te_metric
[level
- 1]);
1659 ip6reach
->control_info
= 0;
1660 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1661 memcpy(&ip6prefix
, ipv6
, sizeof(ip6prefix
));
1662 apply_mask_ipv6(&ip6prefix
);
1664 inet_ntop(AF_INET6
, &ip6prefix
.prefix
.s6_addr
,
1667 "ISIS (%s): Adding IPv6 reachability for %s/%d",
1668 area
->area_tag
, buf
, ipv6
->prefixlen
);
1670 memcpy(ip6reach
->prefix
,
1671 ip6prefix
.prefix
.s6_addr
,
1672 sizeof(ip6reach
->prefix
));
1673 listnode_add(ipv6_reachs
, ip6reach
);
1677 switch (circuit
->circ_type
) {
1678 case CIRCUIT_T_BROADCAST
:
1679 if (level
& circuit
->is_type
) {
1680 if (area
->oldmetric
) {
1681 if (tlv_data
.is_neighs
== NULL
) {
1682 tlv_data
.is_neighs
= list_new();
1683 tlv_data
.is_neighs
->del
=
1688 sizeof(struct is_neigh
));
1689 if (level
== IS_LEVEL_1
)
1690 memcpy(is_neigh
->neigh_id
,
1693 ISIS_SYS_ID_LEN
+ 1);
1695 memcpy(is_neigh
->neigh_id
,
1698 ISIS_SYS_ID_LEN
+ 1);
1699 is_neigh
->metrics
.metric_default
=
1700 circuit
->metric
[level
- 1];
1701 is_neigh
->metrics
.metric_expense
=
1702 METRICS_UNSUPPORTED
;
1703 is_neigh
->metrics
.metric_error
=
1704 METRICS_UNSUPPORTED
;
1705 is_neigh
->metrics
.metric_delay
=
1706 METRICS_UNSUPPORTED
;
1707 if (!memcmp(is_neigh
->neigh_id
, zero_id
,
1708 ISIS_SYS_ID_LEN
+ 1)) {
1709 XFREE(MTYPE_ISIS_TLV
, is_neigh
);
1711 "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1714 listnode_add(tlv_data
.is_neighs
,
1717 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1720 is_neigh
->neigh_id
),
1722 is_neigh
->neigh_id
));
1725 if (area
->newmetric
) {
1726 if (tlv_data
.te_is_neighs
== NULL
) {
1727 tlv_data
.te_is_neighs
=
1729 tlv_data
.te_is_neighs
->del
=
1732 te_is_neigh
= XCALLOC(
1734 sizeof(struct te_is_neigh
));
1735 if (level
== IS_LEVEL_1
)
1736 memcpy(te_is_neigh
->neigh_id
,
1739 ISIS_SYS_ID_LEN
+ 1);
1741 memcpy(te_is_neigh
->neigh_id
,
1744 ISIS_SYS_ID_LEN
+ 1);
1745 if (area
->oldmetric
)
1746 metric
= circuit
->metric
[level
1750 circuit
->te_metric
[level
1752 SET_TE_METRIC(te_is_neigh
, metric
);
1753 if (!memcmp(te_is_neigh
->neigh_id
,
1755 ISIS_SYS_ID_LEN
+ 1)) {
1756 XFREE(MTYPE_ISIS_TLV
,
1759 "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1762 /* Check if MPLS_TE is activate
1764 if (IS_MPLS_TE(isisMplsTE
)
1766 circuit
->interface
))
1767 /* Add SubTLVs & Adjust
1768 * real size of SubTLVs
1771 ->sub_tlvs_length
= add_te_subtlvs(
1778 * SubTLVs if MPLS_TE is
1786 level
, te_is_neigh
);
1787 XFREE(MTYPE_ISIS_TLV
,
1793 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1798 nei
= circuit
->u
.p2p
.neighbor
;
1799 if (nei
&& (level
& nei
->circuit_t
)) {
1800 if (area
->oldmetric
) {
1801 if (tlv_data
.is_neighs
== NULL
) {
1802 tlv_data
.is_neighs
= list_new();
1803 tlv_data
.is_neighs
->del
=
1808 sizeof(struct is_neigh
));
1809 memcpy(is_neigh
->neigh_id
, nei
->sysid
,
1811 is_neigh
->metrics
.metric_default
=
1812 circuit
->metric
[level
- 1];
1813 is_neigh
->metrics
.metric_expense
=
1814 METRICS_UNSUPPORTED
;
1815 is_neigh
->metrics
.metric_error
=
1816 METRICS_UNSUPPORTED
;
1817 is_neigh
->metrics
.metric_delay
=
1818 METRICS_UNSUPPORTED
;
1819 listnode_add(tlv_data
.is_neighs
,
1822 "ISIS (%s): Adding old-style is reach for %s",
1825 is_neigh
->neigh_id
));
1827 if (area
->newmetric
) {
1830 if (tlv_data
.te_is_neighs
== NULL
) {
1831 tlv_data
.te_is_neighs
=
1833 tlv_data
.te_is_neighs
->del
=
1836 te_is_neigh
= XCALLOC(
1838 sizeof(struct te_is_neigh
));
1839 memcpy(te_is_neigh
->neigh_id
,
1840 nei
->sysid
, ISIS_SYS_ID_LEN
);
1841 metric
= circuit
->te_metric
[level
- 1];
1842 SET_TE_METRIC(te_is_neigh
, metric
);
1843 /* Check if MPLS_TE is activate */
1844 if (IS_MPLS_TE(isisMplsTE
)
1846 circuit
->interface
))
1847 /* Update Local and Remote IP
1848 * address for MPLS TE circuit
1850 /* NOTE sure that it is the
1851 * pertinent place for that
1853 /* Local IP address could be
1854 * updated in isis_circuit.c -
1855 * isis_circuit_add_addr() */
1856 /* But, where update remote IP
1857 * address ? in isis_pdu.c -
1858 * process_p2p_hello() ? */
1860 /* Add SubTLVs & Adjust real
1861 * size of SubTLVs */
1862 te_is_neigh
->sub_tlvs_length
=
1868 /* Or keep only TE metric with
1869 * no SubTLVs if MPLS_TE is off
1871 te_is_neigh
->sub_tlvs_length
=
1874 tlvs_add_mt_p2p(&tlv_data
, circuit
,
1876 XFREE(MTYPE_ISIS_TLV
, te_is_neigh
);
1880 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1884 case CIRCUIT_T_LOOPBACK
:
1887 zlog_warn("lsp_area_create: unknown circuit type");
1891 lsp_build_ext_reach(lsp
, area
, &tlv_data
);
1893 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1896 while (tlv_data
.ipv4_int_reachs
1897 && listcount(tlv_data
.ipv4_int_reachs
)) {
1898 if (lsp
->tlv_data
.ipv4_int_reachs
== NULL
)
1899 lsp
->tlv_data
.ipv4_int_reachs
= list_new();
1900 lsp_tlv_fit(lsp
, &tlv_data
.ipv4_int_reachs
,
1901 &lsp
->tlv_data
.ipv4_int_reachs
, IPV4_REACH_LEN
,
1902 area
->lsp_frag_threshold
, tlv_add_ipv4_int_reachs
);
1903 if (tlv_data
.ipv4_int_reachs
1904 && listcount(tlv_data
.ipv4_int_reachs
))
1905 lsp
= lsp_next_frag(
1906 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1910 while (tlv_data
.ipv4_ext_reachs
1911 && listcount(tlv_data
.ipv4_ext_reachs
)) {
1912 if (lsp
->tlv_data
.ipv4_ext_reachs
== NULL
)
1913 lsp
->tlv_data
.ipv4_ext_reachs
= list_new();
1914 lsp_tlv_fit(lsp
, &tlv_data
.ipv4_ext_reachs
,
1915 &lsp
->tlv_data
.ipv4_ext_reachs
, IPV4_REACH_LEN
,
1916 area
->lsp_frag_threshold
, tlv_add_ipv4_ext_reachs
);
1917 if (tlv_data
.ipv4_ext_reachs
1918 && listcount(tlv_data
.ipv4_ext_reachs
))
1919 lsp
= lsp_next_frag(
1920 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1924 while (tlv_data
.te_ipv4_reachs
&& listcount(tlv_data
.te_ipv4_reachs
)) {
1925 if (lsp
->tlv_data
.te_ipv4_reachs
== NULL
)
1926 lsp
->tlv_data
.te_ipv4_reachs
= list_new();
1927 _lsp_tlv_fit(lsp
, &tlv_data
.te_ipv4_reachs
,
1928 &lsp
->tlv_data
.te_ipv4_reachs
,
1929 area
->lsp_frag_threshold
, tlv_add_te_ipv4_reachs
,
1931 if (tlv_data
.te_ipv4_reachs
1932 && listcount(tlv_data
.te_ipv4_reachs
))
1933 lsp
= lsp_next_frag(
1934 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1938 struct tlv_mt_ipv4_reachs
*mt_ipv4_reachs
;
1939 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv4_reachs
, node
,
1941 while (mt_ipv4_reachs
->list
1942 && listcount(mt_ipv4_reachs
->list
)) {
1943 struct tlv_mt_ipv4_reachs
*frag_mt_ipv4_reachs
;
1945 frag_mt_ipv4_reachs
= tlvs_get_mt_ipv4_reachs(
1946 &lsp
->tlv_data
, mt_ipv4_reachs
->mtid
);
1947 _lsp_tlv_fit(lsp
, &mt_ipv4_reachs
->list
,
1948 &frag_mt_ipv4_reachs
->list
,
1949 area
->lsp_frag_threshold
,
1950 tlv_add_te_ipv4_reachs
,
1951 &mt_ipv4_reachs
->mtid
);
1952 if (mt_ipv4_reachs
->list
1953 && listcount(mt_ipv4_reachs
->list
))
1954 lsp
= lsp_next_frag(
1955 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
)
1961 while (tlv_data
.ipv6_reachs
&& listcount(tlv_data
.ipv6_reachs
)) {
1962 if (lsp
->tlv_data
.ipv6_reachs
== NULL
)
1963 lsp
->tlv_data
.ipv6_reachs
= list_new();
1965 lsp
, &tlv_data
.ipv6_reachs
, &lsp
->tlv_data
.ipv6_reachs
,
1966 area
->lsp_frag_threshold
, tlv_add_ipv6_reachs
, NULL
);
1967 if (tlv_data
.ipv6_reachs
&& listcount(tlv_data
.ipv6_reachs
))
1968 lsp
= lsp_next_frag(
1969 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1973 struct tlv_mt_ipv6_reachs
*mt_ipv6_reachs
;
1974 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv6_reachs
, node
,
1976 while (mt_ipv6_reachs
->list
1977 && listcount(mt_ipv6_reachs
->list
)) {
1978 struct tlv_mt_ipv6_reachs
*frag_mt_ipv6_reachs
;
1980 frag_mt_ipv6_reachs
= tlvs_get_mt_ipv6_reachs(
1981 &lsp
->tlv_data
, mt_ipv6_reachs
->mtid
);
1982 _lsp_tlv_fit(lsp
, &mt_ipv6_reachs
->list
,
1983 &frag_mt_ipv6_reachs
->list
,
1984 area
->lsp_frag_threshold
,
1985 tlv_add_ipv6_reachs
,
1986 &mt_ipv6_reachs
->mtid
);
1987 if (mt_ipv6_reachs
->list
1988 && listcount(mt_ipv6_reachs
->list
))
1989 lsp
= lsp_next_frag(
1990 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
)
1996 while (tlv_data
.is_neighs
&& listcount(tlv_data
.is_neighs
)) {
1997 if (lsp
->tlv_data
.is_neighs
== NULL
)
1998 lsp
->tlv_data
.is_neighs
= list_new();
1999 lsp_tlv_fit(lsp
, &tlv_data
.is_neighs
, &lsp
->tlv_data
.is_neighs
,
2000 IS_NEIGHBOURS_LEN
, area
->lsp_frag_threshold
,
2002 if (tlv_data
.is_neighs
&& listcount(tlv_data
.is_neighs
))
2003 lsp
= lsp_next_frag(
2004 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
2008 while (tlv_data
.te_is_neighs
&& listcount(tlv_data
.te_is_neighs
)) {
2009 if (lsp
->tlv_data
.te_is_neighs
== NULL
)
2010 lsp
->tlv_data
.te_is_neighs
= list_new();
2011 _lsp_tlv_fit(lsp
, &tlv_data
.te_is_neighs
,
2012 &lsp
->tlv_data
.te_is_neighs
,
2013 area
->lsp_frag_threshold
, tlv_add_te_is_neighs
,
2015 if (tlv_data
.te_is_neighs
&& listcount(tlv_data
.te_is_neighs
))
2016 lsp
= lsp_next_frag(
2017 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
2021 struct tlv_mt_neighbors
*mt_neighs
;
2022 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_is_neighs
, node
, mt_neighs
)) {
2023 while (mt_neighs
->list
&& listcount(mt_neighs
->list
)) {
2024 struct tlv_mt_neighbors
*frag_mt_neighs
;
2026 frag_mt_neighs
= tlvs_get_mt_neighbors(&lsp
->tlv_data
,
2028 _lsp_tlv_fit(lsp
, &mt_neighs
->list
,
2029 &frag_mt_neighs
->list
,
2030 area
->lsp_frag_threshold
,
2031 tlv_add_te_is_neighs
, &mt_neighs
->mtid
);
2032 if (mt_neighs
->list
&& listcount(mt_neighs
->list
))
2033 lsp
= lsp_next_frag(
2034 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
)
2041 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
2043 free_tlvs(&tlv_data
);
2045 /* Validate the LSP */
2046 retval
= parse_tlvs(area
->area_tag
,
2047 STREAM_DATA(lsp
->pdu
) + ISIS_FIXED_HDR_LEN
2049 stream_get_endp(lsp
->pdu
) - ISIS_FIXED_HDR_LEN
2051 &expected
, &found
, &tlv_data
, NULL
);
2052 assert(retval
== ISIS_OK
);
2058 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
2060 int lsp_generate(struct isis_area
*area
, int level
)
2062 struct isis_lsp
*oldlsp
, *newlsp
;
2063 u_int32_t seq_num
= 0;
2064 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
2065 u_int16_t rem_lifetime
, refresh_time
;
2067 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2070 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2071 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2073 /* only builds the lsp if the area shares the level */
2074 oldlsp
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
2076 /* FIXME: we should actually initiate a purge */
2077 seq_num
= ntohl(oldlsp
->lsp_header
->seq_num
);
2078 lsp_search_and_destroy(oldlsp
->lsp_header
->lsp_id
,
2079 area
->lspdb
[level
- 1]);
2081 rem_lifetime
= lsp_rem_lifetime(area
, level
);
2083 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
2084 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
2086 newlsp
->area
= area
;
2087 newlsp
->own_lsp
= 1;
2089 lsp_insert(newlsp
, area
->lspdb
[level
- 1]);
2090 /* build_lsp_data (newlsp, area); */
2091 lsp_build(newlsp
, area
);
2092 /* time to calculate our checksum */
2093 lsp_seqnum_update(newlsp
);
2094 newlsp
->last_generated
= time(NULL
);
2095 lsp_set_all_srmflags(newlsp
);
2097 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
2099 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
2100 area
->lsp_regenerate_pending
[level
- 1] = 0;
2101 if (level
== IS_LEVEL_1
)
2102 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
2103 &area
->t_lsp_refresh
[level
- 1]);
2104 else if (level
== IS_LEVEL_2
)
2105 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
2106 &area
->t_lsp_refresh
[level
- 1]);
2108 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2110 "ISIS-Upd (%s): Building L%d LSP %s, len %d, "
2111 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2112 area
->area_tag
, level
,
2113 rawlspid_print(newlsp
->lsp_header
->lsp_id
),
2114 ntohl(newlsp
->lsp_header
->pdu_len
),
2115 ntohl(newlsp
->lsp_header
->seq_num
),
2116 ntohs(newlsp
->lsp_header
->checksum
),
2117 ntohs(newlsp
->lsp_header
->rem_lifetime
), refresh_time
);
2120 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2121 area
->area_tag
, level
);
2127 * Search own LSPs, update holding time and set SRM
2129 static int lsp_regenerate(struct isis_area
*area
, int level
)
2132 struct isis_lsp
*lsp
, *frag
;
2133 struct listnode
*node
;
2134 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
2135 u_int16_t rem_lifetime
, refresh_time
;
2137 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2140 lspdb
= area
->lspdb
[level
- 1];
2142 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2143 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2145 lsp
= lsp_search(lspid
, lspdb
);
2148 zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2149 area
->area_tag
, level
);
2153 lsp_clear_data(lsp
);
2154 lsp_build(lsp
, area
);
2155 lsp
->lsp_header
->lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
2156 area
->attached_bit
);
2157 rem_lifetime
= lsp_rem_lifetime(area
, level
);
2158 lsp
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
2159 lsp_seqnum_update(lsp
);
2161 lsp
->last_generated
= time(NULL
);
2162 lsp_set_all_srmflags(lsp
);
2163 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2164 frag
->lsp_header
->lsp_bits
= lsp_bits_generate(
2165 level
, area
->overload_bit
, area
->attached_bit
);
2166 /* Set the lifetime values of all the fragments to the same
2168 * so that no fragment expires before the lsp is refreshed.
2170 frag
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
2171 lsp_set_all_srmflags(frag
);
2174 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
2175 if (level
== IS_LEVEL_1
)
2176 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
2177 &area
->t_lsp_refresh
[level
- 1]);
2178 else if (level
== IS_LEVEL_2
)
2179 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
2180 &area
->t_lsp_refresh
[level
- 1]);
2181 area
->lsp_regenerate_pending
[level
- 1] = 0;
2183 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2185 "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
2186 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2187 area
->area_tag
, level
,
2188 rawlspid_print(lsp
->lsp_header
->lsp_id
),
2189 ntohl(lsp
->lsp_header
->pdu_len
),
2190 ntohl(lsp
->lsp_header
->seq_num
),
2191 ntohs(lsp
->lsp_header
->checksum
),
2192 ntohs(lsp
->lsp_header
->rem_lifetime
), refresh_time
);
2195 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2196 area
->area_tag
, level
);
2202 * Something has changed or periodic refresh -> regenerate LSP
2204 static int lsp_l1_refresh(struct thread
*thread
)
2206 struct isis_area
*area
;
2208 area
= THREAD_ARG(thread
);
2211 area
->t_lsp_refresh
[0] = NULL
;
2212 area
->lsp_regenerate_pending
[0] = 0;
2214 if ((area
->is_type
& IS_LEVEL_1
) == 0)
2218 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
2220 return lsp_regenerate(area
, IS_LEVEL_1
);
2223 static int lsp_l2_refresh(struct thread
*thread
)
2225 struct isis_area
*area
;
2227 area
= THREAD_ARG(thread
);
2230 area
->t_lsp_refresh
[1] = NULL
;
2231 area
->lsp_regenerate_pending
[1] = 0;
2233 if ((area
->is_type
& IS_LEVEL_2
) == 0)
2237 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
2239 return lsp_regenerate(area
, IS_LEVEL_2
);
2242 int lsp_regenerate_schedule(struct isis_area
*area
, int level
, int all_pseudo
)
2244 struct isis_lsp
*lsp
;
2245 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2248 struct listnode
*cnode
;
2249 struct isis_circuit
*circuit
;
2256 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2257 area
->area_tag
, circuit_t2string(level
),
2258 all_pseudo
? "" : "not ");
2260 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2261 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
2264 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
2265 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
2269 "ISIS (%s): Checking whether L%d needs to be scheduled",
2270 area
->area_tag
, lvl
);
2272 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
2273 struct timeval remain
= thread_timer_remain(
2274 area
->t_lsp_refresh
[lvl
- 1]);
2276 "ISIS (%s): Regeneration is already pending, nothing todo."
2277 " (Due in %lld.%03lld seconds)",
2278 area
->area_tag
, (long long)remain
.tv_sec
,
2279 (long long)remain
.tv_usec
/ 1000);
2283 lsp
= lsp_search(id
, area
->lspdb
[lvl
- 1]);
2286 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2292 * Throttle avoidance
2295 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2296 area
->area_tag
, (long long)lsp
->last_generated
,
2298 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
2299 diff
= now
- lsp
->last_generated
;
2300 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
2302 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
2304 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2305 area
->area_tag
, timeout
);
2308 * lsps are not regenerated if lsp_regenerate function
2310 * directly. However if the lsp_regenerate call is
2312 * later execution it works.
2316 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2317 " Scheduling for execution in %ld ms.",
2318 area
->area_tag
, timeout
);
2321 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
2322 if (lvl
== IS_LEVEL_1
) {
2323 thread_add_timer_msec(master
, lsp_l1_refresh
, area
,
2325 &area
->t_lsp_refresh
[lvl
- 1]);
2326 } else if (lvl
== IS_LEVEL_2
) {
2327 thread_add_timer_msec(master
, lsp_l2_refresh
, area
,
2329 &area
->t_lsp_refresh
[lvl
- 1]);
2334 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
2335 lsp_regenerate_schedule_pseudo(circuit
, level
);
2342 * Funcs for pseudonode LSPs
2346 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2348 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2351 struct isis_adjacency
*adj
;
2352 struct is_neigh
*is_neigh
;
2353 struct te_is_neigh
*te_is_neigh
;
2354 struct es_neigh
*es_neigh
;
2355 struct list
*adj_list
;
2356 struct listnode
*node
;
2357 struct isis_area
*area
= circuit
->area
;
2360 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2361 area
->area_tag
, rawlspid_print(lsp
->lsp_header
->lsp_id
),
2362 circuit
->interface
->name
, level
);
2365 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2366 lsp
->lsp_header
->lsp_bits
=
2367 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
2370 * add self to IS neighbours
2372 if (circuit
->area
->oldmetric
) {
2373 if (lsp
->tlv_data
.is_neighs
== NULL
) {
2374 lsp
->tlv_data
.is_neighs
= list_new();
2375 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
2377 is_neigh
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct is_neigh
));
2379 memcpy(&is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2380 listnode_add(lsp
->tlv_data
.is_neighs
, is_neigh
);
2382 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2383 area
->area_tag
, sysid_print(is_neigh
->neigh_id
),
2384 LSP_PSEUDO_ID(is_neigh
->neigh_id
));
2386 if (circuit
->area
->newmetric
) {
2387 if (lsp
->tlv_data
.te_is_neighs
== NULL
) {
2388 lsp
->tlv_data
.te_is_neighs
= list_new();
2389 lsp
->tlv_data
.te_is_neighs
->del
= free_tlv
;
2392 XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct te_is_neigh
));
2394 memcpy(&te_is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2395 listnode_add(lsp
->tlv_data
.te_is_neighs
, te_is_neigh
);
2397 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2398 area
->area_tag
, sysid_print(te_is_neigh
->neigh_id
),
2399 LSP_PSEUDO_ID(te_is_neigh
->neigh_id
));
2402 adj_list
= list_new();
2403 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
2405 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
2406 if (adj
->level
& level
) {
2407 if ((level
== IS_LEVEL_1
2408 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
2409 || (level
== IS_LEVEL_1
2410 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
2411 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
2412 || (level
== IS_LEVEL_2
2413 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
2414 /* an IS neighbour -> add it */
2415 if (circuit
->area
->oldmetric
) {
2418 sizeof(struct is_neigh
));
2420 memcpy(&is_neigh
->neigh_id
, adj
->sysid
,
2422 listnode_add(lsp
->tlv_data
.is_neighs
,
2425 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2427 sysid_print(is_neigh
->neigh_id
),
2429 is_neigh
->neigh_id
));
2431 if (circuit
->area
->newmetric
) {
2432 te_is_neigh
= XCALLOC(
2434 sizeof(struct te_is_neigh
));
2435 memcpy(&te_is_neigh
->neigh_id
,
2436 adj
->sysid
, ISIS_SYS_ID_LEN
);
2437 listnode_add(lsp
->tlv_data
.te_is_neighs
,
2440 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2443 te_is_neigh
->neigh_id
),
2445 te_is_neigh
->neigh_id
));
2447 } else if (level
== IS_LEVEL_1
2448 && adj
->sys_type
== ISIS_SYSTYPE_ES
) {
2449 /* an ES neigbour add it, if we are building
2451 /* FIXME: the tlv-format is hard to use here */
2452 if (lsp
->tlv_data
.es_neighs
== NULL
) {
2453 lsp
->tlv_data
.es_neighs
= list_new();
2454 lsp
->tlv_data
.es_neighs
->del
= free_tlv
;
2456 es_neigh
= XCALLOC(MTYPE_ISIS_TLV
,
2457 sizeof(struct es_neigh
));
2459 memcpy(&es_neigh
->first_es_neigh
, adj
->sysid
,
2461 listnode_add(lsp
->tlv_data
.es_neighs
, es_neigh
);
2463 "ISIS (%s): Adding %s as ES neighbor (peer)",
2465 sysid_print(es_neigh
->first_es_neigh
));
2468 "ISIS (%s): Ignoring neighbor %s, level does not match",
2470 sysid_print(adj
->sysid
));
2474 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
2475 area
->area_tag
, sysid_print(adj
->sysid
));
2478 list_delete(adj_list
);
2480 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.",
2483 /* Reset endp of stream to overwrite only TLV part of it. */
2484 stream_reset(lsp
->pdu
);
2485 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2488 * Add the authentication info if it's present
2492 if (lsp
->tlv_data
.is_neighs
&& listcount(lsp
->tlv_data
.is_neighs
) > 0)
2493 tlv_add_is_neighs(lsp
->tlv_data
.is_neighs
, lsp
->pdu
);
2495 if (lsp
->tlv_data
.te_is_neighs
2496 && listcount(lsp
->tlv_data
.te_is_neighs
) > 0)
2497 tlv_add_te_is_neighs(lsp
->tlv_data
.te_is_neighs
, lsp
->pdu
,
2500 if (lsp
->tlv_data
.es_neighs
&& listcount(lsp
->tlv_data
.es_neighs
) > 0)
2501 tlv_add_is_neighs(lsp
->tlv_data
.es_neighs
, lsp
->pdu
);
2503 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
2505 /* Recompute authentication and checksum information */
2506 lsp_auth_update(lsp
);
2507 fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
2508 ntohs(lsp
->lsp_header
->pdu_len
) - 12, 12);
2513 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
2515 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
2516 struct isis_lsp
*lsp
;
2517 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2518 u_int16_t rem_lifetime
, refresh_time
;
2520 if ((circuit
->is_type
& level
) != level
2521 || (circuit
->state
!= C_STATE_UP
)
2522 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2523 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
2526 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2527 LSP_FRAGMENT(lsp_id
) = 0;
2528 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
2531 * If for some reason have a pseudo LSP in the db already -> regenerate
2533 if (lsp_search(lsp_id
, lspdb
))
2534 return lsp_regenerate_schedule_pseudo(circuit
, level
);
2536 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
2537 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2538 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
2539 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
2541 lsp
->area
= circuit
->area
;
2543 lsp_build_pseudo(lsp
, circuit
, level
);
2546 lsp_insert(lsp
, lspdb
);
2547 lsp_set_all_srmflags(lsp
);
2549 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
2550 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2551 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
2552 if (level
== IS_LEVEL_1
)
2554 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
2555 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2556 else if (level
== IS_LEVEL_2
)
2558 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
2559 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2561 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2563 "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2564 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2565 circuit
->area
->area_tag
, level
,
2566 rawlspid_print(lsp
->lsp_header
->lsp_id
),
2567 ntohl(lsp
->lsp_header
->pdu_len
),
2568 ntohl(lsp
->lsp_header
->seq_num
),
2569 ntohs(lsp
->lsp_header
->checksum
),
2570 ntohs(lsp
->lsp_header
->rem_lifetime
), refresh_time
);
2576 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
2578 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
2579 struct isis_lsp
*lsp
;
2580 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2581 u_int16_t rem_lifetime
, refresh_time
;
2583 if ((circuit
->is_type
& level
) != level
2584 || (circuit
->state
!= C_STATE_UP
)
2585 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2586 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
2589 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2590 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
2591 LSP_FRAGMENT(lsp_id
) = 0;
2593 lsp
= lsp_search(lsp_id
, lspdb
);
2596 zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
2597 rawlspid_print(lsp_id
));
2600 lsp_clear_data(lsp
);
2602 lsp_build_pseudo(lsp
, circuit
, level
);
2604 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2605 lsp
->lsp_header
->lsp_bits
=
2606 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
2607 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
2608 lsp
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
2609 lsp_inc_seqnum(lsp
, 0);
2610 lsp
->last_generated
= time(NULL
);
2611 lsp_set_all_srmflags(lsp
);
2613 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
2614 if (level
== IS_LEVEL_1
)
2616 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
2617 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2618 else if (level
== IS_LEVEL_2
)
2620 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
2621 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2623 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2625 "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2626 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2627 circuit
->area
->area_tag
, level
,
2628 rawlspid_print(lsp
->lsp_header
->lsp_id
),
2629 ntohl(lsp
->lsp_header
->pdu_len
),
2630 ntohl(lsp
->lsp_header
->seq_num
),
2631 ntohs(lsp
->lsp_header
->checksum
),
2632 ntohs(lsp
->lsp_header
->rem_lifetime
), refresh_time
);
2639 * Something has changed or periodic refresh -> regenerate pseudo LSP
2641 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
2643 struct isis_circuit
*circuit
;
2644 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2646 circuit
= THREAD_ARG(thread
);
2648 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
2649 circuit
->lsp_regenerate_pending
[0] = 0;
2651 if ((circuit
->u
.bc
.is_dr
[0] == 0)
2652 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
2653 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2654 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
2655 LSP_FRAGMENT(id
) = 0;
2656 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
2660 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
2663 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
2665 struct isis_circuit
*circuit
;
2666 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2668 circuit
= THREAD_ARG(thread
);
2670 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
2671 circuit
->lsp_regenerate_pending
[1] = 0;
2673 if ((circuit
->u
.bc
.is_dr
[1] == 0)
2674 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
2675 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2676 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
2677 LSP_FRAGMENT(id
) = 0;
2678 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
2682 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
2685 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
2687 struct isis_lsp
*lsp
;
2688 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2692 struct isis_area
*area
= circuit
->area
;
2694 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
2695 || circuit
->state
!= C_STATE_UP
)
2699 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2700 area
->area_tag
, circuit_t2string(level
),
2701 circuit
->interface
->name
);
2703 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2704 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
2705 LSP_FRAGMENT(lsp_id
) = 0;
2708 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
2710 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2711 area
->area_tag
, lvl
);
2713 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
2714 sched_debug("ISIS (%s): Level is not active on circuit",
2719 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
2721 "ISIS (%s): This IS is not DR, nothing to do.",
2726 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
2727 struct timeval remain
= thread_timer_remain(
2728 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2730 "ISIS (%s): Regenerate is already pending, nothing todo."
2731 " (Due in %lld.%03lld seconds)",
2732 area
->area_tag
, (long long)remain
.tv_sec
,
2733 (long long)remain
.tv_usec
/ 1000);
2737 lsp
= lsp_search(lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
2740 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2746 * Throttle avoidance
2749 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2750 area
->area_tag
, (long long)lsp
->last_generated
,
2752 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2753 diff
= now
- lsp
->last_generated
;
2754 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
2756 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
2759 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2760 area
->area_tag
, timeout
);
2764 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2765 " Scheduling for execution in %ld ms.",
2766 area
->area_tag
, timeout
);
2769 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
2771 if (lvl
== IS_LEVEL_1
) {
2772 thread_add_timer_msec(
2773 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
2774 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2775 } else if (lvl
== IS_LEVEL_2
) {
2776 thread_add_timer_msec(
2777 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
2778 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2786 * Walk through LSPs for an area
2787 * - set remaining lifetime
2788 * - set LSPs with SRMflag set for sending
2790 int lsp_tick(struct thread
*thread
)
2792 struct isis_area
*area
;
2793 struct isis_circuit
*circuit
;
2794 struct isis_lsp
*lsp
;
2795 struct list
*lsp_list
;
2796 struct listnode
*lspnode
, *cnode
;
2797 dnode_t
*dnode
, *dnode_next
;
2799 u_int16_t rem_lifetime
;
2801 lsp_list
= list_new();
2803 area
= THREAD_ARG(thread
);
2805 area
->t_tick
= NULL
;
2806 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
2809 * Build a list of LSPs with (any) SRMflag set
2810 * and removed the ones that have aged out
2812 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
2813 if (area
->lspdb
[level
] && dict_count(area
->lspdb
[level
]) > 0) {
2814 for (dnode
= dict_first(area
->lspdb
[level
]);
2815 dnode
!= NULL
; dnode
= dnode_next
) {
2817 dict_next(area
->lspdb
[level
], dnode
);
2818 lsp
= dnode_get(dnode
);
2821 * The lsp rem_lifetime is kept at 0 for MaxAge
2823 * ZeroAgeLifetime depending on explicit purge
2825 * natural age out. So schedule spf only once
2827 * the first time rem_lifetime becomes 0.
2830 ntohs(lsp
->lsp_header
->rem_lifetime
);
2834 * Schedule may run spf which should be done
2836 * the lsp rem_lifetime becomes 0 for the first
2838 * ISO 10589 - 7.3.16.4 first paragraph.
2840 if (rem_lifetime
== 1
2841 && lsp
->lsp_header
->seq_num
!= 0) {
2842 /* 7.3.16.4 a) set SRM flags on all */
2843 lsp_set_all_srmflags(lsp
);
2844 /* 7.3.16.4 b) retain only the header
2846 /* 7.3.16.4 c) record the time to purge
2848 /* run/schedule spf */
2849 /* isis_spf_schedule is called inside
2850 * lsp_destroy() below;
2851 * so it is not needed here. */
2852 /* isis_spf_schedule (lsp->area,
2856 if (lsp
->age_out
== 0) {
2858 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2859 area
->area_tag
, lsp
->level
,
2863 ntohl(lsp
->lsp_header
2867 dict_delete_free(area
->lspdb
[level
],
2869 } else if (flags_any_set(lsp
->SRMflags
))
2870 listnode_add(lsp_list
, lsp
);
2874 * Send LSPs on circuits indicated by the SRMflags
2876 if (listcount(lsp_list
) > 0) {
2877 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
2881 - circuit
->lsp_queue_last_cleared
;
2882 if (circuit
->lsp_queue
== NULL
2883 || diff
< MIN_LSP_TRANS_INTERVAL
)
2885 for (ALL_LIST_ELEMENTS_RO(
2886 lsp_list
, lspnode
, lsp
)) {
2887 if (circuit
->upadjcount
2892 /* Add the lsp only if
2893 * it is not already in
2896 if (!listnode_lookup(
2912 list_delete_all_node(lsp_list
);
2917 list_delete(lsp_list
);
2922 void lsp_purge_pseudo(u_char
*id
, struct isis_circuit
*circuit
, int level
)
2924 struct isis_lsp
*lsp
;
2928 lsp
= lsp_search(id
, circuit
->area
->lspdb
[level
- 1]);
2932 /* store old values */
2933 seq_num
= lsp
->lsp_header
->seq_num
;
2934 lsp_bits
= lsp
->lsp_header
->lsp_bits
;
2937 lsp_clear_data(lsp
);
2938 stream_reset(lsp
->pdu
);
2941 lsp
->lsp_header
->pdu_len
= htons(ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2942 memcpy(lsp
->lsp_header
->lsp_id
, id
, ISIS_SYS_ID_LEN
+ 2);
2943 lsp
->lsp_header
->checksum
= 0;
2944 lsp
->lsp_header
->seq_num
= seq_num
;
2945 lsp
->lsp_header
->rem_lifetime
= 0;
2946 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
2948 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
2949 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2952 * Add and update the authentication info if its present
2955 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
2956 lsp_auth_update(lsp
);
2957 fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
2958 ntohs(lsp
->lsp_header
->pdu_len
) - 12, 12);
2960 lsp_set_all_srmflags(lsp
);
2966 * Purge own LSP that is received and we don't have.
2967 * -> Do as in 7.3.16.4
2969 void lsp_purge_non_exist(int level
, struct isis_link_state_hdr
*lsp_hdr
,
2970 struct isis_area
*area
)
2972 struct isis_lsp
*lsp
;
2974 (level
== IS_LEVEL_1
) ? L1_LINK_STATE
: L2_LINK_STATE
;
2977 * We need to create the LSP to be purged
2979 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
2982 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
2983 fill_fixed_hdr(pdu_type
, lsp
->pdu
);
2985 lsp
->lsp_header
= (struct isis_link_state_hdr
*)(STREAM_DATA(lsp
->pdu
)
2986 + ISIS_FIXED_HDR_LEN
);
2987 memcpy(lsp
->lsp_header
, lsp_hdr
, ISIS_LSP_HDR_LEN
);
2988 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2991 * Set the remaining lifetime to 0
2993 lsp
->lsp_header
->rem_lifetime
= 0;
2996 * Add and update the authentication info if its present
2999 lsp_auth_update(lsp
);
3002 * Update the PDU length to header plus any authentication TLV.
3004 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
3007 * Put the lsp into LSPdb
3009 lsp_insert(lsp
, area
->lspdb
[lsp
->level
- 1]);
3012 * Send in to whole area
3014 lsp_set_all_srmflags(lsp
);
3019 void lsp_set_all_srmflags(struct isis_lsp
*lsp
)
3021 struct listnode
*node
;
3022 struct isis_circuit
*circuit
;
3026 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
3029 struct list
*circuit_list
= lsp
->area
->circuit_list
;
3030 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
3031 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);