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
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include "isisd/dict.h"
40 #include "isisd/isis_constants.h"
41 #include "isisd/isis_common.h"
42 #include "isisd/isis_circuit.h"
43 #include "isisd/isisd.h"
44 #include "isisd/isis_tlv.h"
45 #include "isisd/isis_lsp.h"
46 #include "isisd/isis_pdu.h"
47 #include "isisd/isis_dynhn.h"
48 #include "isisd/isis_misc.h"
49 #include "isisd/isis_flags.h"
50 #include "isisd/iso_checksum.h"
51 #include "isisd/isis_csm.h"
52 #include "isisd/isis_adjacency.h"
53 #include "isisd/isis_spf.h"
55 #ifdef TOPOLOGY_GENERATE
59 #define LSP_MEMORY_PREASSIGN
61 extern struct isis
*isis
;
62 extern struct thread_master
*master
;
63 extern struct in_addr router_id_zebra
;
65 /* staticly assigned vars for printing purposes */
66 char lsp_bits_string
[200]; /* FIXME: enough ? */
69 lsp_id_cmp (u_char
* id1
, u_char
* id2
)
71 return memcmp (id1
, id2
, ISIS_SYS_ID_LEN
+ 2);
79 dict
= dict_create (DICTCOUNT_T_MAX
, (dict_comp_t
) lsp_id_cmp
);
85 lsp_search (u_char
* id
, dict_t
* lspdb
)
92 zlog_debug ("searching db");
93 for (dn
= dict_first (lspdb
); dn
; dn
= dict_next (lspdb
, dn
))
95 zlog_debug ("%s\t%pX", rawlspid_print ((char *) dnode_getkey (dn
)),
98 #endif /* EXTREME DEBUG */
100 node
= dict_lookup (lspdb
, id
);
103 return (struct isis_lsp
*) dnode_get (node
);
109 lsp_clear_data (struct isis_lsp
*lsp
)
116 if (lsp
->tlv_data
.nlpids
)
117 XFREE (MTYPE_ISIS_TLV
, lsp
->tlv_data
.nlpids
);
118 if (lsp
->tlv_data
.hostname
)
119 XFREE (MTYPE_ISIS_TLV
, lsp
->tlv_data
.hostname
);
121 if (lsp
->tlv_data
.is_neighs
)
122 list_delete (lsp
->tlv_data
.is_neighs
);
123 if (lsp
->tlv_data
.area_addrs
)
124 list_delete (lsp
->tlv_data
.area_addrs
);
125 if (lsp
->tlv_data
.es_neighs
)
126 list_delete (lsp
->tlv_data
.es_neighs
);
127 if (lsp
->tlv_data
.ipv4_addrs
)
128 list_delete (lsp
->tlv_data
.ipv4_addrs
);
129 if (lsp
->tlv_data
.ipv4_int_reachs
)
130 list_delete (lsp
->tlv_data
.ipv4_int_reachs
);
131 if (lsp
->tlv_data
.ipv4_ext_reachs
)
132 list_delete (lsp
->tlv_data
.ipv4_ext_reachs
);
134 if (lsp
->tlv_data
.ipv6_addrs
)
135 list_delete (lsp
->tlv_data
.ipv6_addrs
);
136 if (lsp
->tlv_data
.ipv6_reachs
)
137 list_delete (lsp
->tlv_data
.ipv6_reachs
);
138 #endif /* HAVE_IPV6 */
140 memset (&lsp
->tlv_data
, 0, sizeof (struct tlvs
));
146 lsp_destroy (struct isis_lsp
*lsp
)
151 lsp_clear_data (lsp
);
153 if (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) == 0 && lsp
->lspu
.frags
)
155 list_delete (lsp
->lspu
.frags
);
159 stream_free (lsp
->pdu
);
160 XFREE (MTYPE_ISIS_LSP
, lsp
);
164 lsp_db_destroy (dict_t
* lspdb
)
166 dnode_t
*dnode
, *next
;
167 struct isis_lsp
*lsp
;
169 dnode
= dict_first (lspdb
);
172 next
= dict_next (lspdb
, dnode
);
173 lsp
= dnode_get (dnode
);
175 dict_delete_free (lspdb
, dnode
);
185 * Remove all the frags belonging to the given lsp
188 lsp_remove_frags (struct list
*frags
, dict_t
* lspdb
)
191 struct listnode
*lnode
, *lnnode
;
192 struct isis_lsp
*lsp
;
194 for (ALL_LIST_ELEMENTS (frags
, lnode
, lnnode
, lsp
))
196 dnode
= dict_lookup (lspdb
, lsp
->lsp_header
->lsp_id
);
198 dnode_destroy (dict_delete (lspdb
, dnode
));
201 list_delete_all_node (frags
);
207 lsp_search_and_destroy (u_char
* id
, dict_t
* lspdb
)
210 struct isis_lsp
*lsp
;
212 node
= dict_lookup (lspdb
, id
);
215 node
= dict_delete (lspdb
, node
);
216 lsp
= dnode_get (node
);
218 * If this is a zero lsp, remove all the frags now
220 if (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) == 0)
223 lsp_remove_frags (lsp
->lspu
.frags
, lspdb
);
228 * else just remove this frag, from the zero lsps' frag list
230 if (lsp
->lspu
.zero_lsp
&& lsp
->lspu
.zero_lsp
->lspu
.frags
)
231 listnode_delete (lsp
->lspu
.zero_lsp
->lspu
.frags
, lsp
);
234 dnode_destroy (node
);
239 * Compares a LSP to given values
240 * Params are given in net order
243 lsp_compare (char *areatag
, struct isis_lsp
*lsp
, u_int32_t seq_num
,
244 u_int16_t checksum
, u_int16_t rem_lifetime
)
246 /* no point in double ntohl on seqnum */
247 if (lsp
->lsp_header
->seq_num
== seq_num
&&
248 lsp
->lsp_header
->checksum
== checksum
&&
249 /*comparing with 0, no need to do ntohl */
250 ((lsp
->lsp_header
->rem_lifetime
== 0 && rem_lifetime
== 0) ||
251 (lsp
->lsp_header
->rem_lifetime
!= 0 && rem_lifetime
!= 0)))
253 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
255 zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
258 rawlspid_print (lsp
->lsp_header
->lsp_id
),
259 ntohl (lsp
->lsp_header
->seq_num
),
260 ntohs (lsp
->lsp_header
->checksum
),
261 ntohs (lsp
->lsp_header
->rem_lifetime
));
262 zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
263 " cksum 0x%04x, lifetime %us",
265 ntohl (seq_num
), ntohs (checksum
), ntohs (rem_lifetime
));
270 if (ntohl (seq_num
) >= ntohl (lsp
->lsp_header
->seq_num
))
272 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
274 zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
277 rawlspid_print (lsp
->lsp_header
->lsp_id
),
278 ntohl (seq_num
), ntohs (checksum
), ntohs (rem_lifetime
));
279 zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
280 "cksum 0x%04x, lifetime %us",
282 ntohl (lsp
->lsp_header
->seq_num
),
283 ntohs (lsp
->lsp_header
->checksum
),
284 ntohs (lsp
->lsp_header
->rem_lifetime
));
288 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
291 ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
292 areatag
, rawlspid_print (lsp
->lsp_header
->lsp_id
), ntohl (seq_num
),
293 ntohs (checksum
), ntohs (rem_lifetime
));
294 zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
295 " cksum 0x%04x, lifetime %us", areatag
,
296 ntohl (lsp
->lsp_header
->seq_num
),
297 ntohs (lsp
->lsp_header
->checksum
),
298 ntohs (lsp
->lsp_header
->rem_lifetime
));
305 lsp_inc_seqnum (struct isis_lsp
*lsp
, u_int32_t seq_num
)
309 if (seq_num
== 0 || ntohl (lsp
->lsp_header
->seq_num
) > seq_num
)
310 newseq
= ntohl (lsp
->lsp_header
->seq_num
) + 1;
314 lsp
->lsp_header
->seq_num
= htonl (newseq
);
315 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
316 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
322 * Genetates checksum for LSP and its frags
325 lsp_seqnum_update (struct isis_lsp
*lsp0
)
327 struct isis_lsp
*lsp
;
328 struct listnode
*node
, *nnode
;
330 lsp_inc_seqnum (lsp0
, 0);
332 if (!lsp0
->lspu
.frags
)
335 for (ALL_LIST_ELEMENTS (lsp0
->lspu
.frags
, node
, nnode
, lsp
))
336 lsp_inc_seqnum (lsp
, 0);
342 isis_lsp_authinfo_check (struct stream
*stream
, struct isis_area
*area
,
343 int pdulen
, struct isis_passwd
*passwd
)
345 uint32_t expected
= 0, found
;
349 expected
|= TLVFLAG_AUTH_INFO
;
350 retval
= parse_tlvs (area
->area_tag
, stream
->data
+
351 ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
,
352 pdulen
- ISIS_FIXED_HDR_LEN
353 - ISIS_LSP_HDR_LEN
, &expected
, &found
, &tlvs
);
354 if (retval
|| !(found
& TLVFLAG_AUTH_INFO
))
355 return 1; /* Auth fail (parsing failed or no auth-tlv) */
357 return authentication_check (passwd
, &tlvs
.auth_info
);
361 lsp_update_data (struct isis_lsp
*lsp
, struct stream
*stream
,
362 struct isis_area
*area
)
364 uint32_t expected
= 0, found
;
367 /* copying only the relevant part of our stream */
368 lsp
->pdu
= stream_dup (stream
);
370 /* setting pointers to the correct place */
371 lsp
->isis_header
= (struct isis_fixed_hdr
*) (STREAM_DATA (lsp
->pdu
));
372 lsp
->lsp_header
= (struct isis_link_state_hdr
*) (STREAM_DATA (lsp
->pdu
) +
374 lsp
->age_out
= ZERO_AGE_LIFETIME
;
375 lsp
->installed
= time (NULL
);
377 * Get LSP data i.e. TLVs
379 expected
|= TLVFLAG_AUTH_INFO
;
380 expected
|= TLVFLAG_AREA_ADDRS
;
381 expected
|= TLVFLAG_IS_NEIGHS
;
382 if ((lsp
->lsp_header
->lsp_bits
& 3) == 3) /* a level 2 LSP */
383 expected
|= TLVFLAG_PARTITION_DESIG_LEVEL2_IS
;
384 expected
|= TLVFLAG_NLPID
;
385 if (area
->dynhostname
)
386 expected
|= TLVFLAG_DYN_HOSTNAME
;
389 expected
|= TLVFLAG_TE_IS_NEIGHS
;
390 expected
|= TLVFLAG_TE_IPV4_REACHABILITY
;
391 expected
|= TLVFLAG_TE_ROUTER_ID
;
393 expected
|= TLVFLAG_IPV4_ADDR
;
394 expected
|= TLVFLAG_IPV4_INT_REACHABILITY
;
395 expected
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
397 expected
|= TLVFLAG_IPV6_ADDR
;
398 expected
|= TLVFLAG_IPV6_REACHABILITY
;
399 #endif /* HAVE_IPV6 */
401 retval
= parse_tlvs (area
->area_tag
, lsp
->pdu
->data
+
402 ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
,
403 ntohs (lsp
->lsp_header
->pdu_len
) - ISIS_FIXED_HDR_LEN
404 - ISIS_LSP_HDR_LEN
, &expected
, &found
, &lsp
->tlv_data
);
406 if (found
& TLVFLAG_DYN_HOSTNAME
)
408 if (area
->dynhostname
)
409 isis_dynhn_insert (lsp
->lsp_header
->lsp_id
, lsp
->tlv_data
.hostname
,
410 (lsp
->lsp_header
->lsp_bits
& LSPBIT_IST
) ==
411 IS_LEVEL_1_AND_2
? IS_LEVEL_2
:
412 (lsp
->lsp_header
->lsp_bits
& LSPBIT_IST
));
418 lsp_update (struct isis_lsp
*lsp
, struct isis_link_state_hdr
*lsp_hdr
,
419 struct stream
*stream
, struct isis_area
*area
)
421 /* free the old lsp data */
422 XFREE (MTYPE_STREAM_DATA
, lsp
->pdu
);
423 lsp_clear_data (lsp
);
425 /* rebuild the lsp data */
426 lsp_update_data (lsp
, stream
, area
);
428 /* set the new values for lsp header */
429 memcpy (lsp
->lsp_header
, lsp_hdr
, ISIS_LSP_HDR_LEN
);
432 /* creation of LSP directly from what we received */
434 lsp_new_from_stream_ptr (struct stream
*stream
,
435 u_int16_t pdu_len
, struct isis_lsp
*lsp0
,
436 struct isis_area
*area
)
438 struct isis_lsp
*lsp
;
440 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
441 lsp_update_data (lsp
, stream
, area
);
446 * zero lsp -> create the list for fragments
448 lsp
->lspu
.frags
= list_new ();
453 * a fragment -> set the backpointer and add this to zero lsps frag list
455 lsp
->lspu
.zero_lsp
= lsp0
;
456 listnode_add (lsp0
->lspu
.frags
, lsp
);
463 lsp_new (u_char
* lsp_id
, u_int16_t rem_lifetime
, u_int32_t seq_num
,
464 u_int8_t lsp_bits
, u_int16_t checksum
, int level
)
466 struct isis_lsp
*lsp
;
468 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
471 /* FIXME: set lspdbol bit */
472 zlog_warn ("lsp_new(): out of memory");
475 #ifdef LSP_MEMORY_PREASSIGN
476 lsp
->pdu
= stream_new (1514); /*Should be minimal mtu? yup... */
478 /* We need to do realloc on TLVs additions */
479 lsp
->pdu
= malloc (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
480 #endif /* LSP_MEMORY_PREASSIGN */
481 if (LSP_FRAGMENT (lsp_id
) == 0)
482 lsp
->lspu
.frags
= list_new ();
483 lsp
->isis_header
= (struct isis_fixed_hdr
*) (STREAM_DATA (lsp
->pdu
));
484 lsp
->lsp_header
= (struct isis_link_state_hdr
*)
485 (STREAM_DATA (lsp
->pdu
) + ISIS_FIXED_HDR_LEN
);
487 /* at first we fill the FIXED HEADER */
488 (level
== 1) ? fill_fixed_hdr (lsp
->isis_header
, L1_LINK_STATE
) :
489 fill_fixed_hdr (lsp
->isis_header
, L2_LINK_STATE
);
491 /* now for the LSP HEADER */
492 /* Minimal LSP PDU size */
493 lsp
->lsp_header
->pdu_len
= htons (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
494 memcpy (lsp
->lsp_header
->lsp_id
, lsp_id
, ISIS_SYS_ID_LEN
+ 2);
495 lsp
->lsp_header
->checksum
= checksum
; /* Provided in network order */
496 lsp
->lsp_header
->seq_num
= htonl (seq_num
);
497 lsp
->lsp_header
->rem_lifetime
= htons (rem_lifetime
);
498 lsp
->lsp_header
->lsp_bits
= lsp_bits
;
500 lsp
->age_out
= ZERO_AGE_LIFETIME
;
502 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
504 /* #ifdef EXTREME_DEBUG */
506 zlog_debug ("New LSP with ID %s-%02x-%02x seqnum %08x", sysid_print (lsp_id
),
507 LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
),
508 LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
),
509 ntohl (lsp
->lsp_header
->seq_num
));
510 /* #endif EXTREME DEBUG */
516 lsp_insert (struct isis_lsp
*lsp
, dict_t
* lspdb
)
518 dict_alloc_insert (lspdb
, lsp
->lsp_header
->lsp_id
, lsp
);
522 * Build a list of LSPs with non-zero ht bounded by start and stop ids
525 lsp_build_list_nonzero_ht (u_char
* start_id
, u_char
* stop_id
,
526 struct list
*list
, dict_t
* lspdb
)
528 dnode_t
*first
, *last
, *curr
;
530 first
= dict_lower_bound (lspdb
, start_id
);
534 last
= dict_upper_bound (lspdb
, stop_id
);
538 if (((struct isis_lsp
*) (curr
->dict_data
))->lsp_header
->rem_lifetime
)
539 listnode_add (list
, first
->dict_data
);
543 curr
= dict_next (lspdb
, curr
);
545 ((struct isis_lsp
*) (curr
->dict_data
))->lsp_header
->rem_lifetime
)
546 listnode_add (list
, curr
->dict_data
);
555 * Build a list of all LSPs bounded by start and stop ids
558 lsp_build_list (u_char
* start_id
, u_char
* stop_id
,
559 struct list
*list
, dict_t
* lspdb
)
561 dnode_t
*first
, *last
, *curr
;
563 first
= dict_lower_bound (lspdb
, start_id
);
567 last
= dict_upper_bound (lspdb
, stop_id
);
571 listnode_add (list
, first
->dict_data
);
575 curr
= dict_next (lspdb
, curr
);
577 listnode_add (list
, curr
->dict_data
);
586 * Build a list of LSPs with SSN flag set for the given circuit
589 lsp_build_list_ssn (struct isis_circuit
*circuit
, struct list
*list
,
592 dnode_t
*dnode
, *next
;
593 struct isis_lsp
*lsp
;
595 dnode
= dict_first (lspdb
);
596 while (dnode
!= NULL
)
598 next
= dict_next (lspdb
, dnode
);
599 lsp
= dnode_get (dnode
);
600 if (ISIS_CHECK_FLAG (lsp
->SSNflags
, circuit
))
601 listnode_add (list
, lsp
);
609 lsp_set_time (struct isis_lsp
*lsp
)
613 if (lsp
->lsp_header
->rem_lifetime
== 0)
615 if (lsp
->age_out
!= 0)
620 /* If we are turning 0 */
621 /* ISO 10589 - 7.3.16.4 first paragraph */
623 if (ntohs (lsp
->lsp_header
->rem_lifetime
) == 1)
625 /* 7.3.16.4 a) set SRM flags on all */
626 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
627 /* 7.3.16.4 b) retain only the header FIXME */
628 /* 7.3.16.4 c) record the time to purge FIXME (other way to do it) */
631 lsp
->lsp_header
->rem_lifetime
=
632 htons (ntohs (lsp
->lsp_header
->rem_lifetime
) - 1);
636 lspid_print (u_char
* lsp_id
, u_char
* trg
, char dynhost
, char frag
)
638 struct isis_dynhn
*dyn
= NULL
;
639 u_char id
[SYSID_STRLEN
];
642 dyn
= dynhn_find_by_id (lsp_id
);
647 sprintf ((char *)id
, "%.14s", dyn
->name
.name
);
648 else if (!memcmp (isis
->sysid
, lsp_id
, ISIS_SYS_ID_LEN
) & dynhost
)
649 sprintf ((char *)id
, "%.14s", unix_hostname ());
652 memcpy (id
, sysid_print (lsp_id
), 15);
655 sprintf ((char *)trg
, "%s.%02x-%02x", id
, LSP_PSEUDO_ID (lsp_id
),
656 LSP_FRAGMENT (lsp_id
));
658 sprintf ((char *)trg
, "%s.%02x", id
, LSP_PSEUDO_ID (lsp_id
));
661 /* Convert the lsp attribute bits to attribute string */
663 lsp_bits2string (u_char
* lsp_bits
)
665 char *pos
= lsp_bits_string
;
670 /* we only focus on the default metric */
671 pos
+= sprintf (pos
, "%d/",
672 ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits
) ? 1 : 0);
674 pos
+= sprintf (pos
, "%d/",
675 ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits
) ? 1 : 0);
677 pos
+= sprintf (pos
, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits
) ? 1 : 0);
681 return lsp_bits_string
;
684 /* this function prints the lsp on show isis database */
686 lsp_print (dnode_t
* node
, struct vty
*vty
, char dynhost
)
688 struct isis_lsp
*lsp
= dnode_get (node
);
691 lspid_print (lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
692 vty_out (vty
, "%-21s%c ", LSPid
, lsp
->own_lsp
? '*' : ' ');
693 vty_out (vty
, "0x%08x ", ntohl (lsp
->lsp_header
->seq_num
));
694 vty_out (vty
, "0x%04x ", ntohs (lsp
->lsp_header
->checksum
));
696 if (ntohs (lsp
->lsp_header
->rem_lifetime
) == 0)
697 vty_out (vty
, " (%2u)", lsp
->age_out
);
699 vty_out (vty
, "%5u", ntohs (lsp
->lsp_header
->rem_lifetime
));
701 vty_out (vty
, " %s%s",
702 lsp_bits2string (&lsp
->lsp_header
->lsp_bits
), VTY_NEWLINE
);
706 lsp_print_detail (dnode_t
* node
, struct vty
*vty
, char dynhost
)
708 struct isis_lsp
*lsp
= dnode_get (node
);
709 struct area_addr
*area_addr
;
711 struct listnode
*lnode
, *lnnode
;
712 struct is_neigh
*is_neigh
;
713 struct te_is_neigh
*te_is_neigh
;
714 struct ipv4_reachability
*ipv4_reach
;
715 struct in_addr
*ipv4_addr
;
716 struct te_ipv4_reachability
*te_ipv4_reach
;
718 struct ipv6_reachability
*ipv6_reach
;
722 u_char hostname
[255];
724 u_char ipv4_reach_prefix
[20];
725 u_char ipv4_reach_mask
[20];
726 u_char ipv4_address
[20];
728 lspid_print (lsp
->lsp_header
->lsp_id
, LSPid
, dynhost
, 1);
729 lsp_print (node
, vty
, dynhost
);
731 /* for all area address */
732 if (lsp
->tlv_data
.area_addrs
)
733 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.area_addrs
, lnode
,
736 vty_out (vty
, " Area Address: %s%s",
737 isonet_print (area_addr
->area_addr
, area_addr
->addr_len
),
741 /* for the nlpid tlv */
742 if (lsp
->tlv_data
.nlpids
)
744 for (i
= 0; i
< lsp
->tlv_data
.nlpids
->count
; i
++)
746 switch (lsp
->tlv_data
.nlpids
->nlpids
[i
])
750 vty_out (vty
, " NLPID: 0x%X%s",
751 lsp
->tlv_data
.nlpids
->nlpids
[i
], VTY_NEWLINE
);
754 vty_out (vty
, " NLPID: %s%s", "unknown", VTY_NEWLINE
);
760 /* for the hostname tlv */
761 if (lsp
->tlv_data
.hostname
)
763 bzero (hostname
, sizeof (hostname
));
764 memcpy (hostname
, lsp
->tlv_data
.hostname
->name
,
765 lsp
->tlv_data
.hostname
->namelen
);
766 vty_out (vty
, " Hostname: %s%s", hostname
, VTY_NEWLINE
);
769 if (lsp
->tlv_data
.ipv4_addrs
)
770 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.ipv4_addrs
, lnode
,
773 memcpy (ipv4_address
, inet_ntoa (*ipv4_addr
), sizeof (ipv4_address
));
774 vty_out (vty
, " IP: %s%s", ipv4_address
, VTY_NEWLINE
);
778 if (lsp
->tlv_data
.router_id
)
780 memcpy (ipv4_address
, inet_ntoa (lsp
->tlv_data
.router_id
->id
),
781 sizeof (ipv4_address
));
782 vty_out (vty
, " Router ID: %s%s", ipv4_address
, VTY_NEWLINE
);
785 /* for the IS neighbor tlv */
786 if (lsp
->tlv_data
.is_neighs
)
787 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.is_neighs
, lnode
, lnnode
, is_neigh
))
789 lspid_print (is_neigh
->neigh_id
, LSPid
, dynhost
, 0);
790 vty_out (vty
, " Metric: %d IS %s%s",
791 is_neigh
->metrics
.metric_default
, LSPid
, VTY_NEWLINE
);
794 /* for the internal reachable tlv */
795 if (lsp
->tlv_data
.ipv4_int_reachs
)
796 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.ipv4_int_reachs
, lnode
,
799 memcpy (ipv4_reach_prefix
, inet_ntoa (ipv4_reach
->prefix
),
800 sizeof (ipv4_reach_prefix
));
801 memcpy (ipv4_reach_mask
, inet_ntoa (ipv4_reach
->mask
),
802 sizeof (ipv4_reach_mask
));
803 vty_out (vty
, " Metric: %d IP %s %s%s",
804 ipv4_reach
->metrics
.metric_default
, ipv4_reach_prefix
,
805 ipv4_reach_mask
, VTY_NEWLINE
);
808 /* for the external reachable tlv */
809 if (lsp
->tlv_data
.ipv4_ext_reachs
)
810 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.ipv4_ext_reachs
, lnode
,
813 memcpy (ipv4_reach_prefix
, inet_ntoa (ipv4_reach
->prefix
),
814 sizeof (ipv4_reach_prefix
));
815 memcpy (ipv4_reach_mask
, inet_ntoa (ipv4_reach
->mask
),
816 sizeof (ipv4_reach_mask
));
817 vty_out (vty
, " Metric: %d IP-External %s %s%s",
818 ipv4_reach
->metrics
.metric_default
, ipv4_reach_prefix
,
819 ipv4_reach_mask
, VTY_NEWLINE
);
824 if (lsp
->tlv_data
.ipv6_reachs
)
825 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.ipv6_reachs
, lnode
,
828 memset (&in6
, 0, sizeof (in6
));
829 memcpy (in6
.s6_addr
, ipv6_reach
->prefix
,
830 PSIZE (ipv6_reach
->prefix_len
));
831 inet_ntop (AF_INET6
, &in6
, (char *)buff
, BUFSIZ
);
832 if ((ipv6_reach
->control_info
&&
833 CTRL_INFO_DISTRIBUTION
) == DISTRIBUTION_INTERNAL
)
834 vty_out (vty
, " Metric: %d IPv6-Intern %s/%d%s",
835 ntohl (ipv6_reach
->metric
),
836 buff
, ipv6_reach
->prefix_len
, VTY_NEWLINE
);
838 vty_out (vty
, " Metric: %d IPv6-Extern %s/%d%s",
839 ntohl (ipv6_reach
->metric
),
840 buff
, ipv6_reach
->prefix_len
, VTY_NEWLINE
);
844 /* TE IS neighbor tlv */
845 if (lsp
->tlv_data
.te_is_neighs
)
846 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.te_is_neighs
, lnode
,
847 lnnode
, te_is_neigh
))
849 /* FIXME: metric display is wrong. */
850 lspid_print (te_is_neigh
->neigh_id
, LSPid
, dynhost
, 0);
851 vty_out (vty
, " Metric: %d extd-IS %s%s",
852 te_is_neigh
->te_metric
[0], LSPid
, VTY_NEWLINE
);
856 if (lsp
->tlv_data
.te_ipv4_reachs
)
857 for (ALL_LIST_ELEMENTS (lsp
->tlv_data
.te_ipv4_reachs
, lnode
,
858 lnnode
, te_ipv4_reach
))
860 /* FIXME: There should be better way to output this stuff. */
861 vty_out (vty
, " Metric: %d extd-IP %s/%d%s",
862 ntohl (te_ipv4_reach
->te_metric
),
863 inet_ntoa (newprefix2inaddr (&te_ipv4_reach
->prefix_start
,
864 te_ipv4_reach
->control
)),
865 te_ipv4_reach
->control
& 0x3F, VTY_NEWLINE
);
871 /* print all the lsps info in the local lspdb */
873 lsp_print_all (struct vty
*vty
, dict_t
* lspdb
, char detail
, char dynhost
)
876 dnode_t
*node
= dict_first (lspdb
), *next
;
879 /* print the title, for both modes */
880 vty_out (vty
, "LSP ID LSP Seq Num LSP Checksum "
881 "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE
);
883 if (detail
== ISIS_UI_LEVEL_BRIEF
)
887 /* I think it is unnecessary, so I comment it out */
888 /* dict_contains (lspdb, node); */
889 next
= dict_next (lspdb
, node
);
890 lsp_print (node
, vty
, dynhost
);
895 else if (detail
== ISIS_UI_LEVEL_DETAIL
)
899 next
= dict_next (lspdb
, node
);
900 lsp_print_detail (node
, vty
, dynhost
);
909 /* this function reallocate memory to an lsp pdu, with an additional
910 * size of memory, it scans the lsp and moves all pointers the
913 lsppdu_realloc (struct isis_lsp
* lsp
, int memorytype
, int size
)
917 retval
= STREAM_DATA (lsp
->pdu
) + ntohs (lsp
->lsp_header
->pdu_len
);
918 #ifdef LSP_MEMORY_PREASSIGN
919 lsp
->lsp_header
->pdu_len
= htons (ntohs (lsp
->lsp_header
->pdu_len
) + size
);
921 #else /* otherwise we have to move all pointers */
923 newpdu
= stream_new (ntohs (lsp
->lsp_header
->pdu_len
) + size
);
924 stream_put (newpdu
, STREAM_DATA(lsp
->pdu
), ntohs (lsp
->lsp_header
->pdu_len
));
925 XFREE (memorytype
, lsp
->pdu
);
927 lsp
->isis_header
= (struct isis_fixed_hdr
*) STREAM_DATA (lsp
->pdu
);
928 lsp
->lsp_header
= (struct isis_link_state_hdr
*)
929 (STREAM_DATA (lsp
->pdu
) + ISIS_FIXED_HDR_LEN
);
930 htons (ntohs (lsp
->lsp_header
->pdu_len
) += size
);
931 return STREAM_DATA (lsp
->pdu
) + (lsp
->lsp_header
->pdu_len
- size
);
932 #endif /* LSP_MEMORY_PREASSIGN */
935 #if 0 /* Saving the old one just in case :) */
937 * Builds the lsp->tlv_data
938 * and writes the tlvs into lsp->pdu
941 lsp_build_nonpseudo (struct isis_lsp
*lsp
, struct isis_area
*area
)
943 struct is_neigh
*is_neigh
;
944 struct listnode
*node
, *nnode
, *ipnode
, *ipnnode
;
945 int level
= lsp
->level
;
946 struct isis_circuit
*circuit
;
947 struct prefix_ipv4
*ipv4
;
948 struct ipv4_reachability
*ipreach
;
949 struct isis_adjacency
*nei
;
951 struct prefix_ipv6
*ipv6
;
952 struct ipv6_reachability
*ip6reach
;
953 #endif /* HAVE_IPV6 */
956 * First add the tlvs related to area
960 if (lsp
->tlv_data
.area_addrs
== NULL
)
961 lsp
->tlv_data
.area_addrs
= list_new ();
962 list_add_list (lsp
->tlv_data
.area_addrs
, area
->area_addrs
);
963 /* Protocols Supported */
964 if (area
->ip_circuits
> 0
966 || area
->ipv6_circuits
> 0
967 #endif /* HAVE_IPV6 */
970 lsp
->tlv_data
.nlpids
= XMALLOC (MTYPE_ISIS_TLV
, sizeof (struct nlpids
));
971 lsp
->tlv_data
.nlpids
->count
= 0;
972 if (area
->ip_circuits
> 0)
974 lsp
->tlv_data
.nlpids
->count
++;
975 lsp
->tlv_data
.nlpids
->nlpids
[0] = NLPID_IP
;
978 if (area
->ipv6_circuits
> 0)
980 lsp
->tlv_data
.nlpids
->count
++;
981 lsp
->tlv_data
.nlpids
->nlpids
[lsp
->tlv_data
.nlpids
->count
- 1] =
984 #endif /* HAVE_IPV6 */
986 /* Dynamic Hostname */
987 if (area
->dynhostname
)
989 lsp
->tlv_data
.hostname
= XMALLOC (MTYPE_ISIS_TLV
,
990 sizeof (struct hostname
));
991 memcpy (&lsp
->tlv_data
.hostname
->name
, unix_hostname (),
992 strlen (unix_hostname ()));
993 lsp
->tlv_data
.hostname
->namelen
= strlen (unix_hostname ());
995 #ifdef TOPOLOGY_GENERATE
997 * If we have a topology in this area, we need to connect this lsp to
998 * the first topology lsp
1000 if ((area
->topology
) && (level
== 1))
1002 if (lsp
->tlv_data
.is_neighs
== NULL
)
1003 lsp
->tlv_data
.is_neighs
= list_new ();
1004 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1005 memcpy (&is_neigh
->neigh_id
, area
->topology_baseis
, ISIS_SYS_ID_LEN
);
1006 /* connected to the first */
1007 is_neigh
->neigh_id
[ISIS_SYS_ID_LEN
- 1] = (0x01);
1008 /* this is actually the same system, why mess the SPT */
1009 is_neigh
->metrics
.metric_default
= 0;
1010 is_neigh
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
1011 is_neigh
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
1012 is_neigh
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
1013 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
1019 * Then add tlvs related to circuits
1021 for (ALL_LIST_ELEMENTS (area
->circuit_list
, node
, nnode
, circuit
))
1023 if (circuit
->state
!= C_STATE_UP
)
1027 * Add IPv4 internal reachability of this circuit
1029 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
1030 circuit
->ip_addrs
->count
> 0)
1032 if (lsp
->tlv_data
.ipv4_int_reachs
== NULL
)
1034 lsp
->tlv_data
.ipv4_int_reachs
= list_new ();
1035 lsp
->tlv_data
.ipv4_int_reachs
->del
= free_tlv
;
1037 for (ALL_LIST_ELEMENTS (circuit
->ip_addrs
, ipnode
, ipnnode
, ipv4
))
1040 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv4_reachability
));
1041 ipreach
->metrics
= circuit
->metrics
[level
- 1];
1042 ipreach
->prefix
= ipv4
->prefix
;
1043 masklen2ip (ipv4
->prefixlen
, &ipreach
->mask
);
1044 listnode_add (lsp
->tlv_data
.ipv4_int_reachs
, ipreach
);
1049 * Add IPv6 reachability of this circuit
1051 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
&&
1052 circuit
->ipv6_non_link
->count
> 0)
1054 if (lsp
->tlv_data
.ipv6_reachs
== NULL
)
1056 lsp
->tlv_data
.ipv6_reachs
= list_new ();
1057 lsp
->tlv_data
.ipv6_reachs
->del
= free_tlv
;
1059 for (ALL_LIST_ELEMENTS (circuit
->ipv6_non_link
, ipnode
,
1063 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv6_reachability
));
1065 htonl (circuit
->metrics
[level
- 1].metric_default
);
1066 ip6reach
->control_info
= 0;
1067 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1068 memcpy (&ip6reach
->prefix
, ipv6
->prefix
.s6_addr
,
1069 (ipv6
->prefixlen
+ 7) / 8);
1070 listnode_add (lsp
->tlv_data
.ipv6_reachs
, ip6reach
);
1073 #endif /* HAVE_IPV6 */
1075 switch (circuit
->circ_type
)
1077 case CIRCUIT_T_BROADCAST
:
1078 if (level
& circuit
->circuit_is_type
)
1080 if (lsp
->tlv_data
.is_neighs
== NULL
)
1082 lsp
->tlv_data
.is_neighs
= list_new ();
1083 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
1085 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1087 memcpy (&is_neigh
->neigh_id
,
1088 circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1090 memcpy (&is_neigh
->neigh_id
,
1091 circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1092 is_neigh
->metrics
= circuit
->metrics
[level
- 1];
1093 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
1097 nei
= circuit
->u
.p2p
.neighbor
;
1098 if (nei
&& (level
& nei
->circuit_t
))
1100 if (lsp
->tlv_data
.is_neighs
== NULL
)
1102 lsp
->tlv_data
.is_neighs
= list_new ();
1103 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
1105 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1106 memcpy (&is_neigh
->neigh_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1107 is_neigh
->metrics
= circuit
->metrics
[level
- 1];
1108 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
1111 case CIRCUIT_T_STATIC_IN
:
1112 zlog_warn ("lsp_area_create: unsupported circuit type");
1114 case CIRCUIT_T_STATIC_OUT
:
1115 zlog_warn ("lsp_area_create: unsupported circuit type");
1118 zlog_warn ("lsp_area_create: unsupported circuit type");
1121 zlog_warn ("lsp_area_create: unknown circuit type");
1125 if (lsp
->tlv_data
.nlpids
)
1126 tlv_add_nlpid (lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1127 if (lsp
->tlv_data
.hostname
)
1128 tlv_add_dynamic_hostname (lsp
->tlv_data
.hostname
, lsp
->pdu
);
1129 if (lsp
->tlv_data
.area_addrs
&& listcount (lsp
->tlv_data
.area_addrs
) > 0)
1130 tlv_add_area_addrs (lsp
->tlv_data
.area_addrs
, lsp
->pdu
);
1131 if (lsp
->tlv_data
.is_neighs
&& listcount (lsp
->tlv_data
.is_neighs
) > 0)
1132 tlv_add_is_neighs (lsp
->tlv_data
.is_neighs
, lsp
->pdu
);
1133 if (lsp
->tlv_data
.ipv4_int_reachs
&&
1134 listcount (lsp
->tlv_data
.ipv4_int_reachs
) > 0)
1135 tlv_add_ipv4_reachs (lsp
->tlv_data
.ipv4_int_reachs
, lsp
->pdu
);
1137 if (lsp
->tlv_data
.ipv6_reachs
&& listcount (lsp
->tlv_data
.ipv6_reachs
) > 0)
1138 tlv_add_ipv6_reachs (lsp
->tlv_data
.ipv6_reachs
, lsp
->pdu
);
1139 #endif /* HAVE_IPV6 */
1141 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1147 #define FRAG_THOLD(S,T) \
1148 ((STREAM_SIZE(S)*T)/100)
1150 /* stream*, area->lsp_frag_threshold, increment */
1151 #define FRAG_NEEDED(S,T,I) \
1152 (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
1155 lsp_tlv_fit (struct isis_lsp
*lsp
, struct list
**from
, struct list
**to
,
1156 int tlvsize
, int frag_thold
,
1157 int tlv_build_func (struct list
*, struct stream
*))
1161 /* can we fit all ? */
1162 if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, listcount (*from
) * tlvsize
+ 2))
1164 tlv_build_func (*from
, lsp
->pdu
);
1168 else if (!FRAG_NEEDED (lsp
->pdu
, frag_thold
, tlvsize
+ 2))
1170 /* fit all we can */
1171 count
= FRAG_THOLD (lsp
->pdu
, frag_thold
) - 2 -
1172 (STREAM_SIZE (lsp
->pdu
) - STREAM_REMAIN (lsp
->pdu
));
1174 count
= count
/ tlvsize
;
1175 for (i
= 0; i
< count
; i
++)
1177 listnode_add (*to
, listgetdata (listhead (*from
)));
1178 listnode_delete (*from
, listgetdata (listhead (*from
)));
1180 tlv_build_func (*to
, lsp
->pdu
);
1182 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1186 static struct isis_lsp
*
1187 lsp_next_frag (u_char frag_num
, struct isis_lsp
*lsp0
, struct isis_area
*area
,
1190 struct isis_lsp
*lsp
;
1191 u_char frag_id
[ISIS_SYS_ID_LEN
+ 2];
1193 memcpy (frag_id
, lsp0
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1194 LSP_FRAGMENT (frag_id
) = frag_num
;
1195 lsp
= lsp_search (frag_id
, area
->lspdb
[level
- 1]);
1199 * Clear the TLVs, but inherit the authinfo
1201 lsp_clear_data (lsp
);
1202 if (lsp0
->tlv_data
.auth_info
.type
)
1204 memcpy (&lsp
->tlv_data
.auth_info
, &lsp
->tlv_data
.auth_info
,
1205 sizeof (struct isis_passwd
));
1206 tlv_add_authinfo (lsp
->tlv_data
.auth_info
.type
,
1207 lsp
->tlv_data
.auth_info
.len
,
1208 lsp
->tlv_data
.auth_info
.passwd
, lsp
->pdu
);
1212 lsp
= lsp_new (frag_id
, area
->max_lsp_lifetime
[level
- 1], 0, area
->is_type
,
1215 lsp_insert (lsp
, area
->lspdb
[level
- 1]);
1216 listnode_add (lsp0
->lspu
.frags
, lsp
);
1217 lsp
->lspu
.zero_lsp
= lsp0
;
1219 * Copy the authinfo from zero LSP
1221 if (lsp0
->tlv_data
.auth_info
.type
)
1223 memcpy (&lsp
->tlv_data
.auth_info
, &lsp
->tlv_data
.auth_info
,
1224 sizeof (struct isis_passwd
));
1225 tlv_add_authinfo (lsp
->tlv_data
.auth_info
.type
,
1226 lsp
->tlv_data
.auth_info
.len
,
1227 lsp
->tlv_data
.auth_info
.passwd
, lsp
->pdu
);
1233 * Builds the LSP data part. This func creates a new frag whenever
1234 * area->lsp_frag_threshold is exceeded.
1238 lsp_build_nonpseudo (struct isis_lsp
*lsp
, struct isis_area
*area
)
1240 struct is_neigh
*is_neigh
;
1241 struct listnode
*node
, *nnode
, *ipnode
, *ipnnode
;
1242 int level
= lsp
->level
;
1243 struct isis_circuit
*circuit
;
1244 struct prefix_ipv4
*ipv4
;
1245 struct ipv4_reachability
*ipreach
;
1246 struct isis_adjacency
*nei
;
1248 struct prefix_ipv6
*ipv6
, *ip6prefix
;
1249 struct ipv6_reachability
*ip6reach
;
1250 #endif /* HAVE_IPV6 */
1251 struct tlvs tlv_data
;
1252 struct isis_lsp
*lsp0
= lsp
;
1253 struct isis_passwd
*passwd
;
1254 struct in_addr
*routerid
;
1257 * First add the tlvs related to area
1260 /* Area addresses */
1261 if (lsp
->tlv_data
.area_addrs
== NULL
)
1262 lsp
->tlv_data
.area_addrs
= list_new ();
1263 list_add_list (lsp
->tlv_data
.area_addrs
, area
->area_addrs
);
1264 /* Protocols Supported */
1265 if (area
->ip_circuits
> 0
1267 || area
->ipv6_circuits
> 0
1268 #endif /* HAVE_IPV6 */
1271 lsp
->tlv_data
.nlpids
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct nlpids
));
1272 lsp
->tlv_data
.nlpids
->count
= 0;
1273 if (area
->ip_circuits
> 0)
1275 lsp
->tlv_data
.nlpids
->count
++;
1276 lsp
->tlv_data
.nlpids
->nlpids
[0] = NLPID_IP
;
1279 if (area
->ipv6_circuits
> 0)
1281 lsp
->tlv_data
.nlpids
->count
++;
1282 lsp
->tlv_data
.nlpids
->nlpids
[lsp
->tlv_data
.nlpids
->count
- 1] =
1285 #endif /* HAVE_IPV6 */
1287 /* Dynamic Hostname */
1288 if (area
->dynhostname
)
1290 lsp
->tlv_data
.hostname
= XMALLOC (MTYPE_ISIS_TLV
,
1291 sizeof (struct hostname
));
1293 memcpy (lsp
->tlv_data
.hostname
->name
, unix_hostname (),
1294 strlen (unix_hostname ()));
1295 lsp
->tlv_data
.hostname
->namelen
= strlen (unix_hostname ());
1299 * Building the zero lsp
1302 /* Reset stream endp. Stream is always there and on every LSP refresh only
1303 * TLV part of it is overwritten. So we must seek past header we will not
1306 stream_forward_endp (lsp
->pdu
, ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
1309 * Add the authentication info if its present
1311 (level
== 1) ? (passwd
= &area
->area_passwd
) :
1312 (passwd
= &area
->domain_passwd
);
1315 memcpy (&lsp
->tlv_data
.auth_info
, passwd
, sizeof (struct isis_passwd
));
1316 tlv_add_authinfo (passwd
->type
, passwd
->len
, passwd
->passwd
, lsp
->pdu
);
1318 if (lsp
->tlv_data
.nlpids
)
1319 tlv_add_nlpid (lsp
->tlv_data
.nlpids
, lsp
->pdu
);
1320 if (lsp
->tlv_data
.hostname
)
1321 tlv_add_dynamic_hostname (lsp
->tlv_data
.hostname
, lsp
->pdu
);
1322 if (lsp
->tlv_data
.area_addrs
&& listcount (lsp
->tlv_data
.area_addrs
) > 0)
1323 tlv_add_area_addrs (lsp
->tlv_data
.area_addrs
, lsp
->pdu
);
1325 memset (&tlv_data
, 0, sizeof (struct tlvs
));
1327 * IPv4 address TLV. We don't follow "C" vendor, but "J" vendor behavior -
1328 * one IPv4 address is put into LSP and this address is same as router id.
1330 if (router_id_zebra
.s_addr
!= 0)
1332 if (lsp
->tlv_data
.ipv4_addrs
== NULL
)
1334 lsp
->tlv_data
.ipv4_addrs
= list_new ();
1335 lsp
->tlv_data
.ipv4_addrs
->del
= free_tlv
;
1338 routerid
= XMALLOC (MTYPE_ISIS_TLV
, sizeof (struct in_addr
));
1339 routerid
->s_addr
= router_id_zebra
.s_addr
;
1341 listnode_add (lsp
->tlv_data
.ipv4_addrs
, routerid
);
1344 * FIXME: Using add_tlv() directly is hack, but tlv_add_ip_addrs()
1345 * expects list of prefix_ipv4 structures, but we have list of
1346 * in_addr structures.
1348 add_tlv (IPV4_ADDR
, IPV4_MAX_BYTELEN
, (u_char
*) &routerid
->s_addr
,
1352 * Then build lists of tlvs related to circuits
1354 for (ALL_LIST_ELEMENTS (area
->circuit_list
, node
, nnode
, circuit
))
1356 if (circuit
->state
!= C_STATE_UP
)
1360 * Add IPv4 internal reachability of this circuit
1362 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
1363 circuit
->ip_addrs
->count
> 0)
1365 if (tlv_data
.ipv4_int_reachs
== NULL
)
1367 tlv_data
.ipv4_int_reachs
= list_new ();
1368 tlv_data
.ipv4_int_reachs
->del
= free_tlv
;
1370 for (ALL_LIST_ELEMENTS (circuit
->ip_addrs
, ipnode
, ipnnode
, ipv4
))
1373 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv4_reachability
));
1374 ipreach
->metrics
= circuit
->metrics
[level
- 1];
1375 masklen2ip (ipv4
->prefixlen
, &ipreach
->mask
);
1376 ipreach
->prefix
.s_addr
= ((ipreach
->mask
.s_addr
) &
1377 (ipv4
->prefix
.s_addr
));
1378 listnode_add (tlv_data
.ipv4_int_reachs
, ipreach
);
1384 * Add IPv6 reachability of this circuit
1386 if (circuit
->ipv6_router
&& circuit
->ipv6_non_link
&&
1387 circuit
->ipv6_non_link
->count
> 0)
1390 if (tlv_data
.ipv6_reachs
== NULL
)
1392 tlv_data
.ipv6_reachs
= list_new ();
1393 tlv_data
.ipv6_reachs
->del
= free_tlv
;
1395 for (ALL_LIST_ELEMENTS (circuit
->ipv6_non_link
, ipnode
, ipnnode
,
1399 XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct ipv6_reachability
));
1401 htonl (circuit
->metrics
[level
- 1].metric_default
);
1402 ip6reach
->control_info
= 0;
1403 ip6reach
->prefix_len
= ipv6
->prefixlen
;
1404 memcpy (&ip6prefix
, &ipv6
, sizeof(ip6prefix
));
1405 apply_mask_ipv6 (ip6prefix
);
1406 memcpy (ip6reach
->prefix
, ip6prefix
->prefix
.s6_addr
,
1407 sizeof (ip6reach
->prefix
));
1408 listnode_add (tlv_data
.ipv6_reachs
, ip6reach
);
1411 #endif /* HAVE_IPV6 */
1413 switch (circuit
->circ_type
)
1415 case CIRCUIT_T_BROADCAST
:
1416 if (level
& circuit
->circuit_is_type
)
1418 if (tlv_data
.is_neighs
== NULL
)
1420 tlv_data
.is_neighs
= list_new ();
1421 tlv_data
.is_neighs
->del
= free_tlv
;
1423 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1425 memcpy (is_neigh
->neigh_id
,
1426 circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1428 memcpy (is_neigh
->neigh_id
,
1429 circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1430 is_neigh
->metrics
= circuit
->metrics
[level
- 1];
1431 listnode_add (tlv_data
.is_neighs
, is_neigh
);
1435 nei
= circuit
->u
.p2p
.neighbor
;
1436 if (nei
&& (level
& nei
->circuit_t
))
1438 if (tlv_data
.is_neighs
== NULL
)
1440 tlv_data
.is_neighs
= list_new ();
1441 tlv_data
.is_neighs
->del
= free_tlv
;
1443 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1444 memcpy (is_neigh
->neigh_id
, nei
->sysid
, ISIS_SYS_ID_LEN
);
1445 is_neigh
->metrics
= circuit
->metrics
[level
- 1];
1446 listnode_add (tlv_data
.is_neighs
, is_neigh
);
1449 case CIRCUIT_T_STATIC_IN
:
1450 zlog_warn ("lsp_area_create: unsupported circuit type");
1452 case CIRCUIT_T_STATIC_OUT
:
1453 zlog_warn ("lsp_area_create: unsupported circuit type");
1456 zlog_warn ("lsp_area_create: unsupported circuit type");
1459 zlog_warn ("lsp_area_create: unknown circuit type");
1463 while (tlv_data
.ipv4_int_reachs
&& listcount (tlv_data
.ipv4_int_reachs
))
1465 if (lsp
->tlv_data
.ipv4_int_reachs
== NULL
)
1466 lsp
->tlv_data
.ipv4_int_reachs
= list_new ();
1467 lsp_tlv_fit (lsp
, &tlv_data
.ipv4_int_reachs
,
1468 &lsp
->tlv_data
.ipv4_int_reachs
,
1469 IPV4_REACH_LEN
, area
->lsp_frag_threshold
,
1470 tlv_add_ipv4_reachs
);
1471 if (tlv_data
.ipv4_int_reachs
&& listcount (tlv_data
.ipv4_int_reachs
))
1472 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1477 while (tlv_data
.ipv6_reachs
&& listcount (tlv_data
.ipv6_reachs
))
1479 if (lsp
->tlv_data
.ipv6_reachs
== NULL
)
1480 lsp
->tlv_data
.ipv6_reachs
= list_new ();
1481 lsp_tlv_fit (lsp
, &tlv_data
.ipv6_reachs
,
1482 &lsp
->tlv_data
.ipv6_reachs
,
1483 IPV6_REACH_LEN
, area
->lsp_frag_threshold
,
1484 tlv_add_ipv6_reachs
);
1485 if (tlv_data
.ipv6_reachs
&& listcount (tlv_data
.ipv6_reachs
))
1486 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1489 #endif /* HAVE_IPV6 */
1491 while (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
1493 if (lsp
->tlv_data
.is_neighs
== NULL
)
1494 lsp
->tlv_data
.is_neighs
= list_new ();
1495 lsp_tlv_fit (lsp
, &tlv_data
.is_neighs
,
1496 &lsp
->tlv_data
.is_neighs
,
1497 IS_NEIGHBOURS_LEN
, area
->lsp_frag_threshold
,
1499 if (tlv_data
.is_neighs
&& listcount (tlv_data
.is_neighs
))
1500 lsp
= lsp_next_frag (LSP_FRAGMENT (lsp
->lsp_header
->lsp_id
) + 1,
1508 #if 0 /* Old code? */
1510 build_lsp_data (struct isis_lsp
*lsp
, struct isis_area
*area
)
1512 struct list
*circuit_list
= area
->circuit_list
;
1513 struct isis_circuit
*circuit
;
1515 struct is_neigh
*is_neigh
;
1518 /* add our nlpids */
1519 /* the 2 is for the TL plus 1 for the nlpid */
1520 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 3);
1521 *tlv_ptr
= PROTOCOLS_SUPPORTED
; /* Type */
1522 *(tlv_ptr
+ 1) = 1; /* one protocol */
1523 #ifdef HAVE_IPV6 /*dunno if its right */
1524 *(tlv_ptr
+ 2) = NLPID_IPV6
;
1526 *(tlv_ptr
+ 2) = NLPID_IP
;
1527 #endif /* HAVE_IPV6 */
1529 /* we should add our areas here
1530 * FIXME: we need to figure out which should be added? Adj? All? First? */
1532 /* first, lets add ourselves to the IS neighbours info */
1533 /* the 2 is for the TL plus 1 for the virtual field */
1534 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 3);
1535 *tlv_ptr
= IS_NEIGHBOURS
; /* Type */
1536 *(tlv_ptr
+ 2) = 0; /* virtual is zero */
1537 lsp
->tlv_data
.is_neighs
= list_new (); /* new list of is_neighbours */
1538 /* assign space for the is_neigh at the pdu end */
1539 is_neigh
= (struct is_neigh
*) lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
,
1540 sizeof (struct is_neigh
));
1541 /* add this node to our list */
1542 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
1543 /* FIXME: Do we need our designated address here? */
1544 memcpy (&is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
+ 1);
1545 /* FIXME: Where should we really get our own LSPs metrics from? */
1546 circuit
= (struct isis_circuit
*) listhead (circuit_list
);
1547 /* is_neigh->metrics = circuit->metrics[lsp->level -1]; */
1550 (lsp
->tlv_data
.is_neighs
->count
* sizeof (struct is_neigh
) + 1);
1552 /* FIXME: scan for adjencecies and add them */
1554 /* FIXME: add reachability info */
1556 /* adding dynamic hostname if needed */
1557 if (area
->dynhostname
)
1559 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 2); /* the 2 is for the TL */
1560 *tlv_ptr
= DYNAMIC_HOSTNAME
; /* Type */
1561 *(tlv_ptr
+ 1) = strlen (unix_hostname ()); /* Length */
1562 lsp
->tlv_data
.hostname
= (struct hostname
*)
1563 (lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
,
1564 /* the -1 is to fit the length in the struct */
1565 strlen (unix_hostname ())) - 1);
1566 memcpy (lsp
->tlv_data
.hostname
->name
, unix_hostname (),
1567 strlen (unix_hostname ()));
1574 * 7.3.7 Generation on non-pseudonode LSPs
1577 lsp_generate_non_pseudo (struct isis_area
*area
, int level
)
1579 struct isis_lsp
*oldlsp
, *newlsp
;
1580 u_int32_t seq_num
= 0;
1581 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1583 memset (&lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1584 memcpy (&lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1586 /* only builds the lsp if the area shares the level */
1587 if ((area
->is_type
& level
) == level
)
1589 oldlsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
1592 seq_num
= ntohl (oldlsp
->lsp_header
->seq_num
);
1593 lsp_search_and_destroy (oldlsp
->lsp_header
->lsp_id
,
1594 area
->lspdb
[level
- 1]);
1595 /* FIXME: we should actually initiate a purge */
1597 newlsp
= lsp_new (lspid
, area
->max_lsp_lifetime
[level
- 1], seq_num
,
1598 area
->is_type
, 0, level
);
1599 newlsp
->own_lsp
= 1;
1601 lsp_insert (newlsp
, area
->lspdb
[level
- 1]);
1602 /* build_lsp_data (newlsp, area); */
1603 lsp_build_nonpseudo (newlsp
, area
);
1604 /* time to calculate our checksum */
1605 lsp_seqnum_update (newlsp
);
1608 /* DEBUG_ADJ_PACKETS */
1609 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
1611 /* FIXME: is this place right? fix missing info */
1612 zlog_debug ("ISIS-Upd (%s): Building L%d LSP", area
->area_tag
, level
);
1619 * 7.3.9 Generation of level 1 LSPs (non-pseudonode)
1622 lsp_l1_generate (struct isis_area
*area
)
1624 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[0], lsp_refresh_l1
, area
,
1625 MAX_LSP_GEN_INTERVAL
);
1627 return lsp_generate_non_pseudo (area
, 1);
1631 * 7.3.9 Generation of level 2 LSPs (non-pseudonode)
1634 lsp_l2_generate (struct isis_area
*area
)
1636 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[1], lsp_refresh_l2
, area
,
1637 MAX_LSP_GEN_INTERVAL
);
1639 return lsp_generate_non_pseudo (area
, 2);
1643 lsp_non_pseudo_regenerate (struct isis_area
*area
, int level
)
1645 dict_t
*lspdb
= area
->lspdb
[level
- 1];
1646 struct isis_lsp
*lsp
, *frag
;
1647 struct listnode
*node
;
1648 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1650 memset (lspid
, 0, ISIS_SYS_ID_LEN
+ 2);
1651 memcpy (lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1653 lsp
= lsp_search (lspid
, lspdb
);
1658 ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!",
1659 area
->area_tag
, level
);
1664 lsp_clear_data (lsp
);
1665 lsp_build_nonpseudo (lsp
, area
);
1666 lsp
->lsp_header
->rem_lifetime
= htons (isis_jitter
1667 (area
->max_lsp_lifetime
[level
- 1],
1669 lsp_seqnum_update (lsp
);
1671 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1673 zlog_debug ("ISIS-Upd (%s): refreshing our L%d LSP %s, "
1674 "seq 0x%08x, cksum 0x%04x lifetime %us",
1677 rawlspid_print (lsp
->lsp_header
->lsp_id
),
1678 ntohl (lsp
->lsp_header
->seq_num
),
1679 ntohs (lsp
->lsp_header
->checksum
),
1680 ntohs (lsp
->lsp_header
->rem_lifetime
));
1683 lsp
->last_generated
= time (NULL
);
1684 area
->lsp_regenerate_pending
[level
- 1] = 0;
1685 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1686 for (ALL_LIST_ELEMENTS_RO (lsp
->lspu
.frags
, node
, frag
))
1688 frag
->lsp_header
->rem_lifetime
= htons (isis_jitter
1690 max_lsp_lifetime
[level
- 1],
1692 ISIS_FLAGS_SET_ALL (frag
->SRMflags
);
1695 if (area
->ip_circuits
)
1696 isis_spf_schedule (area
, level
);
1698 if (area
->ipv6_circuits
)
1699 isis_spf_schedule6 (area
, level
);
1705 * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding
1709 lsp_refresh_l1 (struct thread
*thread
)
1711 struct isis_area
*area
;
1712 unsigned long ref_time
;
1714 area
= THREAD_ARG (thread
);
1717 area
->t_lsp_refresh
[0] = NULL
;
1718 if (area
->is_type
& IS_LEVEL_1
)
1719 lsp_non_pseudo_regenerate (area
, 1);
1721 ref_time
= area
->lsp_refresh
[0] > MAX_LSP_GEN_INTERVAL
?
1722 MAX_LSP_GEN_INTERVAL
: area
->lsp_refresh
[0];
1724 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[0], lsp_refresh_l1
, area
,
1725 isis_jitter (ref_time
, MAX_AGE_JITTER
));
1731 lsp_refresh_l2 (struct thread
*thread
)
1733 struct isis_area
*area
;
1734 unsigned long ref_time
;
1736 area
= THREAD_ARG (thread
);
1739 area
->t_lsp_refresh
[1] = NULL
;
1740 if (area
->is_type
& IS_LEVEL_2
)
1741 lsp_non_pseudo_regenerate (area
, 2);
1743 ref_time
= area
->lsp_refresh
[1] > MAX_LSP_GEN_INTERVAL
?
1744 MAX_LSP_GEN_INTERVAL
: area
->lsp_refresh
[1];
1746 THREAD_TIMER_ON (master
, area
->t_lsp_refresh
[1], lsp_refresh_l2
, area
,
1747 isis_jitter (ref_time
, MAX_AGE_JITTER
));
1753 * Something has changed -> regenerate LSP
1757 lsp_l1_regenerate (struct thread
*thread
)
1759 struct isis_area
*area
;
1761 area
= THREAD_ARG (thread
);
1762 area
->lsp_regenerate_pending
[0] = 0;
1764 return lsp_non_pseudo_regenerate (area
, 1);
1768 lsp_l2_regenerate (struct thread
*thread
)
1770 struct isis_area
*area
;
1772 area
= THREAD_ARG (thread
);
1773 area
->lsp_regenerate_pending
[1] = 0;
1775 return lsp_non_pseudo_regenerate (area
, 2);
1779 lsp_regenerate_schedule (struct isis_area
*area
)
1781 struct isis_lsp
*lsp
;
1782 u_char id
[ISIS_SYS_ID_LEN
+ 2];
1784 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1785 LSP_PSEUDO_ID (id
) = LSP_FRAGMENT (id
) = 0;
1790 if (area
->is_type
& IS_LEVEL_1
)
1792 lsp
= lsp_search (id
, area
->lspdb
[0]);
1793 if (!lsp
|| area
->lsp_regenerate_pending
[0])
1796 * Throttle avoidance
1798 diff
= now
- lsp
->last_generated
;
1799 if (diff
< MIN_LSP_GEN_INTERVAL
)
1801 area
->lsp_regenerate_pending
[0] = 1;
1802 thread_add_timer (master
, lsp_l1_regenerate
, area
,
1803 MIN_LSP_GEN_INTERVAL
- diff
);
1807 lsp_non_pseudo_regenerate (area
, 1);
1813 if (area
->is_type
& IS_LEVEL_2
)
1815 lsp
= lsp_search (id
, area
->lspdb
[1]);
1816 if (!lsp
|| area
->lsp_regenerate_pending
[1])
1819 * Throttle avoidance
1821 diff
= now
- lsp
->last_generated
;
1822 if (diff
< MIN_LSP_GEN_INTERVAL
)
1824 area
->lsp_regenerate_pending
[1] = 1;
1825 thread_add_timer (master
, lsp_l2_regenerate
, area
,
1826 MIN_LSP_GEN_INTERVAL
- diff
);
1830 lsp_non_pseudo_regenerate (area
, 2);
1837 * Funcs for pseudonode LSPs
1841 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1844 lsp_build_pseudo (struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
1847 struct isis_adjacency
*adj
;
1848 struct is_neigh
*is_neigh
;
1849 struct es_neigh
*es_neigh
;
1850 struct list
*adj_list
;
1851 struct listnode
*node
, *nnode
;
1852 struct isis_passwd
*passwd
;
1855 assert (circuit
->circ_type
== CIRCUIT_T_BROADCAST
);
1857 if (!circuit
->u
.bc
.is_dr
[level
- 1])
1858 return; /* we are not DIS on this circuit */
1862 lsp
->lsp_header
->lsp_bits
|= IS_LEVEL_1
;
1864 lsp
->lsp_header
->lsp_bits
|= IS_LEVEL_2
;
1867 * add self to IS neighbours
1869 if (lsp
->tlv_data
.is_neighs
== NULL
)
1871 lsp
->tlv_data
.is_neighs
= list_new ();
1872 lsp
->tlv_data
.is_neighs
->del
= free_tlv
;
1874 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1876 memcpy (&is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1877 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
1879 adj_list
= list_new ();
1880 isis_adj_build_up_list (circuit
->u
.bc
.adjdb
[level
- 1], adj_list
);
1882 for (ALL_LIST_ELEMENTS (adj_list
, node
, nnode
, adj
))
1884 if (adj
->circuit_t
& level
)
1886 if ((level
== 1 && adj
->sys_type
== ISIS_SYSTYPE_L1_IS
) ||
1887 (level
== 1 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
&&
1888 adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
1889 (level
== 2 && adj
->sys_type
== ISIS_SYSTYPE_L2_IS
))
1891 /* an IS neighbour -> add it */
1892 is_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct is_neigh
));
1894 memcpy (&is_neigh
->neigh_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1895 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
1897 else if (level
== 1 && adj
->sys_type
== ISIS_SYSTYPE_ES
)
1899 /* an ES neigbour add it, if we are building level 1 LSP */
1900 /* FIXME: the tlv-format is hard to use here */
1901 if (lsp
->tlv_data
.es_neighs
== NULL
)
1903 lsp
->tlv_data
.es_neighs
= list_new ();
1904 lsp
->tlv_data
.es_neighs
->del
= free_tlv
;
1906 es_neigh
= XCALLOC (MTYPE_ISIS_TLV
, sizeof (struct es_neigh
));
1908 memcpy (&es_neigh
->first_es_neigh
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1909 listnode_add (lsp
->tlv_data
.es_neighs
, es_neigh
);
1915 * Add the authentication info if it's present
1917 (level
== 1) ? (passwd
= &circuit
->area
->area_passwd
) :
1918 (passwd
= &circuit
->area
->domain_passwd
);
1921 memcpy (&lsp
->tlv_data
.auth_info
, passwd
, sizeof (struct isis_passwd
));
1922 tlv_add_authinfo (passwd
->type
, passwd
->len
, passwd
->passwd
, lsp
->pdu
);
1925 if (lsp
->tlv_data
.is_neighs
&& listcount (lsp
->tlv_data
.is_neighs
) > 0)
1926 tlv_add_is_neighs (lsp
->tlv_data
.is_neighs
, lsp
->pdu
);
1928 if (lsp
->tlv_data
.es_neighs
&& listcount (lsp
->tlv_data
.es_neighs
) > 0)
1929 tlv_add_is_neighs (lsp
->tlv_data
.es_neighs
, lsp
->pdu
);
1931 lsp
->lsp_header
->pdu_len
= htons (stream_get_endp (lsp
->pdu
));
1932 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1933 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1935 list_delete (adj_list
);
1941 lsp_pseudo_regenerate (struct isis_circuit
*circuit
, int level
)
1943 dict_t
*lspdb
= circuit
->area
->lspdb
[level
- 1];
1944 struct isis_lsp
*lsp
;
1945 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1947 memcpy (lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1948 LSP_PSEUDO_ID (lsp_id
) = circuit
->circuit_id
;
1949 LSP_FRAGMENT (lsp_id
) = 0;
1951 lsp
= lsp_search (lsp_id
, lspdb
);
1955 zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level
,
1956 rawlspid_print (lsp_id
));
1959 lsp_clear_data (lsp
);
1961 lsp_build_pseudo (lsp
, circuit
, level
);
1963 lsp
->lsp_header
->rem_lifetime
=
1964 htons (isis_jitter (circuit
->area
->max_lsp_lifetime
[level
- 1],
1967 lsp_inc_seqnum (lsp
, 0);
1969 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1971 zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s",
1972 circuit
->area
->area_tag
, level
,
1973 rawlspid_print (lsp
->lsp_header
->lsp_id
));
1976 lsp
->last_generated
= time (NULL
);
1977 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1983 lsp_l1_refresh_pseudo (struct thread
*thread
)
1985 struct isis_circuit
*circuit
;
1987 unsigned long ref_time
;
1989 circuit
= THREAD_ARG (thread
);
1991 if (!circuit
->u
.bc
.is_dr
[0])
1992 return ISIS_ERROR
; /* FIXME: purge and such */
1994 circuit
->u
.bc
.t_refresh_pseudo_lsp
[0] = NULL
;
1996 retval
= lsp_pseudo_regenerate (circuit
, 1);
1998 ref_time
= circuit
->area
->lsp_refresh
[0] > MAX_LSP_GEN_INTERVAL
?
1999 MAX_LSP_GEN_INTERVAL
: circuit
->area
->lsp_refresh
[0];
2001 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[0],
2002 lsp_l1_refresh_pseudo
, circuit
,
2003 isis_jitter (ref_time
, MAX_AGE_JITTER
));
2009 lsp_l1_pseudo_generate (struct isis_circuit
*circuit
)
2011 struct isis_lsp
*lsp
;
2012 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2013 unsigned long ref_time
;
2015 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2016 LSP_FRAGMENT (id
) = 0;
2017 LSP_PSEUDO_ID (id
) = circuit
->circuit_id
;
2020 * If for some reason have a pseudo LSP in the db already -> regenerate
2022 if (lsp_search (id
, circuit
->area
->lspdb
[0]))
2023 return lsp_pseudo_regenerate (circuit
, 1);
2024 lsp
= lsp_new (id
, circuit
->area
->max_lsp_lifetime
[0],
2025 1, circuit
->area
->is_type
, 0, 1);
2027 lsp_build_pseudo (lsp
, circuit
, 1);
2030 lsp_insert (lsp
, circuit
->area
->lspdb
[0]);
2031 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
2033 ref_time
= circuit
->area
->lsp_refresh
[0] > MAX_LSP_GEN_INTERVAL
?
2034 MAX_LSP_GEN_INTERVAL
: circuit
->area
->lsp_refresh
[0];
2036 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[0],
2037 lsp_l1_refresh_pseudo
, circuit
,
2038 isis_jitter (ref_time
, MAX_AGE_JITTER
));
2040 return lsp_regenerate_schedule (circuit
->area
);
2044 lsp_l2_refresh_pseudo (struct thread
*thread
)
2046 struct isis_circuit
*circuit
;
2048 unsigned long ref_time
;
2049 circuit
= THREAD_ARG (thread
);
2051 if (!circuit
->u
.bc
.is_dr
[1])
2052 return ISIS_ERROR
; /* FIXME: purge and such */
2054 circuit
->u
.bc
.t_refresh_pseudo_lsp
[1] = NULL
;
2056 retval
= lsp_pseudo_regenerate (circuit
, 2);
2058 ref_time
= circuit
->area
->lsp_refresh
[1] > MAX_LSP_GEN_INTERVAL
?
2059 MAX_LSP_GEN_INTERVAL
: circuit
->area
->lsp_refresh
[1];
2061 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[1],
2062 lsp_l2_refresh_pseudo
, circuit
,
2063 isis_jitter (ref_time
, MAX_AGE_JITTER
));
2069 lsp_l2_pseudo_generate (struct isis_circuit
*circuit
)
2071 struct isis_lsp
*lsp
;
2072 u_char id
[ISIS_SYS_ID_LEN
+ 2];
2073 unsigned long ref_time
;
2075 memcpy (id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2076 LSP_FRAGMENT (id
) = 0;
2077 LSP_PSEUDO_ID (id
) = circuit
->circuit_id
;
2079 if (lsp_search (id
, circuit
->area
->lspdb
[1]))
2080 return lsp_pseudo_regenerate (circuit
, 2);
2082 lsp
= lsp_new (id
, circuit
->area
->max_lsp_lifetime
[1],
2083 1, circuit
->area
->is_type
, 0, 2);
2085 lsp_build_pseudo (lsp
, circuit
, 2);
2087 ref_time
= circuit
->area
->lsp_refresh
[1] > MAX_LSP_GEN_INTERVAL
?
2088 MAX_LSP_GEN_INTERVAL
: circuit
->area
->lsp_refresh
[1];
2092 lsp_insert (lsp
, circuit
->area
->lspdb
[1]);
2093 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
2095 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_refresh_pseudo_lsp
[1],
2096 lsp_l2_refresh_pseudo
, circuit
,
2097 isis_jitter (ref_time
, MAX_AGE_JITTER
));
2099 return lsp_regenerate_schedule (circuit
->area
);
2103 * Walk through LSPs for an area
2104 * - set remaining lifetime
2105 * - set LSPs with SRMflag set for sending
2108 lsp_tick (struct thread
*thread
)
2110 struct isis_area
*area
;
2111 struct isis_circuit
*circuit
;
2112 struct isis_lsp
*lsp
;
2113 struct list
*lsp_list
;
2114 struct listnode
*lspnode
, *lspnnode
, *cnode
;
2115 dnode_t
*dnode
, *dnode_next
;
2118 lsp_list
= list_new ();
2120 area
= THREAD_ARG (thread
);
2122 area
->t_tick
= NULL
;
2123 THREAD_TIMER_ON (master
, area
->t_tick
, lsp_tick
, area
, 1);
2126 * Build a list of LSPs with (any) SRMflag set
2127 * and removed the ones that have aged out
2129 for (level
= 0; level
< ISIS_LEVELS
; level
++)
2131 if (area
->lspdb
[level
] && dict_count (area
->lspdb
[level
]) > 0)
2133 dnode
= dict_first (area
->lspdb
[level
]);
2134 while (dnode
!= NULL
)
2136 dnode_next
= dict_next (area
->lspdb
[level
], dnode
);
2137 lsp
= dnode_get (dnode
);
2139 if (lsp
->age_out
== 0)
2142 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2145 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2146 ntohl (lsp
->lsp_header
->seq_num
));
2149 dict_delete (area
->lspdb
[level
], dnode
);
2151 else if (flags_any_set (lsp
->SRMflags
))
2152 listnode_add (lsp_list
, lsp
);
2157 * Send LSPs on circuits indicated by the SRMflags
2159 if (listcount (lsp_list
) > 0)
2161 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
2163 for (ALL_LIST_ELEMENTS (lsp_list
, lspnode
, lspnnode
, lsp
))
2165 if (ISIS_CHECK_FLAG (lsp
->SRMflags
, circuit
))
2167 /* FIXME: if same or elder lsp is already in lsp
2169 listnode_add (circuit
->lsp_queue
, lsp
);
2170 thread_add_event (master
, send_lsp
, circuit
, 0);
2175 list_delete_all_node (lsp_list
);
2179 list_delete (lsp_list
);
2185 lsp_purge_dr (u_char
* id
, struct isis_circuit
*circuit
, int level
)
2187 struct isis_lsp
*lsp
;
2189 lsp
= lsp_search (id
, circuit
->area
->lspdb
[level
- 1]);
2191 if (lsp
&& lsp
->purged
== 0)
2193 lsp
->lsp_header
->rem_lifetime
= htons (0);
2194 lsp
->lsp_header
->pdu_len
=
2195 htons (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2197 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
2198 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
2199 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
2206 * Purge own LSP that is received and we don't have.
2207 * -> Do as in 7.3.16.4
2210 lsp_purge_non_exist (struct isis_link_state_hdr
*lsp_hdr
,
2211 struct isis_area
*area
)
2213 struct isis_lsp
*lsp
;
2216 * We need to create the LSP to be purged
2218 zlog_debug ("LSP PURGE NON EXIST");
2219 lsp
= XCALLOC (MTYPE_ISIS_LSP
, sizeof (struct isis_lsp
));
2220 /*FIXME: BUG BUG BUG! the lsp doesn't exist here! */
2221 /*did smt here, maybe good probably not */
2222 lsp
->level
= ((lsp_hdr
->lsp_bits
& LSPBIT_IST
) == IS_LEVEL_1
) ? 1 : 2;
2223 lsp
->pdu
= stream_new (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2224 lsp
->isis_header
= (struct isis_fixed_hdr
*) STREAM_DATA (lsp
->pdu
);
2225 fill_fixed_hdr (lsp
->isis_header
, (lsp
->level
== 1) ? L1_LINK_STATE
2227 lsp
->lsp_header
= (struct isis_link_state_hdr
*) (STREAM_DATA (lsp
->pdu
) +
2228 ISIS_FIXED_HDR_LEN
);
2229 memcpy (lsp
->lsp_header
, lsp_hdr
, ISIS_LSP_HDR_LEN
);
2232 * Retain only LSP header
2234 lsp
->lsp_header
->pdu_len
= htons (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
);
2236 * Set the remaining lifetime to 0
2238 lsp
->lsp_header
->rem_lifetime
= 0;
2240 * Put the lsp into LSPdb
2242 lsp_insert (lsp
, area
->lspdb
[lsp
->level
- 1]);
2245 * Send in to whole area
2247 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
2252 #ifdef TOPOLOGY_GENERATE
2254 top_lsp_refresh (struct thread
*thread
)
2256 struct isis_lsp
*lsp
;
2258 lsp
= THREAD_ARG (thread
);
2261 lsp
->t_lsp_top_ref
= NULL
;
2263 lsp
->lsp_header
->rem_lifetime
=
2264 htons (isis_jitter (MAX_AGE
, MAX_AGE_JITTER
));
2265 lsp
->lsp_header
->seq_num
= htonl (ntohl (lsp
->lsp_header
->seq_num
) + 1);
2267 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
2268 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2270 zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
2271 rawlspid_print (lsp
->lsp_header
->lsp_id
));
2274 /* time to calculate our checksum */
2275 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
2276 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
2277 THREAD_TIMER_ON (master
, lsp
->t_lsp_top_ref
, top_lsp_refresh
, lsp
,
2278 isis_jitter (MAX_LSP_GEN_INTERVAL
, MAX_LSP_GEN_JITTER
));
2284 generate_topology_lsps (struct isis_area
*area
)
2286 struct listnode
*node
;
2289 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
2290 struct isis_lsp
*lsp
;
2292 /* first we find the maximal node */
2293 for (ALL_LIST_ELEMENTS_RO (area
->topology
, node
, arc
))
2295 if (arc
->from_node
> max
)
2296 max
= arc
->from_node
;
2297 if (arc
->to_node
> max
)
2301 for (i
= 1; i
< (max
+ 1); i
++)
2303 memcpy (lspid
, area
->topology_baseis
, ISIS_SYS_ID_LEN
);
2304 LSP_PSEUDO_ID (lspid
) = 0x00;
2305 LSP_FRAGMENT (lspid
) = 0x00;
2306 lspid
[ISIS_SYS_ID_LEN
- 1] = (i
& 0xFF);
2307 lspid
[ISIS_SYS_ID_LEN
- 2] = ((i
>> 8) & 0xFF);
2309 lsp
= lsp_new (lspid
, isis_jitter (area
->max_lsp_lifetime
[0],
2310 MAX_AGE_JITTER
), 1, IS_LEVEL_1
, 0,
2312 lsp
->from_topology
= 1;
2313 /* creating data based on topology */
2314 build_topology_lsp_data (lsp
, area
, i
);
2315 /* time to calculate our checksum */
2316 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
2317 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
2318 THREAD_TIMER_ON (master
, lsp
->t_lsp_top_ref
, top_lsp_refresh
, lsp
,
2319 isis_jitter (MAX_LSP_GEN_INTERVAL
,
2320 MAX_LSP_GEN_JITTER
));
2322 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
2323 lsp_insert (lsp
, area
->lspdb
[0]);
2329 remove_topology_lsps (struct isis_area
*area
)
2331 struct isis_lsp
*lsp
;
2332 dnode_t
*dnode
, *dnode_next
;
2334 dnode
= dict_first (area
->lspdb
[0]);
2335 while (dnode
!= NULL
)
2337 dnode_next
= dict_next (area
->lspdb
[0], dnode
);
2338 lsp
= dnode_get (dnode
);
2339 if (lsp
->from_topology
)
2341 THREAD_TIMER_OFF (lsp
->t_lsp_top_ref
);
2343 dict_delete (area
->lspdb
[0], dnode
);
2350 build_topology_lsp_data (struct isis_lsp
*lsp
, struct isis_area
*area
,
2353 struct listnode
*node
, *nnode
;
2356 struct is_neigh
*is_neigh
;
2360 /* add our nlpids */
2361 /* the 2 is for the TL plus 1 for the nlpid */
2362 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 3);
2363 *tlv_ptr
= PROTOCOLS_SUPPORTED
; /* Type */
2364 *(tlv_ptr
+ 1) = 1; /* one protocol */
2365 *(tlv_ptr
+ 2) = NLPID_IP
;
2366 lsp
->tlv_data
.nlpids
= (struct nlpids
*) (tlv_ptr
+ 1);
2368 /* first, lets add the tops */
2369 /* the 2 is for the TL plus 1 for the virtual field */
2370 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 3);
2371 *tlv_ptr
= IS_NEIGHBOURS
; /* Type */
2372 *(tlv_ptr
+ 1) = 1; /* this is the virtual char len */
2373 *(tlv_ptr
+ 2) = 0; /* virtual is zero */
2374 lsp
->tlv_data
.is_neighs
= list_new (); /* new list of is_neighbours */
2376 /* add reachability for this IS for simulated 1 */
2377 if (lsp_top_num
== 1)
2379 /* assign space for the is_neigh at the pdu end */
2380 is_neigh
= (struct is_neigh
*) lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
,
2383 /* add this node to our list */
2384 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
2385 memcpy (&is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2386 LSP_PSEUDO_ID (is_neigh
->neigh_id
) = 0x00;
2387 is_neigh
->metrics
.metric_default
= 0x00; /* no special reason */
2388 is_neigh
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
2389 is_neigh
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
2390 is_neigh
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
2391 /* don't forget the length */
2392 *(tlv_ptr
+ 1) += IS_NEIGHBOURS_LEN
; /* the -1 is the virtual */
2393 /* no need to check for fragging here, it is a lonely is_reach */
2396 /* addding is reachabilities */
2397 for (ALL_LIST_ELEMENTS (area
->topology
, node
, nnode
, arc
))
2399 if ((arc
->from_node
== lsp_top_num
) || (arc
->to_node
== lsp_top_num
))
2401 if (arc
->to_node
== lsp_top_num
)
2402 to_lsp
= arc
->from_node
;
2403 if (arc
->from_node
== lsp_top_num
)
2404 to_lsp
= arc
->to_node
;
2406 /* if the length here is about to cross the FF limit, we reTLV */
2407 if (*(tlv_ptr
+ 1) >= (0xFF - IS_NEIGHBOURS_LEN
))
2410 /* the 2 is for the TL plus 1 for the virtual field */
2411 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 3);
2412 *tlv_ptr
= IS_NEIGHBOURS
; /* Type */
2413 *(tlv_ptr
+ 1) = 1; /* this is the virtual char len */
2414 *(tlv_ptr
+ 2) = 0; /* virtual is zero */
2416 /* doing this here assures us that we won't add an "empty" tlv */
2417 /* assign space for the is_neigh at the pdu end */
2418 is_neigh
= (struct is_neigh
*) lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
,
2421 /* add this node to our list */
2422 listnode_add (lsp
->tlv_data
.is_neighs
, is_neigh
);
2423 memcpy (&is_neigh
->neigh_id
, area
->topology_baseis
, ISIS_SYS_ID_LEN
);
2424 LSP_PSEUDO_ID (is_neigh
->neigh_id
) = 0x00;
2425 is_neigh
->neigh_id
[ISIS_SYS_ID_LEN
- 1] = (to_lsp
& 0xFF);
2426 is_neigh
->neigh_id
[ISIS_SYS_ID_LEN
- 2] = ((to_lsp
>> 8) & 0xFF);
2427 is_neigh
->metrics
.metric_default
= arc
->distance
;
2428 is_neigh
->metrics
.metric_delay
= METRICS_UNSUPPORTED
;
2429 is_neigh
->metrics
.metric_expense
= METRICS_UNSUPPORTED
;
2430 is_neigh
->metrics
.metric_error
= METRICS_UNSUPPORTED
;
2431 /* don't forget the length */
2432 *(tlv_ptr
+ 1) += IS_NEIGHBOURS_LEN
; /* the -1 is the virtual */
2436 /* adding dynamic hostname if needed */
2437 if (area
->dynhostname
)
2439 memset (buff
, 0x00, 200);
2440 sprintf (buff
, "feedme%d", lsp_top_num
);
2441 /* the 2 is for the TL */
2442 tlv_ptr
= lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, 2);
2443 *tlv_ptr
= DYNAMIC_HOSTNAME
; /* Type */
2444 *(tlv_ptr
+ 1) = strlen (buff
); /* Length */
2445 /* the -1 is to fit the length in the struct */
2446 lsp
->tlv_data
.hostname
= (struct hostname
*)
2447 (lsppdu_realloc (lsp
, MTYPE_ISIS_TLV
, strlen (buff
)) - 1);
2448 memcpy (lsp
->tlv_data
.hostname
->name
, buff
, strlen (buff
));
2451 #endif /* TOPOLOGY_GENERATE */