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
->isis_header
= (struct isis_fixed_hdr
*)(STREAM_DATA(lsp
->pdu
));
472 lsp
->lsp_header
= (struct isis_link_state_hdr
*)(STREAM_DATA(lsp
->pdu
)
473 + ISIS_FIXED_HDR_LEN
);
476 lsp
->age_out
= ZERO_AGE_LIFETIME
;
477 lsp
->installed
= time(NULL
);
479 * Get LSP data i.e. TLVs
481 expected
|= TLVFLAG_AUTH_INFO
;
482 expected
|= TLVFLAG_AREA_ADDRS
;
483 expected
|= TLVFLAG_IS_NEIGHS
;
484 expected
|= TLVFLAG_NLPID
;
485 if (area
->dynhostname
)
486 expected
|= TLVFLAG_DYN_HOSTNAME
;
487 if (area
->newmetric
) {
488 expected
|= TLVFLAG_TE_IS_NEIGHS
;
489 expected
|= TLVFLAG_TE_IPV4_REACHABILITY
;
490 expected
|= TLVFLAG_TE_ROUTER_ID
;
492 expected
|= TLVFLAG_MT_ROUTER_INFORMATION
;
493 expected
|= TLVFLAG_IPV4_ADDR
;
494 expected
|= TLVFLAG_IPV4_INT_REACHABILITY
;
495 expected
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
496 expected
|= TLVFLAG_IPV6_ADDR
;
497 expected
|= TLVFLAG_IPV6_REACHABILITY
;
499 retval
= parse_tlvs(area
->area_tag
,
500 STREAM_DATA(lsp
->pdu
) + ISIS_FIXED_HDR_LEN
502 ntohs(lsp
->lsp_header
->pdu_len
) - ISIS_FIXED_HDR_LEN
504 &expected
, &found
, &lsp
->tlv_data
, NULL
);
505 if (retval
!= ISIS_OK
) {
506 zlog_warn("Could not parse LSP");
510 if ((found
& TLVFLAG_DYN_HOSTNAME
) && (area
->dynhostname
)) {
511 isis_dynhn_insert(lsp
->lsp_header
->lsp_id
,
512 lsp
->tlv_data
.hostname
,
513 (lsp
->lsp_header
->lsp_bits
& LSPBIT_IST
)
522 void lsp_update(struct isis_lsp
*lsp
, struct stream
*stream
,
523 struct isis_area
*area
, int level
)
525 dnode_t
*dnode
= NULL
;
527 /* Remove old LSP from database. This is required since the
528 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
529 * and will update it with the new data in the stream. */
530 dnode
= dict_lookup(area
->lspdb
[level
- 1], lsp
->lsp_header
->lsp_id
);
532 dnode_destroy(dict_delete(area
->lspdb
[level
- 1], dnode
));
536 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
538 rawlspid_print(lsp
->lsp_header
->lsp_id
));
543 /* rebuild the lsp data */
544 lsp_update_data(lsp
, stream
, area
, level
);
546 /* insert the lsp back into the database */
547 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
550 /* creation of LSP directly from what we received */
551 struct isis_lsp
*lsp_new_from_stream_ptr(struct stream
*stream
,
553 struct isis_lsp
*lsp0
,
554 struct isis_area
*area
, int level
)
556 struct isis_lsp
*lsp
;
558 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
559 lsp_update_data(lsp
, stream
, area
, level
);
563 * zero lsp -> create the list for fragments
565 lsp
->lspu
.frags
= list_new();
568 * a fragment -> set the backpointer and add this to zero lsps
571 lsp
->lspu
.zero_lsp
= lsp0
;
572 listnode_add(lsp0
->lspu
.frags
, lsp
);
578 struct isis_lsp
*lsp_new(struct isis_area
*area
, u_char
*lsp_id
,
579 u_int16_t rem_lifetime
, u_int32_t seq_num
,
580 u_int8_t lsp_bits
, u_int16_t checksum
, int level
)
582 struct isis_lsp
*lsp
;
584 lsp
= XCALLOC(MTYPE_ISIS_LSP
, sizeof(struct isis_lsp
));
587 lsp
->pdu
= stream_new(LLC_LEN
+ area
->lsp_mtu
);
588 if (LSP_FRAGMENT(lsp_id
) == 0)
589 lsp
->lspu
.frags
= list_new();
590 lsp
->isis_header
= (struct isis_fixed_hdr
*)(STREAM_DATA(lsp
->pdu
));
591 lsp
->lsp_header
= (struct isis_link_state_hdr
*)(STREAM_DATA(lsp
->pdu
)
592 + ISIS_FIXED_HDR_LEN
);
594 /* at first we fill the FIXED HEADER */
595 (level
== IS_LEVEL_1
) ? fill_fixed_hdr(lsp
->isis_header
, L1_LINK_STATE
)
596 : fill_fixed_hdr(lsp
->isis_header
, L2_LINK_STATE
);
598 /* now for the LSP HEADER */
599 /* Minimal LSP PDU size */
600 lsp
->lsp_header
->pdu_len
= htons(ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
601 memcpy(lsp
->lsp_header
->lsp_id
, lsp_id
, ISIS_SYS_ID_LEN
+ 2);
602 lsp
->lsp_header
->checksum
= checksum
; /* Provided in network order */
603 lsp
->lsp_header
->seq_num
= htonl(seq_num
);
604 lsp
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
605 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
607 lsp
->age_out
= ZERO_AGE_LIFETIME
;
609 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
611 if (isis
->debugs
& DEBUG_EVENTS
)
612 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
614 LSP_PSEUDO_ID(lsp
->lsp_header
->lsp_id
),
615 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
),
616 ntohl(lsp
->lsp_header
->pdu_len
),
617 ntohl(lsp
->lsp_header
->seq_num
));
622 void lsp_insert(struct isis_lsp
*lsp
, dict_t
*lspdb
)
624 dict_alloc_insert(lspdb
, lsp
->lsp_header
->lsp_id
, lsp
);
625 if (lsp
->lsp_header
->seq_num
!= 0) {
626 isis_spf_schedule(lsp
->area
, lsp
->level
);
631 * Build a list of LSPs with non-zero ht bounded by start and stop ids
633 void lsp_build_list_nonzero_ht(u_char
*start_id
, u_char
*stop_id
,
634 struct list
*list
, dict_t
*lspdb
)
636 dnode_t
*first
, *last
, *curr
;
638 first
= dict_lower_bound(lspdb
, start_id
);
642 last
= dict_upper_bound(lspdb
, stop_id
);
646 if (((struct isis_lsp
*)(curr
->dict_data
))->lsp_header
->rem_lifetime
)
647 listnode_add(list
, first
->dict_data
);
650 curr
= dict_next(lspdb
, curr
);
652 && ((struct isis_lsp
*)(curr
->dict_data
))
653 ->lsp_header
->rem_lifetime
)
654 listnode_add(list
, curr
->dict_data
);
663 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
665 void lsp_build_list(u_char
*start_id
, u_char
*stop_id
, u_char num_lsps
,
666 struct list
*list
, dict_t
*lspdb
)
669 dnode_t
*first
, *last
, *curr
;
671 first
= dict_lower_bound(lspdb
, start_id
);
675 last
= dict_upper_bound(lspdb
, stop_id
);
679 listnode_add(list
, first
->dict_data
);
683 curr
= dict_next(lspdb
, curr
);
685 listnode_add(list
, curr
->dict_data
);
688 if (count
== num_lsps
|| curr
== last
)
696 * Build a list of LSPs with SSN flag set for the given circuit
698 void lsp_build_list_ssn(struct isis_circuit
*circuit
, u_char num_lsps
,
699 struct list
*list
, dict_t
*lspdb
)
701 dnode_t
*dnode
, *next
;
702 struct isis_lsp
*lsp
;
705 dnode
= dict_first(lspdb
);
706 while (dnode
!= NULL
) {
707 next
= dict_next(lspdb
, dnode
);
708 lsp
= dnode_get(dnode
);
709 if (ISIS_CHECK_FLAG(lsp
->SSNflags
, circuit
)) {
710 listnode_add(list
, lsp
);
713 if (count
== num_lsps
)
721 static void lsp_set_time(struct isis_lsp
*lsp
)
725 if (lsp
->lsp_header
->rem_lifetime
== 0) {
726 if (lsp
->age_out
> 0)
731 lsp
->lsp_header
->rem_lifetime
=
732 htons(ntohs(lsp
->lsp_header
->rem_lifetime
) - 1);
735 static void lspid_print(u_char
*lsp_id
, u_char
*trg
, char dynhost
, char frag
)
737 struct isis_dynhn
*dyn
= NULL
;
738 u_char id
[SYSID_STRLEN
];
741 dyn
= dynhn_find_by_id(lsp_id
);
746 sprintf((char *)id
, "%.14s", dyn
->name
.name
);
747 else if (!memcmp(isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) && dynhost
)
748 sprintf((char *)id
, "%.14s", unix_hostname());
750 memcpy(id
, sysid_print(lsp_id
), 15);
752 sprintf((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID(lsp_id
),
753 LSP_FRAGMENT(lsp_id
));
755 sprintf((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID(lsp_id
));
758 /* Convert the lsp attribute bits to attribute string */
759 const char *lsp_bits2string(u_char
*lsp_bits
)
761 char *pos
= lsp_bits_string
;
766 /* we only focus on the default metric */
767 pos
+= sprintf(pos
, "%d/",
768 ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits
) ? 1 : 0);
770 pos
+= sprintf(pos
, "%d/",
771 ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits
) ? 1 : 0);
773 pos
+= sprintf(pos
, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits
) ? 1 : 0);
777 return lsp_bits_string
;
780 /* this function prints the lsp on show isis database */
781 void lsp_print(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
786 lspid_print(lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
787 vty_out(vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
788 vty_out(vty
, "%5u ", ntohs(lsp
->lsp_header
->pdu_len
));
789 vty_out(vty
, "0x%08x ", ntohl(lsp
->lsp_header
->seq_num
));
790 vty_out(vty
, "0x%04x ", ntohs(lsp
->lsp_header
->checksum
));
791 if (ntohs(lsp
->lsp_header
->rem_lifetime
) == 0) {
792 snprintf(age_out
, 8, "(%u)", lsp
->age_out
);
794 vty_out(vty
, "%7s ", age_out
);
796 vty_out(vty
, " %5u ", ntohs(lsp
->lsp_header
->rem_lifetime
));
797 vty_out(vty
, "%s\n", lsp_bits2string(&lsp
->lsp_header
->lsp_bits
));
800 static void lsp_print_mt_reach(struct list
*list
, struct vty
*vty
, char dynhost
,
803 struct listnode
*node
;
804 struct te_is_neigh
*neigh
;
806 for (ALL_LIST_ELEMENTS_RO(list
, node
, neigh
)) {
809 lspid_print(neigh
->neigh_id
, lspid
, dynhost
, 0);
810 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
812 " Metric : %-8u IS-Extended : %s\n",
813 GET_TE_METRIC(neigh
), lspid
);
816 " Metric : %-8u MT-Reach : %s %s\n",
817 GET_TE_METRIC(neigh
), lspid
,
818 isis_mtid2str(mtid
));
820 if (IS_MPLS_TE(isisMplsTE
))
821 mpls_te_print_detail(vty
, neigh
);
825 static void lsp_print_mt_ipv6_reach(struct list
*list
, struct vty
*vty
,
828 struct listnode
*node
;
829 struct ipv6_reachability
*ipv6_reach
;
833 for (ALL_LIST_ELEMENTS_RO(list
, node
, ipv6_reach
)) {
834 memset(&in6
, 0, sizeof(in6
));
835 memcpy(in6
.s6_addr
, ipv6_reach
->prefix
,
836 PSIZE(ipv6_reach
->prefix_len
));
837 inet_ntop(AF_INET6
, &in6
, (char *)buff
, BUFSIZ
);
838 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
839 if ((ipv6_reach
->control_info
& CTRL_INFO_DISTRIBUTION
)
840 == DISTRIBUTION_INTERNAL
)
841 vty_out(vty
, " Metric : %-8" PRIu32
842 " IPv6-Internal : %s/%d\n",
843 ntohl(ipv6_reach
->metric
), buff
,
844 ipv6_reach
->prefix_len
);
846 vty_out(vty
, " Metric : %-8" PRIu32
847 " IPv6-External : %s/%d\n",
848 ntohl(ipv6_reach
->metric
), buff
,
849 ipv6_reach
->prefix_len
);
851 if ((ipv6_reach
->control_info
& CTRL_INFO_DISTRIBUTION
)
852 == DISTRIBUTION_INTERNAL
)
853 vty_out(vty
, " Metric : %-8" PRIu32
854 " IPv6-MT-Int : %s/%d %s\n",
855 ntohl(ipv6_reach
->metric
), buff
,
856 ipv6_reach
->prefix_len
,
857 isis_mtid2str(mtid
));
859 vty_out(vty
, " Metric : %-8" PRIu32
860 " IPv6-MT-Ext : %s/%d %s\n",
861 ntohl(ipv6_reach
->metric
), buff
,
862 ipv6_reach
->prefix_len
,
863 isis_mtid2str(mtid
));
868 static void lsp_print_mt_ipv4_reach(struct list
*list
, struct vty
*vty
,
871 struct listnode
*node
;
872 struct te_ipv4_reachability
*te_ipv4_reach
;
874 for (ALL_LIST_ELEMENTS_RO(list
, node
, te_ipv4_reach
)) {
875 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
876 /* FIXME: There should be better way to output this
878 vty_out(vty
, " Metric : %-8" PRIu32
879 " IPv4-Extended : %s/%d\n",
880 ntohl(te_ipv4_reach
->te_metric
),
881 inet_ntoa(newprefix2inaddr(
882 &te_ipv4_reach
->prefix_start
,
883 te_ipv4_reach
->control
)),
884 te_ipv4_reach
->control
& 0x3F);
886 /* FIXME: There should be better way to output this
888 vty_out(vty
, " Metric : %-8" PRIu32
889 " IPv4-MT : %s/%d %s\n",
890 ntohl(te_ipv4_reach
->te_metric
),
891 inet_ntoa(newprefix2inaddr(
892 &te_ipv4_reach
->prefix_start
,
893 te_ipv4_reach
->control
)),
894 te_ipv4_reach
->control
& 0x3F,
895 isis_mtid2str(mtid
));
900 void lsp_print_detail(struct isis_lsp
*lsp
, struct vty
*vty
, char dynhost
)
902 struct area_addr
*area_addr
;
904 struct listnode
*lnode
;
905 struct is_neigh
*is_neigh
;
906 struct ipv4_reachability
*ipv4_reach
;
907 struct in_addr
*ipv4_addr
;
908 struct mt_router_info
*mt_router_info
;
909 struct tlv_mt_ipv6_reachs
*mt_ipv6_reachs
;
910 struct tlv_mt_neighbors
*mt_is_neigh
;
911 struct tlv_mt_ipv4_reachs
*mt_ipv4_reachs
;
913 u_char hostname
[255];
914 u_char ipv4_reach_prefix
[20];
915 u_char ipv4_reach_mask
[20];
916 u_char ipv4_address
[20];
918 lspid_print(lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
919 lsp_print(lsp
, vty
, dynhost
);
921 /* for all area address */
922 if (lsp
->tlv_data
.area_addrs
)
923 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.area_addrs
, lnode
,
925 vty_out(vty
, " Area Address: %s\n",
926 isonet_print(area_addr
->area_addr
,
927 area_addr
->addr_len
));
930 /* for the nlpid tlv */
931 if (lsp
->tlv_data
.nlpids
) {
932 for (i
= 0; i
< lsp
->tlv_data
.nlpids
->count
; i
++) {
933 switch (lsp
->tlv_data
.nlpids
->nlpids
[i
]) {
936 vty_out(vty
, " NLPID : 0x%X\n",
937 lsp
->tlv_data
.nlpids
->nlpids
[i
]);
940 vty_out(vty
, " NLPID : %s\n", "unknown");
946 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_router_info
, lnode
,
948 vty_out(vty
, " MT : %s%s\n",
949 isis_mtid2str(mt_router_info
->mtid
),
950 mt_router_info
->overload
? " (overload)" : "");
953 /* for the hostname tlv */
954 if (lsp
->tlv_data
.hostname
) {
955 bzero(hostname
, sizeof(hostname
));
956 memcpy(hostname
, lsp
->tlv_data
.hostname
->name
,
957 lsp
->tlv_data
.hostname
->namelen
);
958 vty_out(vty
, " Hostname : %s\n", hostname
);
961 /* authentication tlv */
962 if (lsp
->tlv_data
.auth_info
.type
!= ISIS_PASSWD_TYPE_UNUSED
) {
963 if (lsp
->tlv_data
.auth_info
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
964 vty_out(vty
, " Auth type : md5\n");
965 else if (lsp
->tlv_data
.auth_info
.type
966 == ISIS_PASSWD_TYPE_CLEARTXT
)
967 vty_out(vty
, " Auth type : clear text\n");
971 if (lsp
->tlv_data
.router_id
) {
972 memcpy(ipv4_address
, inet_ntoa(lsp
->tlv_data
.router_id
->id
),
973 sizeof(ipv4_address
));
974 vty_out(vty
, " Router ID : %s\n", ipv4_address
);
977 if (lsp
->tlv_data
.ipv4_addrs
)
978 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.ipv4_addrs
, lnode
,
980 memcpy(ipv4_address
, inet_ntoa(*ipv4_addr
),
981 sizeof(ipv4_address
));
982 vty_out(vty
, " IPv4 Address: %s\n", ipv4_address
);
985 /* for the IS neighbor tlv */
986 if (lsp
->tlv_data
.is_neighs
)
987 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.is_neighs
, lnode
,
989 lspid_print(is_neigh
->neigh_id
, LSPid
, dynhost
, 0);
990 vty_out(vty
, " Metric : %-8" PRIu8
992 is_neigh
->metrics
.metric_default
, LSPid
);
995 /* for the internal reachable tlv */
996 if (lsp
->tlv_data
.ipv4_int_reachs
)
997 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.ipv4_int_reachs
, lnode
,
999 memcpy(ipv4_reach_prefix
, inet_ntoa(ipv4_reach
->prefix
),
1000 sizeof(ipv4_reach_prefix
));
1001 memcpy(ipv4_reach_mask
, inet_ntoa(ipv4_reach
->mask
),
1002 sizeof(ipv4_reach_mask
));
1003 vty_out(vty
, " Metric : %-8" PRIu8
1004 " IPv4-Internal : %s %s\n",
1005 ipv4_reach
->metrics
.metric_default
,
1006 ipv4_reach_prefix
, ipv4_reach_mask
);
1009 /* for the external reachable tlv */
1010 if (lsp
->tlv_data
.ipv4_ext_reachs
)
1011 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.ipv4_ext_reachs
, lnode
,
1013 memcpy(ipv4_reach_prefix
, inet_ntoa(ipv4_reach
->prefix
),
1014 sizeof(ipv4_reach_prefix
));
1015 memcpy(ipv4_reach_mask
, inet_ntoa(ipv4_reach
->mask
),
1016 sizeof(ipv4_reach_mask
));
1017 vty_out(vty
, " Metric : %-8" PRIu8
1018 " IPv4-External : %s %s\n",
1019 ipv4_reach
->metrics
.metric_default
,
1020 ipv4_reach_prefix
, ipv4_reach_mask
);
1024 lsp_print_mt_ipv6_reach(lsp
->tlv_data
.ipv6_reachs
, vty
,
1025 ISIS_MT_IPV4_UNICAST
);
1027 /* MT IPv6 reachability tlv */
1028 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_ipv6_reachs
, lnode
,
1030 lsp_print_mt_ipv6_reach(mt_ipv6_reachs
->list
, vty
,
1031 mt_ipv6_reachs
->mtid
);
1033 /* TE IS neighbor tlv */
1034 lsp_print_mt_reach(lsp
->tlv_data
.te_is_neighs
, vty
, dynhost
,
1035 ISIS_MT_IPV4_UNICAST
);
1037 /* MT IS neighbor tlv */
1038 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_is_neighs
, lnode
,
1040 lsp_print_mt_reach(mt_is_neigh
->list
, vty
, dynhost
,
1044 lsp_print_mt_ipv4_reach(lsp
->tlv_data
.te_ipv4_reachs
, vty
,
1045 ISIS_MT_IPV4_UNICAST
);
1047 /* MT IPv4 reachability tlv */
1048 for (ALL_LIST_ELEMENTS_RO(lsp
->tlv_data
.mt_ipv4_reachs
, lnode
,
1050 lsp_print_mt_ipv4_reach(mt_ipv4_reachs
->list
, vty
,
1051 mt_ipv4_reachs
->mtid
);
1058 /* print all the lsps info in the local lspdb */
1059 int lsp_print_all(struct vty
*vty
, dict_t
*lspdb
, char detail
, char dynhost
)
1062 dnode_t
*node
= dict_first(lspdb
), *next
;
1065 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
1066 while (node
!= NULL
) {
1067 /* I think it is unnecessary, so I comment it out */
1068 /* dict_contains (lspdb, node); */
1069 next
= dict_next(lspdb
, node
);
1070 lsp_print(dnode_get(node
), vty
, dynhost
);
1074 } else if (detail
== ISIS_UI_LEVEL_DETAIL
) {
1075 while (node
!= NULL
) {
1076 next
= dict_next(lspdb
, node
);
1077 lsp_print_detail(dnode_get(node
), vty
, dynhost
);
1086 static void _lsp_tlv_fit(struct isis_lsp
*lsp
, struct list
**from
,
1087 struct list
**to
, int frag_thold
,
1088 unsigned int tlv_build_func(struct list
*,
1093 while (*from
&& listcount(*from
)) {
1096 count
= tlv_build_func(*from
, lsp
->pdu
, arg
);
1098 if (listcount(*to
) != 0 || count
!= listcount(*from
)) {
1099 struct listnode
*node
, *nnode
;
1102 for (ALL_LIST_ELEMENTS(*from
, node
, nnode
, elem
)) {
1105 listnode_add(*to
, elem
);
1106 list_delete_node(*from
, node
);
1117 #define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100)
1119 /* stream*, area->lsp_frag_threshold, increment */
1120 #define FRAG_NEEDED(S, T, I) \
1121 (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T))
1123 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1124 * variable length (TE TLVs, sub TLVs). */
1125 static void lsp_tlv_fit(struct isis_lsp
*lsp
, struct list
**from
,
1126 struct list
**to
, int tlvsize
, int frag_thold
,
1127 int tlv_build_func(struct list
*, struct stream
*))
1131 /* can we fit all ? */
1132 if (!FRAG_NEEDED(lsp
->pdu
, frag_thold
,
1133 listcount(*from
) * tlvsize
+ 2)) {
1134 tlv_build_func(*from
, lsp
->pdu
);
1135 if (listcount(*to
) != 0) {
1136 struct listnode
*node
, *nextnode
;
1139 for (ALL_LIST_ELEMENTS(*from
, node
, nextnode
, elem
)) {
1140 listnode_add(*to
, elem
);
1141 list_delete_node(*from
, node
);
1148 } else if (!FRAG_NEEDED(lsp
->pdu
, frag_thold
, tlvsize
+ 2)) {
1149 /* fit all we can */
1150 count
= FRAG_THOLD(lsp
->pdu
, frag_thold
) - 2
1151 - (STREAM_SIZE(lsp
->pdu
) - STREAM_REMAIN(lsp
->pdu
));
1152 count
= count
/ tlvsize
;
1153 if (count
> (int)listcount(*from
))
1154 count
= listcount(*from
);
1155 for (i
= 0; i
< count
; i
++) {
1156 listnode_add(*to
, listgetdata(listhead(*from
)));
1157 listnode_delete(*from
, listgetdata(listhead(*from
)));
1159 tlv_build_func(*to
, lsp
->pdu
);
1161 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
1165 static u_int16_t
lsp_rem_lifetime(struct isis_area
*area
, int level
)
1167 u_int16_t rem_lifetime
;
1169 /* Add jitter to configured LSP lifetime */
1171 isis_jitter(area
->max_lsp_lifetime
[level
- 1], MAX_AGE_JITTER
);
1173 /* No jitter if the max refresh will be less than configure gen interval
1175 /* N.B. this calucation is acceptable since rem_lifetime is in
1178 if (area
->lsp_gen_interval
[level
- 1] > (rem_lifetime
- 300))
1179 rem_lifetime
= area
->max_lsp_lifetime
[level
- 1];
1181 return rem_lifetime
;
1184 static u_int16_t
lsp_refresh_time(struct isis_lsp
*lsp
, u_int16_t rem_lifetime
)
1186 struct isis_area
*area
= lsp
->area
;
1187 int level
= lsp
->level
;
1188 u_int16_t refresh_time
;
1190 /* Add jitter to LSP refresh time */
1192 isis_jitter(area
->lsp_refresh
[level
- 1], MAX_LSP_GEN_JITTER
);
1194 /* RFC 4444 : make sure the refresh time is at least less than 300
1195 * of the remaining lifetime and more than gen interval */
1196 if (refresh_time
<= area
->lsp_gen_interval
[level
- 1]
1197 || refresh_time
> (rem_lifetime
- 300))
1198 refresh_time
= rem_lifetime
- 300;
1200 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1201 * we accept this violation to satisfy refresh_time <= rem_lifetime -
1204 return refresh_time
;
1207 static struct isis_lsp
*lsp_next_frag(u_char frag_num
, struct isis_lsp
*lsp0
,
1208 struct isis_area
*area
, int level
)
1210 struct isis_lsp
*lsp
;
1211 u_char frag_id
[ISIS_SYS_ID_LEN
+ 2];
1213 memcpy(frag_id
, lsp0
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1214 LSP_FRAGMENT(frag_id
) = frag_num
;
1215 /* FIXME add authentication TLV for fragment LSPs */
1216 lsp
= lsp_search(frag_id
, area
->lspdb
[level
- 1]);
1218 /* Clear the TLVs */
1219 lsp_clear_data(lsp
);
1222 lsp
= lsp_new(area
, frag_id
, ntohs(lsp0
->lsp_header
->rem_lifetime
), 0,
1223 lsp_bits_generate(level
, area
->overload_bit
,
1224 area
->attached_bit
),
1228 lsp_insert(lsp
, area
->lspdb
[level
- 1]);
1229 listnode_add(lsp0
->lspu
.frags
, lsp
);
1230 lsp
->lspu
.zero_lsp
= lsp0
;
1234 static void lsp_build_ext_reach_ipv4(struct isis_lsp
*lsp
,
1235 struct isis_area
*area
,
1236 struct tlvs
*tlv_data
)
1238 struct route_table
*er_table
;
1239 struct route_node
*rn
;
1240 struct prefix_ipv4
*ipv4
;
1241 struct isis_ext_info
*info
;
1242 struct ipv4_reachability
*ipreach
;
1243 struct te_ipv4_reachability
*te_ipreach
;
1245 er_table
= get_ext_reach(area
, AF_INET
, lsp
->level
);
1249 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
)) {
1253 ipv4
= (struct prefix_ipv4
*)&rn
->p
;
1255 if (area
->oldmetric
) {
1256 if (tlv_data
->ipv4_ext_reachs
== NULL
) {
1257 tlv_data
->ipv4_ext_reachs
= list_new();
1258 tlv_data
->ipv4_ext_reachs
->del
= free_tlv
;
1260 ipreach
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*ipreach
));
1262 ipreach
->prefix
.s_addr
= ipv4
->prefix
.s_addr
;
1263 masklen2ip(ipv4
->prefixlen
, &ipreach
->mask
);
1264 ipreach
->prefix
.s_addr
&= ipreach
->mask
.s_addr
;
1266 if ((info
->metric
& 0x3f) != info
->metric
)
1267 ipreach
->metrics
.metric_default
= 0x3f;
1269 ipreach
->metrics
.metric_default
= info
->metric
;
1270 ipreach
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1271 ipreach
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1272 ipreach
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1273 listnode_add(tlv_data
->ipv4_ext_reachs
, ipreach
);
1275 if (area
->newmetric
) {
1276 if (tlv_data
->te_ipv4_reachs
== NULL
) {
1277 tlv_data
->te_ipv4_reachs
= list_new();
1278 tlv_data
->te_ipv4_reachs
->del
= free_tlv
;
1280 te_ipreach
= XCALLOC(MTYPE_ISIS_TLV
,
1281 sizeof(*te_ipreach
) - 1
1282 + PSIZE(ipv4
->prefixlen
));
1283 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1284 te_ipreach
->te_metric
=
1285 htonl(MAX_WIDE_PATH_METRIC
);
1287 te_ipreach
->te_metric
= htonl(info
->metric
);
1288 te_ipreach
->control
= ipv4
->prefixlen
& 0x3f;
1289 memcpy(&te_ipreach
->prefix_start
, &ipv4
->prefix
.s_addr
,
1290 PSIZE(ipv4
->prefixlen
));
1291 listnode_add(tlv_data
->te_ipv4_reachs
, te_ipreach
);
1296 static struct list
*tlv_get_ipv6_reach_list(struct isis_area
*area
,
1297 struct tlvs
*tlv_data
)
1299 uint16_t mtid
= isis_area_ipv6_topology(area
);
1300 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1301 if (!tlv_data
->ipv6_reachs
) {
1302 tlv_data
->ipv6_reachs
= list_new();
1303 tlv_data
->ipv6_reachs
->del
= free_tlv
;
1305 return tlv_data
->ipv6_reachs
;
1308 struct tlv_mt_ipv6_reachs
*reachs
=
1309 tlvs_get_mt_ipv6_reachs(tlv_data
, mtid
);
1310 return reachs
->list
;
1313 static void lsp_build_ext_reach_ipv6(struct isis_lsp
*lsp
,
1314 struct isis_area
*area
,
1315 struct tlvs
*tlv_data
)
1317 struct route_table
*er_table
;
1318 struct route_node
*rn
;
1319 struct prefix_ipv6
*ipv6
;
1320 struct isis_ext_info
*info
;
1321 struct ipv6_reachability
*ip6reach
;
1322 struct list
*reach_list
= NULL
;
1324 er_table
= get_ext_reach(area
, AF_INET6
, lsp
->level
);
1328 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
)) {
1332 ipv6
= (struct prefix_ipv6
*)&rn
->p
;
1336 reach_list
= tlv_get_ipv6_reach_list(area
, tlv_data
);
1338 ip6reach
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ip6reach
));
1339 if (info
->metric
> MAX_WIDE_PATH_METRIC
)
1340 ip6reach
->metric
= htonl(MAX_WIDE_PATH_METRIC
);
1342 ip6reach
->metric
= htonl(info
->metric
);
1343 ip6reach
->control_info
= DISTRIBUTION_EXTERNAL
;
1344 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1345 memcpy(ip6reach
->prefix
, ipv6
->prefix
.s6_addr
,
1346 sizeof(ip6reach
->prefix
));
1347 listnode_add(reach_list
, ip6reach
);
1351 static void lsp_build_ext_reach(struct isis_lsp
*lsp
, struct isis_area
*area
,
1352 struct tlvs
*tlv_data
)
1354 lsp_build_ext_reach_ipv4(lsp
, area
, tlv_data
);
1355 lsp_build_ext_reach_ipv6(lsp
, area
, tlv_data
);
1359 * Builds the LSP data part. This func creates a new frag whenever
1360 * area->lsp_frag_threshold is exceeded.
1362 static void lsp_build(struct isis_lsp
*lsp
, struct isis_area
*area
)
1364 struct is_neigh
*is_neigh
;
1365 struct te_is_neigh
*te_is_neigh
;
1366 struct listnode
*node
, *ipnode
;
1367 int level
= lsp
->level
;
1368 struct isis_circuit
*circuit
;
1369 struct prefix_ipv4
*ipv4
;
1370 struct ipv4_reachability
*ipreach
;
1371 struct te_ipv4_reachability
*te_ipreach
;
1372 struct isis_adjacency
*nei
;
1373 struct prefix_ipv6
*ipv6
, ip6prefix
;
1374 struct list
*ipv6_reachs
= NULL
;
1375 struct ipv6_reachability
*ip6reach
;
1376 struct tlvs tlv_data
;
1377 struct isis_lsp
*lsp0
= lsp
;
1378 struct in_addr
*routerid
;
1379 uint32_t expected
= 0, found
= 0;
1381 u_char zero_id
[ISIS_SYS_ID_LEN
+ 1];
1382 int retval
= ISIS_OK
;
1385 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1386 area
->area_tag
, level
);
1389 * Building the zero lsp
1391 memset(zero_id
, 0, ISIS_SYS_ID_LEN
+ 1);
1393 /* Reset stream endp. Stream is always there and on every LSP refresh
1395 * TLV part of it is overwritten. So we must seek past header we will
1398 stream_reset(lsp
->pdu
);
1399 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
1402 * Add the authentication info if its present
1407 * First add the tlvs related to area
1410 /* Area addresses */
1411 if (lsp
->tlv_data
.area_addrs
== NULL
)
1412 lsp
->tlv_data
.area_addrs
= list_new();
1413 list_add_list(lsp
->tlv_data
.area_addrs
, area
->area_addrs
);
1414 if (listcount(lsp
->tlv_data
.area_addrs
) > 0)
1415 tlv_add_area_addrs(lsp
->tlv_data
.area_addrs
, lsp
->pdu
);
1417 /* Protocols Supported */
1418 if (area
->ip_circuits
> 0 || area
->ipv6_circuits
> 0) {
1419 lsp
->tlv_data
.nlpids
=
1420 XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct nlpids
));
1421 lsp
->tlv_data
.nlpids
->count
= 0;
1422 if (area
->ip_circuits
> 0) {
1424 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1426 lsp
->tlv_data
.nlpids
->count
++;
1427 lsp
->tlv_data
.nlpids
->nlpids
[0] = NLPID_IP
;
1429 if (area
->ipv6_circuits
> 0) {
1431 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1433 lsp
->tlv_data
.nlpids
->count
++;
1434 lsp
->tlv_data
.nlpids
1435 ->nlpids
[lsp
->tlv_data
.nlpids
->count
- 1] =
1438 tlv_add_nlpid(lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1441 if (area_is_mt(area
)) {
1442 lsp_debug("ISIS (%s): Adding MT router tlv...", area
->area_tag
);
1443 lsp
->tlv_data
.mt_router_info
= list_new();
1444 lsp
->tlv_data
.mt_router_info
->del
= free_tlv
;
1446 struct isis_area_mt_setting
**mt_settings
;
1447 unsigned int mt_count
;
1449 mt_settings
= area_mt_settings(area
, &mt_count
);
1450 for (unsigned int i
= 0; i
< mt_count
; i
++) {
1451 struct mt_router_info
*info
;
1453 info
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*info
));
1454 info
->mtid
= mt_settings
[i
]->mtid
;
1455 info
->overload
= mt_settings
[i
]->overload
;
1456 listnode_add(lsp
->tlv_data
.mt_router_info
, info
);
1457 lsp_debug("ISIS (%s): MT %s", area
->area_tag
,
1458 isis_mtid2str(info
->mtid
));
1460 tlv_add_mt_router_info(lsp
->tlv_data
.mt_router_info
, lsp
->pdu
);
1462 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
1465 /* Dynamic Hostname */
1466 if (area
->dynhostname
) {
1467 const char *hostname
= unix_hostname();
1468 size_t hostname_len
= strlen(hostname
);
1470 lsp
->tlv_data
.hostname
=
1471 XMALLOC(MTYPE_ISIS_TLV
, sizeof(struct hostname
));
1473 strncpy((char *)lsp
->tlv_data
.hostname
->name
, hostname
,
1474 sizeof(lsp
->tlv_data
.hostname
->name
));
1475 if (hostname_len
<= MAX_TLV_LEN
)
1476 lsp
->tlv_data
.hostname
->namelen
= hostname_len
;
1478 lsp
->tlv_data
.hostname
->namelen
= MAX_TLV_LEN
;
1480 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'",
1481 area
->area_tag
, lsp
->tlv_data
.hostname
->namelen
,
1482 lsp
->tlv_data
.hostname
->name
);
1483 tlv_add_dynamic_hostname(lsp
->tlv_data
.hostname
, lsp
->pdu
);
1485 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1489 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1490 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
1492 * LSP and this address is same as router id. */
1493 if (isis
->router_id
!= 0) {
1494 inet_ntop(AF_INET
, &isis
->router_id
, buf
, sizeof(buf
));
1495 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
1496 area
->area_tag
, buf
);
1497 if (lsp
->tlv_data
.ipv4_addrs
== NULL
) {
1498 lsp
->tlv_data
.ipv4_addrs
= list_new();
1499 lsp
->tlv_data
.ipv4_addrs
->del
= free_tlv
;
1502 routerid
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(struct in_addr
));
1503 routerid
->s_addr
= isis
->router_id
;
1504 listnode_add(lsp
->tlv_data
.ipv4_addrs
, routerid
);
1505 tlv_add_in_addr(routerid
, lsp
->pdu
, IPV4_ADDR
);
1507 /* Exactly same data is put into TE router ID TLV, but only if
1509 * TLV's are in use. */
1510 if (area
->newmetric
) {
1512 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1514 lsp
->tlv_data
.router_id
=
1515 XMALLOC(MTYPE_ISIS_TLV
, sizeof(struct in_addr
));
1516 lsp
->tlv_data
.router_id
->id
.s_addr
= isis
->router_id
;
1517 tlv_add_in_addr(&lsp
->tlv_data
.router_id
->id
, lsp
->pdu
,
1521 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1525 memset(&tlv_data
, 0, sizeof(struct tlvs
));
1527 lsp_debug("ISIS (%s): Adding circuit specific information.",
1531 * Then build lists of tlvs related to circuits
1533 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
1534 if (!circuit
->interface
)
1536 "ISIS (%s): Processing %s circuit %p with unknown interface",
1538 circuit_type2string(circuit
->circ_type
),
1541 lsp_debug("ISIS (%s): Processing %s circuit %s",
1543 circuit_type2string(circuit
->circ_type
),
1544 circuit
->interface
->name
);
1546 if (circuit
->state
!= C_STATE_UP
) {
1547 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1553 * Add IPv4 internal reachability of this circuit
1555 if (circuit
->ip_router
&& circuit
->ip_addrs
1556 && circuit
->ip_addrs
->count
> 0) {
1558 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1560 if (area
->oldmetric
) {
1561 if (tlv_data
.ipv4_int_reachs
== NULL
) {
1562 tlv_data
.ipv4_int_reachs
= list_new();
1563 tlv_data
.ipv4_int_reachs
->del
=
1566 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
,
1571 ipv4_reachability
));
1572 ipreach
->metrics
.metric_default
=
1573 circuit
->metric
[level
- 1];
1574 ipreach
->metrics
.metric_expense
=
1575 METRICS_UNSUPPORTED
;
1576 ipreach
->metrics
.metric_error
=
1577 METRICS_UNSUPPORTED
;
1578 ipreach
->metrics
.metric_delay
=
1579 METRICS_UNSUPPORTED
;
1580 masklen2ip(ipv4
->prefixlen
,
1582 ipreach
->prefix
.s_addr
=
1583 ((ipreach
->mask
.s_addr
)
1584 & (ipv4
->prefix
.s_addr
));
1586 &ipreach
->prefix
.s_addr
, buf
,
1589 "ISIS (%s): Adding old-style IP reachability for %s/%d",
1590 area
->area_tag
, buf
,
1592 listnode_add(tlv_data
.ipv4_int_reachs
,
1596 if (area
->newmetric
) {
1597 if (tlv_data
.te_ipv4_reachs
== NULL
) {
1598 tlv_data
.te_ipv4_reachs
= list_new();
1599 tlv_data
.te_ipv4_reachs
->del
= free_tlv
;
1601 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
,
1603 /* FIXME All this assumes that we have
1605 te_ipreach
= XCALLOC(
1608 te_ipv4_reachability
)
1609 + ((ipv4
->prefixlen
+ 7)
1613 if (area
->oldmetric
)
1614 te_ipreach
->te_metric
= htonl(
1615 circuit
->metric
[level
1618 te_ipreach
->te_metric
= htonl(
1622 te_ipreach
->control
=
1623 (ipv4
->prefixlen
& 0x3F);
1624 memcpy(&te_ipreach
->prefix_start
,
1625 &ipv4
->prefix
.s_addr
,
1626 (ipv4
->prefixlen
+ 7) / 8);
1627 inet_ntop(AF_INET
, &ipv4
->prefix
.s_addr
,
1630 "ISIS (%s): Adding te-style IP reachability for %s/%d",
1631 area
->area_tag
, buf
,
1633 listnode_add(tlv_data
.te_ipv4_reachs
,
1640 * Add IPv6 reachability of this circuit
1642 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
1643 && circuit
->ipv6_non_link
->count
> 0) {
1645 ipv6_reachs
= tlv_get_ipv6_reach_list(
1648 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
,
1652 sizeof(struct ipv6_reachability
));
1654 if (area
->oldmetric
)
1655 ip6reach
->metric
= htonl(
1656 circuit
->metric
[level
- 1]);
1658 ip6reach
->metric
= htonl(
1659 circuit
->te_metric
[level
- 1]);
1661 ip6reach
->control_info
= 0;
1662 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1663 memcpy(&ip6prefix
, ipv6
, sizeof(ip6prefix
));
1664 apply_mask_ipv6(&ip6prefix
);
1666 inet_ntop(AF_INET6
, &ip6prefix
.prefix
.s6_addr
,
1669 "ISIS (%s): Adding IPv6 reachability for %s/%d",
1670 area
->area_tag
, buf
, ipv6
->prefixlen
);
1672 memcpy(ip6reach
->prefix
,
1673 ip6prefix
.prefix
.s6_addr
,
1674 sizeof(ip6reach
->prefix
));
1675 listnode_add(ipv6_reachs
, ip6reach
);
1679 switch (circuit
->circ_type
) {
1680 case CIRCUIT_T_BROADCAST
:
1681 if (level
& circuit
->is_type
) {
1682 if (area
->oldmetric
) {
1683 if (tlv_data
.is_neighs
== NULL
) {
1684 tlv_data
.is_neighs
= list_new();
1685 tlv_data
.is_neighs
->del
=
1690 sizeof(struct is_neigh
));
1691 if (level
== IS_LEVEL_1
)
1692 memcpy(is_neigh
->neigh_id
,
1695 ISIS_SYS_ID_LEN
+ 1);
1697 memcpy(is_neigh
->neigh_id
,
1700 ISIS_SYS_ID_LEN
+ 1);
1701 is_neigh
->metrics
.metric_default
=
1702 circuit
->metric
[level
- 1];
1703 is_neigh
->metrics
.metric_expense
=
1704 METRICS_UNSUPPORTED
;
1705 is_neigh
->metrics
.metric_error
=
1706 METRICS_UNSUPPORTED
;
1707 is_neigh
->metrics
.metric_delay
=
1708 METRICS_UNSUPPORTED
;
1709 if (!memcmp(is_neigh
->neigh_id
, zero_id
,
1710 ISIS_SYS_ID_LEN
+ 1)) {
1711 XFREE(MTYPE_ISIS_TLV
, is_neigh
);
1713 "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1716 listnode_add(tlv_data
.is_neighs
,
1719 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1722 is_neigh
->neigh_id
),
1724 is_neigh
->neigh_id
));
1727 if (area
->newmetric
) {
1728 if (tlv_data
.te_is_neighs
== NULL
) {
1729 tlv_data
.te_is_neighs
=
1731 tlv_data
.te_is_neighs
->del
=
1734 te_is_neigh
= XCALLOC(
1736 sizeof(struct te_is_neigh
));
1737 if (level
== IS_LEVEL_1
)
1738 memcpy(te_is_neigh
->neigh_id
,
1741 ISIS_SYS_ID_LEN
+ 1);
1743 memcpy(te_is_neigh
->neigh_id
,
1746 ISIS_SYS_ID_LEN
+ 1);
1747 if (area
->oldmetric
)
1748 metric
= circuit
->metric
[level
1752 circuit
->te_metric
[level
1754 SET_TE_METRIC(te_is_neigh
, metric
);
1755 if (!memcmp(te_is_neigh
->neigh_id
,
1757 ISIS_SYS_ID_LEN
+ 1)) {
1758 XFREE(MTYPE_ISIS_TLV
,
1761 "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1764 /* Check if MPLS_TE is activate
1766 if (IS_MPLS_TE(isisMplsTE
)
1768 circuit
->interface
))
1769 /* Add SubTLVs & Adjust
1770 * real size of SubTLVs
1773 ->sub_tlvs_length
= add_te_subtlvs(
1780 * SubTLVs if MPLS_TE is
1788 level
, te_is_neigh
);
1789 XFREE(MTYPE_ISIS_TLV
,
1795 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1800 nei
= circuit
->u
.p2p
.neighbor
;
1801 if (nei
&& (level
& nei
->circuit_t
)) {
1802 if (area
->oldmetric
) {
1803 if (tlv_data
.is_neighs
== NULL
) {
1804 tlv_data
.is_neighs
= list_new();
1805 tlv_data
.is_neighs
->del
=
1810 sizeof(struct is_neigh
));
1811 memcpy(is_neigh
->neigh_id
, nei
->sysid
,
1813 is_neigh
->metrics
.metric_default
=
1814 circuit
->metric
[level
- 1];
1815 is_neigh
->metrics
.metric_expense
=
1816 METRICS_UNSUPPORTED
;
1817 is_neigh
->metrics
.metric_error
=
1818 METRICS_UNSUPPORTED
;
1819 is_neigh
->metrics
.metric_delay
=
1820 METRICS_UNSUPPORTED
;
1821 listnode_add(tlv_data
.is_neighs
,
1824 "ISIS (%s): Adding old-style is reach for %s",
1827 is_neigh
->neigh_id
));
1829 if (area
->newmetric
) {
1832 if (tlv_data
.te_is_neighs
== NULL
) {
1833 tlv_data
.te_is_neighs
=
1835 tlv_data
.te_is_neighs
->del
=
1838 te_is_neigh
= XCALLOC(
1840 sizeof(struct te_is_neigh
));
1841 memcpy(te_is_neigh
->neigh_id
,
1842 nei
->sysid
, ISIS_SYS_ID_LEN
);
1843 metric
= circuit
->te_metric
[level
- 1];
1844 SET_TE_METRIC(te_is_neigh
, metric
);
1845 /* Check if MPLS_TE is activate */
1846 if (IS_MPLS_TE(isisMplsTE
)
1848 circuit
->interface
))
1849 /* Update Local and Remote IP
1850 * address for MPLS TE circuit
1852 /* NOTE sure that it is the
1853 * pertinent place for that
1855 /* Local IP address could be
1856 * updated in isis_circuit.c -
1857 * isis_circuit_add_addr() */
1858 /* But, where update remote IP
1859 * address ? in isis_pdu.c -
1860 * process_p2p_hello() ? */
1862 /* Add SubTLVs & Adjust real
1863 * size of SubTLVs */
1864 te_is_neigh
->sub_tlvs_length
=
1870 /* Or keep only TE metric with
1871 * no SubTLVs if MPLS_TE is off
1873 te_is_neigh
->sub_tlvs_length
=
1876 tlvs_add_mt_p2p(&tlv_data
, circuit
,
1878 XFREE(MTYPE_ISIS_TLV
, te_is_neigh
);
1882 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1886 case CIRCUIT_T_LOOPBACK
:
1889 zlog_warn("lsp_area_create: unknown circuit type");
1893 lsp_build_ext_reach(lsp
, area
, &tlv_data
);
1895 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1898 while (tlv_data
.ipv4_int_reachs
1899 && listcount(tlv_data
.ipv4_int_reachs
)) {
1900 if (lsp
->tlv_data
.ipv4_int_reachs
== NULL
)
1901 lsp
->tlv_data
.ipv4_int_reachs
= list_new();
1902 lsp_tlv_fit(lsp
, &tlv_data
.ipv4_int_reachs
,
1903 &lsp
->tlv_data
.ipv4_int_reachs
, IPV4_REACH_LEN
,
1904 area
->lsp_frag_threshold
, tlv_add_ipv4_int_reachs
);
1905 if (tlv_data
.ipv4_int_reachs
1906 && listcount(tlv_data
.ipv4_int_reachs
))
1907 lsp
= lsp_next_frag(
1908 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1912 while (tlv_data
.ipv4_ext_reachs
1913 && listcount(tlv_data
.ipv4_ext_reachs
)) {
1914 if (lsp
->tlv_data
.ipv4_ext_reachs
== NULL
)
1915 lsp
->tlv_data
.ipv4_ext_reachs
= list_new();
1916 lsp_tlv_fit(lsp
, &tlv_data
.ipv4_ext_reachs
,
1917 &lsp
->tlv_data
.ipv4_ext_reachs
, IPV4_REACH_LEN
,
1918 area
->lsp_frag_threshold
, tlv_add_ipv4_ext_reachs
);
1919 if (tlv_data
.ipv4_ext_reachs
1920 && listcount(tlv_data
.ipv4_ext_reachs
))
1921 lsp
= lsp_next_frag(
1922 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1926 while (tlv_data
.te_ipv4_reachs
&& listcount(tlv_data
.te_ipv4_reachs
)) {
1927 if (lsp
->tlv_data
.te_ipv4_reachs
== NULL
)
1928 lsp
->tlv_data
.te_ipv4_reachs
= list_new();
1929 _lsp_tlv_fit(lsp
, &tlv_data
.te_ipv4_reachs
,
1930 &lsp
->tlv_data
.te_ipv4_reachs
,
1931 area
->lsp_frag_threshold
, tlv_add_te_ipv4_reachs
,
1933 if (tlv_data
.te_ipv4_reachs
1934 && listcount(tlv_data
.te_ipv4_reachs
))
1935 lsp
= lsp_next_frag(
1936 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1940 struct tlv_mt_ipv4_reachs
*mt_ipv4_reachs
;
1941 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv4_reachs
, node
,
1943 while (mt_ipv4_reachs
->list
1944 && listcount(mt_ipv4_reachs
->list
)) {
1945 struct tlv_mt_ipv4_reachs
*frag_mt_ipv4_reachs
;
1947 frag_mt_ipv4_reachs
= tlvs_get_mt_ipv4_reachs(
1948 &lsp
->tlv_data
, mt_ipv4_reachs
->mtid
);
1949 _lsp_tlv_fit(lsp
, &mt_ipv4_reachs
->list
,
1950 &frag_mt_ipv4_reachs
->list
,
1951 area
->lsp_frag_threshold
,
1952 tlv_add_te_ipv4_reachs
,
1953 &mt_ipv4_reachs
->mtid
);
1954 if (mt_ipv4_reachs
->list
1955 && listcount(mt_ipv4_reachs
->list
))
1956 lsp
= lsp_next_frag(
1957 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
)
1963 while (tlv_data
.ipv6_reachs
&& listcount(tlv_data
.ipv6_reachs
)) {
1964 if (lsp
->tlv_data
.ipv6_reachs
== NULL
)
1965 lsp
->tlv_data
.ipv6_reachs
= list_new();
1967 lsp
, &tlv_data
.ipv6_reachs
, &lsp
->tlv_data
.ipv6_reachs
,
1968 area
->lsp_frag_threshold
, tlv_add_ipv6_reachs
, NULL
);
1969 if (tlv_data
.ipv6_reachs
&& listcount(tlv_data
.ipv6_reachs
))
1970 lsp
= lsp_next_frag(
1971 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
1975 struct tlv_mt_ipv6_reachs
*mt_ipv6_reachs
;
1976 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_ipv6_reachs
, node
,
1978 while (mt_ipv6_reachs
->list
1979 && listcount(mt_ipv6_reachs
->list
)) {
1980 struct tlv_mt_ipv6_reachs
*frag_mt_ipv6_reachs
;
1982 frag_mt_ipv6_reachs
= tlvs_get_mt_ipv6_reachs(
1983 &lsp
->tlv_data
, mt_ipv6_reachs
->mtid
);
1984 _lsp_tlv_fit(lsp
, &mt_ipv6_reachs
->list
,
1985 &frag_mt_ipv6_reachs
->list
,
1986 area
->lsp_frag_threshold
,
1987 tlv_add_ipv6_reachs
,
1988 &mt_ipv6_reachs
->mtid
);
1989 if (mt_ipv6_reachs
->list
1990 && listcount(mt_ipv6_reachs
->list
))
1991 lsp
= lsp_next_frag(
1992 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
)
1998 while (tlv_data
.is_neighs
&& listcount(tlv_data
.is_neighs
)) {
1999 if (lsp
->tlv_data
.is_neighs
== NULL
)
2000 lsp
->tlv_data
.is_neighs
= list_new();
2001 lsp_tlv_fit(lsp
, &tlv_data
.is_neighs
, &lsp
->tlv_data
.is_neighs
,
2002 IS_NEIGHBOURS_LEN
, area
->lsp_frag_threshold
,
2004 if (tlv_data
.is_neighs
&& listcount(tlv_data
.is_neighs
))
2005 lsp
= lsp_next_frag(
2006 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
2010 while (tlv_data
.te_is_neighs
&& listcount(tlv_data
.te_is_neighs
)) {
2011 if (lsp
->tlv_data
.te_is_neighs
== NULL
)
2012 lsp
->tlv_data
.te_is_neighs
= list_new();
2013 _lsp_tlv_fit(lsp
, &tlv_data
.te_is_neighs
,
2014 &lsp
->tlv_data
.te_is_neighs
,
2015 area
->lsp_frag_threshold
, tlv_add_te_is_neighs
,
2017 if (tlv_data
.te_is_neighs
&& listcount(tlv_data
.te_is_neighs
))
2018 lsp
= lsp_next_frag(
2019 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
) + 1, lsp0
,
2023 struct tlv_mt_neighbors
*mt_neighs
;
2024 for (ALL_LIST_ELEMENTS_RO(tlv_data
.mt_is_neighs
, node
, mt_neighs
)) {
2025 while (mt_neighs
->list
&& listcount(mt_neighs
->list
)) {
2026 struct tlv_mt_neighbors
*frag_mt_neighs
;
2028 frag_mt_neighs
= tlvs_get_mt_neighbors(&lsp
->tlv_data
,
2030 _lsp_tlv_fit(lsp
, &mt_neighs
->list
,
2031 &frag_mt_neighs
->list
,
2032 area
->lsp_frag_threshold
,
2033 tlv_add_te_is_neighs
, &mt_neighs
->mtid
);
2034 if (mt_neighs
->list
&& listcount(mt_neighs
->list
))
2035 lsp
= lsp_next_frag(
2036 LSP_FRAGMENT(lsp
->lsp_header
->lsp_id
)
2043 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
2045 free_tlvs(&tlv_data
);
2047 /* Validate the LSP */
2048 retval
= parse_tlvs(area
->area_tag
,
2049 STREAM_DATA(lsp
->pdu
) + ISIS_FIXED_HDR_LEN
2051 stream_get_endp(lsp
->pdu
) - ISIS_FIXED_HDR_LEN
2053 &expected
, &found
, &tlv_data
, NULL
);
2054 assert(retval
== ISIS_OK
);
2060 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
2062 int lsp_generate(struct isis_area
*area
, int level
)
2064 struct isis_lsp
*oldlsp
, *newlsp
;
2065 u_int32_t seq_num
= 0;
2066 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
2067 u_int16_t rem_lifetime
, refresh_time
;
2069 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2072 memset(&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2073 memcpy(&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2075 /* only builds the lsp if the area shares the level */
2076 oldlsp
= lsp_search(lspid
, area
->lspdb
[level
- 1]);
2078 /* FIXME: we should actually initiate a purge */
2079 seq_num
= ntohl(oldlsp
->lsp_header
->seq_num
);
2080 lsp_search_and_destroy(oldlsp
->lsp_header
->lsp_id
,
2081 area
->lspdb
[level
- 1]);
2083 rem_lifetime
= lsp_rem_lifetime(area
, level
);
2085 lsp_new(area
, lspid
, rem_lifetime
, seq_num
,
2086 area
->is_type
| area
->overload_bit
| area
->attached_bit
,
2088 newlsp
->area
= area
;
2089 newlsp
->own_lsp
= 1;
2091 lsp_insert(newlsp
, area
->lspdb
[level
- 1]);
2092 /* build_lsp_data (newlsp, area); */
2093 lsp_build(newlsp
, area
);
2094 /* time to calculate our checksum */
2095 lsp_seqnum_update(newlsp
);
2096 newlsp
->last_generated
= time(NULL
);
2097 lsp_set_all_srmflags(newlsp
);
2099 refresh_time
= lsp_refresh_time(newlsp
, rem_lifetime
);
2101 THREAD_TIMER_OFF(area
->t_lsp_refresh
[level
- 1]);
2102 area
->lsp_regenerate_pending
[level
- 1] = 0;
2103 if (level
== IS_LEVEL_1
)
2104 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
2105 &area
->t_lsp_refresh
[level
- 1]);
2106 else if (level
== IS_LEVEL_2
)
2107 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
2108 &area
->t_lsp_refresh
[level
- 1]);
2110 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2112 "ISIS-Upd (%s): Building L%d LSP %s, len %d, "
2113 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2114 area
->area_tag
, level
,
2115 rawlspid_print(newlsp
->lsp_header
->lsp_id
),
2116 ntohl(newlsp
->lsp_header
->pdu_len
),
2117 ntohl(newlsp
->lsp_header
->seq_num
),
2118 ntohs(newlsp
->lsp_header
->checksum
),
2119 ntohs(newlsp
->lsp_header
->rem_lifetime
), refresh_time
);
2122 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2123 area
->area_tag
, level
);
2129 * Search own LSPs, update holding time and set SRM
2131 static int lsp_regenerate(struct isis_area
*area
, int level
)
2134 struct isis_lsp
*lsp
, *frag
;
2135 struct listnode
*node
;
2136 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
2137 u_int16_t rem_lifetime
, refresh_time
;
2139 if ((area
== NULL
) || (area
->is_type
& level
) != level
)
2142 lspdb
= area
->lspdb
[level
- 1];
2144 memset(lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
2145 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2147 lsp
= lsp_search(lspid
, lspdb
);
2150 zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2151 area
->area_tag
, level
);
2155 lsp_clear_data(lsp
);
2156 lsp_build(lsp
, area
);
2157 lsp
->lsp_header
->lsp_bits
= lsp_bits_generate(level
, area
->overload_bit
,
2158 area
->attached_bit
);
2159 rem_lifetime
= lsp_rem_lifetime(area
, level
);
2160 lsp
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
2161 lsp_seqnum_update(lsp
);
2163 lsp
->last_generated
= time(NULL
);
2164 lsp_set_all_srmflags(lsp
);
2165 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
2166 frag
->lsp_header
->lsp_bits
= lsp_bits_generate(
2167 level
, area
->overload_bit
, area
->attached_bit
);
2168 /* Set the lifetime values of all the fragments to the same
2170 * so that no fragment expires before the lsp is refreshed.
2172 frag
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
2173 lsp_set_all_srmflags(frag
);
2176 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
2177 if (level
== IS_LEVEL_1
)
2178 thread_add_timer(master
, lsp_l1_refresh
, area
, refresh_time
,
2179 &area
->t_lsp_refresh
[level
- 1]);
2180 else if (level
== IS_LEVEL_2
)
2181 thread_add_timer(master
, lsp_l2_refresh
, area
, refresh_time
,
2182 &area
->t_lsp_refresh
[level
- 1]);
2183 area
->lsp_regenerate_pending
[level
- 1] = 0;
2185 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2187 "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
2188 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2189 area
->area_tag
, level
,
2190 rawlspid_print(lsp
->lsp_header
->lsp_id
),
2191 ntohl(lsp
->lsp_header
->pdu_len
),
2192 ntohl(lsp
->lsp_header
->seq_num
),
2193 ntohs(lsp
->lsp_header
->checksum
),
2194 ntohs(lsp
->lsp_header
->rem_lifetime
), refresh_time
);
2197 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2198 area
->area_tag
, level
);
2204 * Something has changed or periodic refresh -> regenerate LSP
2206 static int lsp_l1_refresh(struct thread
*thread
)
2208 struct isis_area
*area
;
2210 area
= THREAD_ARG(thread
);
2213 area
->t_lsp_refresh
[0] = NULL
;
2214 area
->lsp_regenerate_pending
[0] = 0;
2216 if ((area
->is_type
& IS_LEVEL_1
) == 0)
2220 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
2222 return lsp_regenerate(area
, IS_LEVEL_1
);
2225 static int lsp_l2_refresh(struct thread
*thread
)
2227 struct isis_area
*area
;
2229 area
= THREAD_ARG(thread
);
2232 area
->t_lsp_refresh
[1] = NULL
;
2233 area
->lsp_regenerate_pending
[1] = 0;
2235 if ((area
->is_type
& IS_LEVEL_2
) == 0)
2239 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
2241 return lsp_regenerate(area
, IS_LEVEL_2
);
2244 int lsp_regenerate_schedule(struct isis_area
*area
, int level
, int all_pseudo
)
2246 struct isis_lsp
*lsp
;
2247 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2250 struct listnode
*cnode
;
2251 struct isis_circuit
*circuit
;
2258 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2259 area
->area_tag
, circuit_t2string(level
),
2260 all_pseudo
? "" : "not ");
2262 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2263 LSP_PSEUDO_ID(id
) = LSP_FRAGMENT(id
) = 0;
2266 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
2267 if (!((level
& lvl
) && (area
->is_type
& lvl
)))
2271 "ISIS (%s): Checking whether L%d needs to be scheduled",
2272 area
->area_tag
, lvl
);
2274 if (area
->lsp_regenerate_pending
[lvl
- 1]) {
2275 struct timeval remain
= thread_timer_remain(
2276 area
->t_lsp_refresh
[lvl
- 1]);
2278 "ISIS (%s): Regeneration is already pending, nothing todo."
2279 " (Due in %lld.%03lld seconds)",
2280 area
->area_tag
, (long long)remain
.tv_sec
,
2281 (long long)remain
.tv_usec
/ 1000);
2285 lsp
= lsp_search(id
, area
->lspdb
[lvl
- 1]);
2288 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2294 * Throttle avoidance
2297 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2298 area
->area_tag
, (long long)lsp
->last_generated
,
2300 THREAD_TIMER_OFF(area
->t_lsp_refresh
[lvl
- 1]);
2301 diff
= now
- lsp
->last_generated
;
2302 if (diff
< area
->lsp_gen_interval
[lvl
- 1]) {
2304 1000 * (area
->lsp_gen_interval
[lvl
- 1] - diff
);
2306 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2307 area
->area_tag
, timeout
);
2310 * lsps are not regenerated if lsp_regenerate function
2312 * directly. However if the lsp_regenerate call is
2314 * later execution it works.
2318 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2319 " Scheduling for execution in %ld ms.",
2320 area
->area_tag
, timeout
);
2323 area
->lsp_regenerate_pending
[lvl
- 1] = 1;
2324 if (lvl
== IS_LEVEL_1
) {
2325 thread_add_timer_msec(master
, lsp_l1_refresh
, area
,
2327 &area
->t_lsp_refresh
[lvl
- 1]);
2328 } else if (lvl
== IS_LEVEL_2
) {
2329 thread_add_timer_msec(master
, lsp_l2_refresh
, area
,
2331 &area
->t_lsp_refresh
[lvl
- 1]);
2336 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
, circuit
))
2337 lsp_regenerate_schedule_pseudo(circuit
, level
);
2344 * Funcs for pseudonode LSPs
2348 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2350 static void lsp_build_pseudo(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2353 struct isis_adjacency
*adj
;
2354 struct is_neigh
*is_neigh
;
2355 struct te_is_neigh
*te_is_neigh
;
2356 struct es_neigh
*es_neigh
;
2357 struct list
*adj_list
;
2358 struct listnode
*node
;
2359 struct isis_area
*area
= circuit
->area
;
2362 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2363 area
->area_tag
, rawlspid_print(lsp
->lsp_header
->lsp_id
),
2364 circuit
->interface
->name
, level
);
2367 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2368 lsp
->lsp_header
->lsp_bits
=
2369 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
2372 * add self to IS neighbours
2374 if (circuit
->area
->oldmetric
) {
2375 if (lsp
->tlv_data
.is_neighs
== NULL
) {
2376 lsp
->tlv_data
.is_neighs
= list_new();
2377 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
2379 is_neigh
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct is_neigh
));
2381 memcpy(&is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2382 listnode_add(lsp
->tlv_data
.is_neighs
, is_neigh
);
2384 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2385 area
->area_tag
, sysid_print(is_neigh
->neigh_id
),
2386 LSP_PSEUDO_ID(is_neigh
->neigh_id
));
2388 if (circuit
->area
->newmetric
) {
2389 if (lsp
->tlv_data
.te_is_neighs
== NULL
) {
2390 lsp
->tlv_data
.te_is_neighs
= list_new();
2391 lsp
->tlv_data
.te_is_neighs
->del
= free_tlv
;
2394 XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct te_is_neigh
));
2396 memcpy(&te_is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2397 listnode_add(lsp
->tlv_data
.te_is_neighs
, te_is_neigh
);
2399 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2400 area
->area_tag
, sysid_print(te_is_neigh
->neigh_id
),
2401 LSP_PSEUDO_ID(te_is_neigh
->neigh_id
));
2404 adj_list
= list_new();
2405 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
2407 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
2408 if (adj
->level
& level
) {
2409 if ((level
== IS_LEVEL_1
2410 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
)
2411 || (level
== IS_LEVEL_1
2412 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
2413 && adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
2414 || (level
== IS_LEVEL_2
2415 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
)) {
2416 /* an IS neighbour -> add it */
2417 if (circuit
->area
->oldmetric
) {
2420 sizeof(struct is_neigh
));
2422 memcpy(&is_neigh
->neigh_id
, adj
->sysid
,
2424 listnode_add(lsp
->tlv_data
.is_neighs
,
2427 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2429 sysid_print(is_neigh
->neigh_id
),
2431 is_neigh
->neigh_id
));
2433 if (circuit
->area
->newmetric
) {
2434 te_is_neigh
= XCALLOC(
2436 sizeof(struct te_is_neigh
));
2437 memcpy(&te_is_neigh
->neigh_id
,
2438 adj
->sysid
, ISIS_SYS_ID_LEN
);
2439 listnode_add(lsp
->tlv_data
.te_is_neighs
,
2442 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2445 te_is_neigh
->neigh_id
),
2447 te_is_neigh
->neigh_id
));
2449 } else if (level
== IS_LEVEL_1
2450 && adj
->sys_type
== ISIS_SYSTYPE_ES
) {
2451 /* an ES neigbour add it, if we are building
2453 /* FIXME: the tlv-format is hard to use here */
2454 if (lsp
->tlv_data
.es_neighs
== NULL
) {
2455 lsp
->tlv_data
.es_neighs
= list_new();
2456 lsp
->tlv_data
.es_neighs
->del
= free_tlv
;
2458 es_neigh
= XCALLOC(MTYPE_ISIS_TLV
,
2459 sizeof(struct es_neigh
));
2461 memcpy(&es_neigh
->first_es_neigh
, adj
->sysid
,
2463 listnode_add(lsp
->tlv_data
.es_neighs
, es_neigh
);
2465 "ISIS (%s): Adding %s as ES neighbor (peer)",
2467 sysid_print(es_neigh
->first_es_neigh
));
2470 "ISIS (%s): Ignoring neighbor %s, level does not match",
2472 sysid_print(adj
->sysid
));
2476 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
2477 area
->area_tag
, sysid_print(adj
->sysid
));
2480 list_delete(adj_list
);
2482 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.",
2485 /* Reset endp of stream to overwrite only TLV part of it. */
2486 stream_reset(lsp
->pdu
);
2487 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2490 * Add the authentication info if it's present
2494 if (lsp
->tlv_data
.is_neighs
&& listcount(lsp
->tlv_data
.is_neighs
) > 0)
2495 tlv_add_is_neighs(lsp
->tlv_data
.is_neighs
, lsp
->pdu
);
2497 if (lsp
->tlv_data
.te_is_neighs
2498 && listcount(lsp
->tlv_data
.te_is_neighs
) > 0)
2499 tlv_add_te_is_neighs(lsp
->tlv_data
.te_is_neighs
, lsp
->pdu
,
2502 if (lsp
->tlv_data
.es_neighs
&& listcount(lsp
->tlv_data
.es_neighs
) > 0)
2503 tlv_add_is_neighs(lsp
->tlv_data
.es_neighs
, lsp
->pdu
);
2505 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
2507 /* Recompute authentication and checksum information */
2508 lsp_auth_update(lsp
);
2509 fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
2510 ntohs(lsp
->lsp_header
->pdu_len
) - 12, 12);
2515 int lsp_generate_pseudo(struct isis_circuit
*circuit
, int level
)
2517 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
2518 struct isis_lsp
*lsp
;
2519 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2520 u_int16_t rem_lifetime
, refresh_time
;
2522 if ((circuit
->is_type
& level
) != level
2523 || (circuit
->state
!= C_STATE_UP
)
2524 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2525 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
2528 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2529 LSP_FRAGMENT(lsp_id
) = 0;
2530 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
2533 * If for some reason have a pseudo LSP in the db already -> regenerate
2535 if (lsp_search(lsp_id
, lspdb
))
2536 return lsp_regenerate_schedule_pseudo(circuit
, level
);
2538 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
2539 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2540 lsp
= lsp_new(circuit
->area
, lsp_id
, rem_lifetime
, 1,
2541 circuit
->area
->is_type
| circuit
->area
->attached_bit
, 0,
2543 lsp
->area
= circuit
->area
;
2545 lsp_build_pseudo(lsp
, circuit
, level
);
2548 lsp_insert(lsp
, lspdb
);
2549 lsp_set_all_srmflags(lsp
);
2551 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
2552 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2553 circuit
->lsp_regenerate_pending
[level
- 1] = 0;
2554 if (level
== IS_LEVEL_1
)
2556 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
2557 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2558 else if (level
== IS_LEVEL_2
)
2560 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
2561 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2563 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2565 "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2566 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2567 circuit
->area
->area_tag
, level
,
2568 rawlspid_print(lsp
->lsp_header
->lsp_id
),
2569 ntohl(lsp
->lsp_header
->pdu_len
),
2570 ntohl(lsp
->lsp_header
->seq_num
),
2571 ntohs(lsp
->lsp_header
->checksum
),
2572 ntohs(lsp
->lsp_header
->rem_lifetime
), refresh_time
);
2578 static int lsp_regenerate_pseudo(struct isis_circuit
*circuit
, int level
)
2580 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
2581 struct isis_lsp
*lsp
;
2582 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2583 u_int16_t rem_lifetime
, refresh_time
;
2585 if ((circuit
->is_type
& level
) != level
2586 || (circuit
->state
!= C_STATE_UP
)
2587 || (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2588 || (circuit
->u
.bc
.is_dr
[level
- 1] == 0))
2591 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2592 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
2593 LSP_FRAGMENT(lsp_id
) = 0;
2595 lsp
= lsp_search(lsp_id
, lspdb
);
2598 zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level
,
2599 rawlspid_print(lsp_id
));
2602 lsp_clear_data(lsp
);
2604 lsp_build_pseudo(lsp
, circuit
, level
);
2606 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2607 lsp
->lsp_header
->lsp_bits
=
2608 lsp_bits_generate(level
, 0, circuit
->area
->attached_bit
);
2609 rem_lifetime
= lsp_rem_lifetime(circuit
->area
, level
);
2610 lsp
->lsp_header
->rem_lifetime
= htons(rem_lifetime
);
2611 lsp_inc_seqnum(lsp
, 0);
2612 lsp
->last_generated
= time(NULL
);
2613 lsp_set_all_srmflags(lsp
);
2615 refresh_time
= lsp_refresh_time(lsp
, rem_lifetime
);
2616 if (level
== IS_LEVEL_1
)
2618 master
, lsp_l1_refresh_pseudo
, circuit
, refresh_time
,
2619 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2620 else if (level
== IS_LEVEL_2
)
2622 master
, lsp_l2_refresh_pseudo
, circuit
, refresh_time
,
2623 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[level
- 1]);
2625 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
) {
2627 "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2628 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2629 circuit
->area
->area_tag
, level
,
2630 rawlspid_print(lsp
->lsp_header
->lsp_id
),
2631 ntohl(lsp
->lsp_header
->pdu_len
),
2632 ntohl(lsp
->lsp_header
->seq_num
),
2633 ntohs(lsp
->lsp_header
->checksum
),
2634 ntohs(lsp
->lsp_header
->rem_lifetime
), refresh_time
);
2641 * Something has changed or periodic refresh -> regenerate pseudo LSP
2643 static int lsp_l1_refresh_pseudo(struct thread
*thread
)
2645 struct isis_circuit
*circuit
;
2646 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2648 circuit
= THREAD_ARG(thread
);
2650 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
2651 circuit
->lsp_regenerate_pending
[0] = 0;
2653 if ((circuit
->u
.bc
.is_dr
[0] == 0)
2654 || (circuit
->is_type
& IS_LEVEL_1
) == 0) {
2655 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2656 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
2657 LSP_FRAGMENT(id
) = 0;
2658 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_1
);
2662 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_1
);
2665 static int lsp_l2_refresh_pseudo(struct thread
*thread
)
2667 struct isis_circuit
*circuit
;
2668 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2670 circuit
= THREAD_ARG(thread
);
2672 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
2673 circuit
->lsp_regenerate_pending
[1] = 0;
2675 if ((circuit
->u
.bc
.is_dr
[1] == 0)
2676 || (circuit
->is_type
& IS_LEVEL_2
) == 0) {
2677 memcpy(id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2678 LSP_PSEUDO_ID(id
) = circuit
->circuit_id
;
2679 LSP_FRAGMENT(id
) = 0;
2680 lsp_purge_pseudo(id
, circuit
, IS_LEVEL_2
);
2684 return lsp_regenerate_pseudo(circuit
, IS_LEVEL_2
);
2687 int lsp_regenerate_schedule_pseudo(struct isis_circuit
*circuit
, int level
)
2689 struct isis_lsp
*lsp
;
2690 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
2694 struct isis_area
*area
= circuit
->area
;
2696 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
2697 || circuit
->state
!= C_STATE_UP
)
2701 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2702 area
->area_tag
, circuit_t2string(level
),
2703 circuit
->interface
->name
);
2705 memcpy(lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2706 LSP_PSEUDO_ID(lsp_id
) = circuit
->circuit_id
;
2707 LSP_FRAGMENT(lsp_id
) = 0;
2710 for (lvl
= IS_LEVEL_1
; lvl
<= IS_LEVEL_2
; lvl
++) {
2712 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2713 area
->area_tag
, lvl
);
2715 if (!((level
& lvl
) && (circuit
->is_type
& lvl
))) {
2716 sched_debug("ISIS (%s): Level is not active on circuit",
2721 if (circuit
->u
.bc
.is_dr
[lvl
- 1] == 0) {
2723 "ISIS (%s): This IS is not DR, nothing to do.",
2728 if (circuit
->lsp_regenerate_pending
[lvl
- 1]) {
2729 struct timeval remain
= thread_timer_remain(
2730 circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2732 "ISIS (%s): Regenerate is already pending, nothing todo."
2733 " (Due in %lld.%03lld seconds)",
2734 area
->area_tag
, (long long)remain
.tv_sec
,
2735 (long long)remain
.tv_usec
/ 1000);
2739 lsp
= lsp_search(lsp_id
, circuit
->area
->lspdb
[lvl
- 1]);
2742 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2748 * Throttle avoidance
2751 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2752 area
->area_tag
, (long long)lsp
->last_generated
,
2754 THREAD_TIMER_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2755 diff
= now
- lsp
->last_generated
;
2756 if (diff
< circuit
->area
->lsp_gen_interval
[lvl
- 1]) {
2758 1000 * (circuit
->area
->lsp_gen_interval
[lvl
- 1]
2761 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2762 area
->area_tag
, timeout
);
2766 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2767 " Scheduling for execution in %ld ms.",
2768 area
->area_tag
, timeout
);
2771 circuit
->lsp_regenerate_pending
[lvl
- 1] = 1;
2773 if (lvl
== IS_LEVEL_1
) {
2774 thread_add_timer_msec(
2775 master
, lsp_l1_refresh_pseudo
, circuit
, timeout
,
2776 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2777 } else if (lvl
== IS_LEVEL_2
) {
2778 thread_add_timer_msec(
2779 master
, lsp_l2_refresh_pseudo
, circuit
, timeout
,
2780 &circuit
->u
.bc
.t_refresh_pseudo_lsp
[lvl
- 1]);
2788 * Walk through LSPs for an area
2789 * - set remaining lifetime
2790 * - set LSPs with SRMflag set for sending
2792 int lsp_tick(struct thread
*thread
)
2794 struct isis_area
*area
;
2795 struct isis_circuit
*circuit
;
2796 struct isis_lsp
*lsp
;
2797 struct list
*lsp_list
;
2798 struct listnode
*lspnode
, *cnode
;
2799 dnode_t
*dnode
, *dnode_next
;
2801 u_int16_t rem_lifetime
;
2803 lsp_list
= list_new();
2805 area
= THREAD_ARG(thread
);
2807 area
->t_tick
= NULL
;
2808 thread_add_timer(master
, lsp_tick
, area
, 1, &area
->t_tick
);
2811 * Build a list of LSPs with (any) SRMflag set
2812 * and removed the ones that have aged out
2814 for (level
= 0; level
< ISIS_LEVELS
; level
++) {
2815 if (area
->lspdb
[level
] && dict_count(area
->lspdb
[level
]) > 0) {
2816 for (dnode
= dict_first(area
->lspdb
[level
]);
2817 dnode
!= NULL
; dnode
= dnode_next
) {
2819 dict_next(area
->lspdb
[level
], dnode
);
2820 lsp
= dnode_get(dnode
);
2823 * The lsp rem_lifetime is kept at 0 for MaxAge
2825 * ZeroAgeLifetime depending on explicit purge
2827 * natural age out. So schedule spf only once
2829 * the first time rem_lifetime becomes 0.
2832 ntohs(lsp
->lsp_header
->rem_lifetime
);
2836 * Schedule may run spf which should be done
2838 * the lsp rem_lifetime becomes 0 for the first
2840 * ISO 10589 - 7.3.16.4 first paragraph.
2842 if (rem_lifetime
== 1
2843 && lsp
->lsp_header
->seq_num
!= 0) {
2844 /* 7.3.16.4 a) set SRM flags on all */
2845 lsp_set_all_srmflags(lsp
);
2846 /* 7.3.16.4 b) retain only the header
2848 /* 7.3.16.4 c) record the time to purge
2850 /* run/schedule spf */
2851 /* isis_spf_schedule is called inside
2852 * lsp_destroy() below;
2853 * so it is not needed here. */
2854 /* isis_spf_schedule (lsp->area,
2858 if (lsp
->age_out
== 0) {
2860 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2861 area
->area_tag
, lsp
->level
,
2865 ntohl(lsp
->lsp_header
2869 dict_delete_free(area
->lspdb
[level
],
2871 } else if (flags_any_set(lsp
->SRMflags
))
2872 listnode_add(lsp_list
, lsp
);
2876 * Send LSPs on circuits indicated by the SRMflags
2878 if (listcount(lsp_list
) > 0) {
2879 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
2883 - circuit
->lsp_queue_last_cleared
;
2884 if (circuit
->lsp_queue
== NULL
2885 || diff
< MIN_LSP_TRANS_INTERVAL
)
2887 for (ALL_LIST_ELEMENTS_RO(
2888 lsp_list
, lspnode
, lsp
)) {
2889 if (circuit
->upadjcount
2894 /* Add the lsp only if
2895 * it is not already in
2898 if (!listnode_lookup(
2914 list_delete_all_node(lsp_list
);
2919 list_delete(lsp_list
);
2924 void lsp_purge_pseudo(u_char
*id
, struct isis_circuit
*circuit
, int level
)
2926 struct isis_lsp
*lsp
;
2930 lsp
= lsp_search(id
, circuit
->area
->lspdb
[level
- 1]);
2934 /* store old values */
2935 seq_num
= lsp
->lsp_header
->seq_num
;
2936 lsp_bits
= lsp
->lsp_header
->lsp_bits
;
2939 lsp_clear_data(lsp
);
2940 stream_reset(lsp
->pdu
);
2943 lsp
->lsp_header
->pdu_len
= htons(ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2944 memcpy(lsp
->lsp_header
->lsp_id
, id
, ISIS_SYS_ID_LEN
+ 2);
2945 lsp
->lsp_header
->checksum
= 0;
2946 lsp
->lsp_header
->seq_num
= seq_num
;
2947 lsp
->lsp_header
->rem_lifetime
= 0;
2948 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
2950 lsp
->age_out
= lsp
->area
->max_lsp_lifetime
[level
- 1];
2951 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2954 * Add and update the authentication info if its present
2957 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
2958 lsp_auth_update(lsp
);
2959 fletcher_checksum(STREAM_DATA(lsp
->pdu
) + 12,
2960 ntohs(lsp
->lsp_header
->pdu_len
) - 12, 12);
2962 lsp_set_all_srmflags(lsp
);
2968 * Purge own LSP that is received and we don't have.
2969 * -> Do as in 7.3.16.4
2971 void lsp_purge_non_exist(int level
, struct isis_link_state_hdr
*lsp_hdr
,
2972 struct isis_area
*area
)
2974 struct isis_lsp
*lsp
;
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 lsp
->isis_header
= (struct isis_fixed_hdr
*)STREAM_DATA(lsp
->pdu
);
2984 fill_fixed_hdr(lsp
->isis_header
,
2985 (lsp
->level
== IS_LEVEL_1
) ? L1_LINK_STATE
2987 lsp
->lsp_header
= (struct isis_link_state_hdr
*)(STREAM_DATA(lsp
->pdu
)
2988 + ISIS_FIXED_HDR_LEN
);
2989 memcpy(lsp
->lsp_header
, lsp_hdr
, ISIS_LSP_HDR_LEN
);
2990 stream_forward_endp(lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2993 * Set the remaining lifetime to 0
2995 lsp
->lsp_header
->rem_lifetime
= 0;
2998 * Add and update the authentication info if its present
3001 lsp_auth_update(lsp
);
3004 * Update the PDU length to header plus any authentication TLV.
3006 lsp
->lsp_header
->pdu_len
= htons(stream_get_endp(lsp
->pdu
));
3009 * Put the lsp into LSPdb
3011 lsp_insert(lsp
, area
->lspdb
[lsp
->level
- 1]);
3014 * Send in to whole area
3016 lsp_set_all_srmflags(lsp
);
3021 void lsp_set_all_srmflags(struct isis_lsp
*lsp
)
3023 struct listnode
*node
;
3024 struct isis_circuit
*circuit
;
3028 ISIS_FLAGS_CLEAR_ALL(lsp
->SRMflags
);
3031 struct list
*circuit_list
= lsp
->area
->circuit_list
;
3032 for (ALL_LIST_ELEMENTS_RO(circuit_list
, node
, circuit
)) {
3033 ISIS_SET_FLAG(lsp
->SRMflags
, circuit
);