2 * IS-IS TLV Serializer/Deserializer
4 * Copyright (C) 2015,2017 Christian Franke
6 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
8 * This file is part of FRR.
10 * FRR 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
12 * Free Software Foundation; either version 2, or (at your option) any
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FRR; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #include <json-c/json_object.h>
29 #ifdef CRYPTO_INTERNAL
37 #include "isisd/isisd.h"
38 #include "isisd/isis_tlvs.h"
39 #include "isisd/isis_common.h"
40 #include "isisd/isis_mt.h"
41 #include "isisd/isis_misc.h"
42 #include "isisd/isis_adjacency.h"
43 #include "isisd/isis_circuit.h"
44 #include "isisd/isis_pdu.h"
45 #include "isisd/isis_lsp.h"
46 #include "isisd/isis_te.h"
47 #include "isisd/isis_sr.h"
49 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs");
50 DEFINE_MTYPE(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs");
51 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists");
53 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
54 uint8_t tlv_len
, struct stream
*s
,
55 struct sbuf
*log
, void *dest
, int indent
);
56 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
,
58 typedef void (*free_item_func
)(struct isis_item
*i
);
59 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
60 struct sbuf
*log
, void *dest
, int indent
);
61 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
62 struct sbuf
*buf
, struct json_object
*json
,
64 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
68 unpack_tlv_func unpack
;
70 pack_item_func pack_item
;
71 free_item_func free_item
;
72 unpack_item_func unpack_item
;
73 format_item_func format_item
;
74 copy_item_func copy_item
;
82 struct pack_order_entry
{
83 enum isis_tlv_context context
;
84 enum isis_tlv_type type
;
85 enum how_to_pack how_to_pack
;
88 #define PACK_ENTRY(t, h, w) \
90 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
92 .what_to_pack = offsetof(struct isis_tlvs, w), \
95 static const struct pack_order_entry pack_order
[] = {
96 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
97 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
98 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
99 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
100 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
101 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
102 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
103 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
104 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
105 PACK_ENTRY(GLOBAL_IPV6_ADDRESS
, ISIS_ITEMS
, global_ipv6_address
),
106 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
107 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
108 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
109 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)
112 /* This is a forward definition. The table is actually initialized
113 * in at the bottom. */
114 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
116 /* End of _ops forward definition. */
119 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
120 static void init_item_list(struct isis_item_list
*items
);
122 /* For tests/isisd, TLV text requires ipv4-unicast instead of standard */
123 static const char *isis_mtid2str_fake(uint16_t mtid
)
125 if (mtid
== ISIS_MT_STANDARD
)
126 return "ipv4-unicast";
127 return isis_mtid2str(mtid
);
130 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
131 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
133 struct isis_ext_subtlvs
*ext
;
135 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
136 init_item_list(&ext
->adj_sid
);
137 init_item_list(&ext
->lan_sid
);
139 admin_group_init(&ext
->ext_admin_group
);
144 void isis_del_ext_subtlvs(struct isis_ext_subtlvs
*ext
)
146 struct isis_item
*item
, *next_item
;
151 /* First, free Adj SID and LAN Adj SID list if needed */
152 for (item
= ext
->adj_sid
.head
; item
; item
= next_item
) {
153 next_item
= item
->next
;
154 XFREE(MTYPE_ISIS_SUBTLV
, item
);
156 for (item
= ext
->lan_sid
.head
; item
; item
= next_item
) {
157 next_item
= item
->next
;
158 XFREE(MTYPE_ISIS_SUBTLV
, item
);
161 admin_group_term(&ext
->ext_admin_group
);
163 XFREE(MTYPE_ISIS_SUBTLV
, ext
);
167 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
168 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
169 * that MT is disabled i.e. IS-IS is working with a Single Topology.
171 static struct isis_ext_subtlvs
*
172 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, uint16_t mtid
)
174 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
175 struct isis_adj_sid
*adj
;
176 struct isis_lan_adj_sid
*lan
;
178 /* Copy the Extended IS main part */
179 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
181 /* Disable IPv4 / IPv6 advertisement in function of MTID */
182 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
183 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR6
);
184 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR6
);
186 if (mtid
== ISIS_MT_IPV6_UNICAST
) {
187 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR
);
188 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR
);
191 /* Prepare (LAN)-Adjacency Segment Routing ID*/
192 init_item_list(&rv
->adj_sid
);
193 init_item_list(&rv
->lan_sid
);
195 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
196 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
198 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
199 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
201 if ((mtid
!= ISIS_MT_DISABLE
)
202 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
203 && (adj
->family
!= AF_INET
))
204 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
205 && (adj
->family
!= AF_INET6
))))
208 struct isis_adj_sid
*new;
210 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
211 new->family
= adj
->family
;
212 new->flags
= adj
->flags
;
213 new->weight
= adj
->weight
;
215 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
216 SET_SUBTLV(rv
, EXT_ADJ_SID
);
219 /* Same for LAN Adj SID */
220 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
222 if ((mtid
!= ISIS_MT_DISABLE
)
223 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
224 && (lan
->family
!= AF_INET
))
225 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
226 && (lan
->family
!= AF_INET6
))))
229 struct isis_lan_adj_sid
*new;
231 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
232 new->family
= lan
->family
;
233 new->flags
= lan
->flags
;
234 new->weight
= lan
->weight
;
235 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
237 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
238 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
241 rv
->ext_admin_group
.bitmap
.data
= NULL
;
242 admin_group_copy(&rv
->ext_admin_group
, &exts
->ext_admin_group
);
247 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
248 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
249 struct sbuf
*buf
, struct json_object
*json
,
250 int indent
, uint16_t mtid
)
252 char admin_group_buf
[ADMIN_GROUP_PRINT_MAX_SIZE
];
256 /* Standard metrics */
257 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
259 snprintfrr(aux_buf
, sizeof(aux_buf
), "0x%x",
261 json_object_string_add(json
, "adm-group", aux_buf
);
263 sbuf_push(buf
, indent
, "Administrative Group: 0x%x\n",
265 sbuf_push(buf
, indent
+ 2, "Bit positions: %s\n",
266 admin_group_standard_print(
268 indent
+ strlen("Admin Group: "),
273 if (IS_SUBTLV(exts
, EXT_EXTEND_ADM_GRP
) &&
274 admin_group_nb_words(&exts
->ext_admin_group
) != 0) {
276 /* TODO json after fix show database detail json */
277 sbuf_push(buf
, indent
, "Ext Admin Group: %s\n",
280 ADMIN_GROUP_PRINT_MAX_SIZE
,
281 indent
+ strlen("Ext Admin Group: "),
282 &exts
->ext_admin_group
));
283 admin_group_print(admin_group_buf
,
284 indent
+ strlen("Ext Admin Group: "),
285 &exts
->ext_admin_group
);
286 if (admin_group_buf
[0] != '\0' &&
287 (buf
->pos
+ strlen(admin_group_buf
) +
288 SBUF_DEFAULT_SIZE
/ 2) < buf
->size
)
289 sbuf_push(buf
, indent
+ 2,
290 "Bit positions: %s\n",
294 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
296 json_object_int_add(json
, "link-local-id",
298 json_object_int_add(json
, "link-remote-id",
301 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
303 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
307 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
309 inet_ntop(AF_INET
, &exts
->local_addr
, aux_buf
,
311 json_object_string_add(json
, "local-iface-ip", aux_buf
);
313 sbuf_push(buf
, indent
,
314 "Local Interface IP Address(es): %pI4\n",
317 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
319 inet_ntop(AF_INET
, &exts
->neigh_addr
, aux_buf
,
321 json_object_string_add(json
, "remote-iface-ip",
324 sbuf_push(buf
, indent
,
325 "Remote Interface IP Address(es): %pI4\n",
328 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
330 inet_ntop(AF_INET6
, &exts
->local_addr6
, aux_buf
,
332 json_object_string_add(json
, "local-iface-ipv6",
335 sbuf_push(buf
, indent
,
336 "Local Interface IPv6 Address(es): %pI6\n",
339 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
341 inet_ntop(AF_INET6
, &exts
->neigh_addr6
, aux_buf
,
343 json_object_string_add(json
, "remote-iface-ipv6",
346 sbuf_push(buf
, indent
,
347 "Remote Interface IPv6 Address(es): %pI6\n",
350 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
352 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
354 json_object_string_add(json
, "max-bandwith-bytes-sec",
357 sbuf_push(buf
, indent
,
358 "Maximum Bandwidth: %g (Bytes/sec)\n",
361 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
363 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
365 json_object_string_add(
366 json
, "max-res-bandwith-bytes-sec", aux_buf
);
370 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
373 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
375 struct json_object
*unrsv_json
;
376 unrsv_json
= json_object_new_object();
377 json_object_object_add(json
, "unrsv-bandwith-bytes-sec",
379 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 1) {
380 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d", j
);
381 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
383 json_object_string_add(unrsv_json
, cnt_buf
,
387 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
388 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
391 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
392 j
, exts
->unrsv_bw
[j
], j
+ 1,
393 exts
->unrsv_bw
[j
+ 1]);
397 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
399 json_object_int_add(json
, "te-metric", exts
->te_metric
);
401 sbuf_push(buf
, indent
,
402 "Traffic Engineering Metric: %u\n",
405 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
407 json_object_int_add(json
, "inter-as-te-remote-as",
410 sbuf_push(buf
, indent
,
411 "Inter-AS TE Remote AS number: %u\n",
414 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
416 inet_ntop(AF_INET6
, &exts
->remote_ip
, aux_buf
,
418 json_object_string_add(
419 json
, "inter-as-te-remote-asbr-ip", aux_buf
);
421 sbuf_push(buf
, indent
,
422 "Inter-AS TE Remote ASBR IP address: %pI4\n",
425 /* Extended metrics */
426 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
428 struct json_object
*avg_json
;
429 avg_json
= json_object_new_object();
430 json_object_object_add(json
, "avg-delay", avg_json
);
431 json_object_string_add(avg_json
, "delay",
432 IS_ANORMAL(exts
->delay
)
435 json_object_int_add(avg_json
, "micro-sec", exts
->delay
);
437 sbuf_push(buf
, indent
,
438 "%s Average Link Delay: %u (micro-sec)\n",
439 IS_ANORMAL(exts
->delay
) ? "Anomalous"
441 exts
->delay
& TE_EXT_MASK
);
443 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
445 struct json_object
*avg_json
;
446 avg_json
= json_object_new_object();
447 json_object_object_add(json
, "max-min-delay", avg_json
);
448 json_object_string_add(avg_json
, "delay",
449 IS_ANORMAL(exts
->min_delay
)
452 snprintfrr(aux_buf
, sizeof(aux_buf
), "%u / %u",
453 exts
->min_delay
& TE_EXT_MASK
,
454 exts
->max_delay
& TE_EXT_MASK
);
455 json_object_string_add(avg_json
, "micro-sec", aux_buf
);
460 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
461 IS_ANORMAL(exts
->min_delay
) ? "Anomalous"
463 exts
->min_delay
& TE_EXT_MASK
,
464 exts
->max_delay
& TE_EXT_MASK
);
466 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
468 json_object_int_add(json
, "delay-variation-micro-sec",
469 exts
->delay_var
& TE_EXT_MASK
);
471 sbuf_push(buf
, indent
,
472 "Delay Variation: %u (micro-sec)\n",
473 exts
->delay_var
& TE_EXT_MASK
);
475 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
477 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
478 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
480 struct json_object
*link_json
;
481 link_json
= json_object_new_object();
482 json_object_object_add(json
, "link-packet-loss",
484 json_object_string_add(link_json
, "loss",
485 IS_ANORMAL(exts
->pkt_loss
)
488 json_object_string_add(link_json
, "percentaje",
491 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
492 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous"
494 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
497 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
499 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
501 json_object_string_add(json
,
502 "unidir-residual-band-bytes-sec",
507 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
510 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
512 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
514 json_object_string_add(
515 json
, "unidir-available-band-bytes-sec",
520 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
523 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
525 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
527 json_object_string_add(json
,
528 "unidir-utilized-band-bytes-sec",
533 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
536 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
537 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
538 struct isis_adj_sid
*adj
;
541 struct json_object
*arr_adj_json
, *flags_json
;
542 arr_adj_json
= json_object_new_array();
543 json_object_object_add(json
, "adj-sid", arr_adj_json
);
544 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
545 adj
; adj
= adj
->next
) {
546 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
548 flags_json
= json_object_new_object();
549 json_object_int_add(flags_json
, "sid",
551 json_object_int_add(flags_json
, "weight",
553 json_object_string_add(
554 flags_json
, "flag-f",
555 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
558 json_object_string_add(
559 flags_json
, "flag-b",
560 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
563 json_object_string_add(
564 flags_json
, "flag-v",
565 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
568 json_object_string_add(
569 flags_json
, "flag-l",
570 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
573 json_object_string_add(
574 flags_json
, "flag-s",
575 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
578 json_object_string_add(
579 flags_json
, "flag-p",
580 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
583 json_object_array_add(arr_adj_json
, flags_json
);
586 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
587 adj
; adj
= adj
->next
) {
590 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
591 adj
->sid
, adj
->weight
,
592 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
595 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
598 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
601 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
604 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
607 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
612 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
613 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
614 struct isis_lan_adj_sid
*lan
;
616 struct json_object
*arr_adj_json
, *flags_json
;
617 arr_adj_json
= json_object_new_array();
618 json_object_object_add(json
, "lan-adj-sid",
620 for (lan
= (struct isis_lan_adj_sid
*)
622 lan
; lan
= lan
->next
) {
623 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
624 (lan
->family
!= AF_INET
)) ||
625 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
626 (lan
->family
!= AF_INET6
)))
628 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
630 flags_json
= json_object_new_object();
631 json_object_int_add(flags_json
, "sid",
633 json_object_int_add(flags_json
, "weight",
635 json_object_string_add(
636 flags_json
, "flag-f",
637 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
640 json_object_string_add(
641 flags_json
, "flag-b",
642 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
645 json_object_string_add(
646 flags_json
, "flag-v",
647 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
650 json_object_string_add(
651 flags_json
, "flag-l",
652 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
655 json_object_string_add(
656 flags_json
, "flag-s",
657 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
660 json_object_string_add(
661 flags_json
, "flag-p",
662 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
665 json_object_array_add(arr_adj_json
, flags_json
);
669 for (lan
= (struct isis_lan_adj_sid
*)
671 lan
; lan
= lan
->next
) {
672 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
673 (lan
->family
!= AF_INET
)) ||
674 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
675 (lan
->family
!= AF_INET6
)))
679 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
680 " Neighbor-ID: %s\n",
681 lan
->sid
, lan
->weight
,
682 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
685 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
688 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
691 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
694 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
697 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
700 isis_format_id(lan
->neighbor_id
, 6));
705 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
707 isis_del_ext_subtlvs(exts
);
710 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
711 struct stream
*s
, size_t *min_len
)
715 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
716 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
720 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
721 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
722 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
723 stream_putl(s
, exts
->adm_group
);
725 if (IS_SUBTLV(exts
, EXT_EXTEND_ADM_GRP
) &&
726 admin_group_nb_words(&exts
->ext_admin_group
) != 0) {
727 /* Extended Administrative Group */
729 size_t ag_length_pos
;
730 struct admin_group
*ag
;
732 stream_putc(s
, ISIS_SUBTLV_EXT_ADMIN_GRP
);
733 ag_length_pos
= stream_get_endp(s
);
734 stream_putc(s
, 0); /* length will be filled later*/
736 ag
= &exts
->ext_admin_group
;
737 for (size_t i
= 0; i
< admin_group_nb_words(ag
); i
++)
738 stream_putl(s
, ag
->bitmap
.data
[i
]);
740 ag_length
= stream_get_endp(s
) - ag_length_pos
- 1;
741 stream_putc_at(s
, ag_length_pos
, ag_length
);
743 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
744 stream_putc(s
, ISIS_SUBTLV_LLRI
);
745 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
746 stream_putl(s
, exts
->local_llri
);
747 stream_putl(s
, exts
->remote_llri
);
749 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
750 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
751 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
752 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
754 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
755 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
756 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
757 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
759 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
760 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
761 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
762 stream_put(s
, &exts
->local_addr6
, 16);
764 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
765 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
766 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
767 stream_put(s
, &exts
->neigh_addr6
, 16);
769 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
770 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
771 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
772 stream_putf(s
, exts
->max_bw
);
774 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
775 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
776 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
777 stream_putf(s
, exts
->max_rsv_bw
);
779 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
780 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
781 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
782 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
783 stream_putf(s
, exts
->unrsv_bw
[j
]);
785 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
786 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
787 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
788 stream_put3(s
, exts
->te_metric
);
790 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
791 stream_putc(s
, ISIS_SUBTLV_RAS
);
792 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
793 stream_putl(s
, exts
->remote_as
);
795 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
796 stream_putc(s
, ISIS_SUBTLV_RIP
);
797 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
798 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
800 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
801 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
802 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
803 stream_putl(s
, exts
->delay
);
805 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
806 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
807 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
808 stream_putl(s
, exts
->min_delay
);
809 stream_putl(s
, exts
->max_delay
);
811 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
812 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
813 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
814 stream_putl(s
, exts
->delay_var
);
816 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
817 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
818 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
819 stream_putl(s
, exts
->pkt_loss
);
821 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
822 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
823 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
824 stream_putf(s
, exts
->res_bw
);
826 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
827 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
828 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
829 stream_putf(s
, exts
->ava_bw
);
831 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
832 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
833 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
834 stream_putf(s
, exts
->use_bw
);
836 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
837 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
838 struct isis_adj_sid
*adj
;
840 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
842 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
843 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
844 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
846 stream_putc(s
, size
);
847 stream_putc(s
, adj
->flags
);
848 stream_putc(s
, adj
->weight
);
849 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
850 stream_put3(s
, adj
->sid
);
852 stream_putl(s
, adj
->sid
);
856 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
857 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
858 struct isis_lan_adj_sid
*lan
;
860 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
862 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
863 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
864 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
866 stream_putc(s
, size
);
867 stream_putc(s
, lan
->flags
);
868 stream_putc(s
, lan
->weight
);
869 stream_put(s
, lan
->neighbor_id
, 6);
870 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
871 stream_put3(s
, lan
->sid
);
873 stream_putl(s
, lan
->sid
);
880 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
881 struct sbuf
*log
, void *dest
, int indent
)
889 struct isis_extended_reach
*rv
= dest
;
890 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
895 * Parse subTLVs until reach subTLV length
896 * Check that it remains at least 2 bytes: subTLV Type & Length
898 while (len
> sum
+ 2) {
899 /* Read SubTLV Type and Length */
900 subtlv_type
= stream_getc(s
);
901 subtlv_len
= stream_getc(s
);
902 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
905 "TLV %hhu: Available data %u is less than TLV size %u !\n",
906 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
911 switch (subtlv_type
) {
912 /* Standard Metric as defined in RFC5305 */
913 case ISIS_SUBTLV_ADMIN_GRP
:
914 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
915 sbuf_push(log
, indent
,
916 "TLV size does not match expected size for Administrative Group!\n");
917 stream_forward_getp(s
, subtlv_len
);
919 exts
->adm_group
= stream_getl(s
);
920 SET_SUBTLV(exts
, EXT_ADM_GRP
);
923 case ISIS_SUBTLV_EXT_ADMIN_GRP
:
924 nb_groups
= subtlv_len
/ sizeof(uint32_t);
925 for (size_t i
= 0; i
< nb_groups
; i
++) {
926 val
= stream_getl(s
);
927 admin_group_bulk_set(&exts
->ext_admin_group
,
930 SET_SUBTLV(exts
, EXT_EXTEND_ADM_GRP
);
932 case ISIS_SUBTLV_LLRI
:
933 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
934 sbuf_push(log
, indent
,
935 "TLV size does not match expected size for Link ID!\n");
936 stream_forward_getp(s
, subtlv_len
);
938 exts
->local_llri
= stream_getl(s
);
939 exts
->remote_llri
= stream_getl(s
);
940 SET_SUBTLV(exts
, EXT_LLRI
);
943 case ISIS_SUBTLV_LOCAL_IPADDR
:
944 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
945 sbuf_push(log
, indent
,
946 "TLV size does not match expected size for Local IP address!\n");
947 stream_forward_getp(s
, subtlv_len
);
949 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
950 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
953 case ISIS_SUBTLV_RMT_IPADDR
:
954 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
955 sbuf_push(log
, indent
,
956 "TLV size does not match expected size for Remote IP address!\n");
957 stream_forward_getp(s
, subtlv_len
);
959 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
960 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
963 case ISIS_SUBTLV_LOCAL_IPADDR6
:
964 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
965 sbuf_push(log
, indent
,
966 "TLV size does not match expected size for Local IPv6 address!\n");
967 stream_forward_getp(s
, subtlv_len
);
969 stream_get(&exts
->local_addr6
, s
, 16);
970 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
973 case ISIS_SUBTLV_RMT_IPADDR6
:
974 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
975 sbuf_push(log
, indent
,
976 "TLV size does not match expected size for Remote IPv6 address!\n");
977 stream_forward_getp(s
, subtlv_len
);
979 stream_get(&exts
->neigh_addr6
, s
, 16);
980 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
983 case ISIS_SUBTLV_MAX_BW
:
984 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
985 sbuf_push(log
, indent
,
986 "TLV size does not match expected size for Maximum Bandwidth!\n");
987 stream_forward_getp(s
, subtlv_len
);
989 exts
->max_bw
= stream_getf(s
);
990 SET_SUBTLV(exts
, EXT_MAX_BW
);
993 case ISIS_SUBTLV_MAX_RSV_BW
:
994 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
995 sbuf_push(log
, indent
,
996 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
997 stream_forward_getp(s
, subtlv_len
);
999 exts
->max_rsv_bw
= stream_getf(s
);
1000 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
1003 case ISIS_SUBTLV_UNRSV_BW
:
1004 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
1005 sbuf_push(log
, indent
,
1006 "TLV size does not match expected size for Unreserved Bandwidth!\n");
1007 stream_forward_getp(s
, subtlv_len
);
1009 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
1010 exts
->unrsv_bw
[i
] = stream_getf(s
);
1011 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
1014 case ISIS_SUBTLV_TE_METRIC
:
1015 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
1016 sbuf_push(log
, indent
,
1017 "TLV size does not match expected size for Traffic Engineering Metric!\n");
1018 stream_forward_getp(s
, subtlv_len
);
1020 exts
->te_metric
= stream_get3(s
);
1021 SET_SUBTLV(exts
, EXT_TE_METRIC
);
1024 case ISIS_SUBTLV_RAS
:
1025 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1026 sbuf_push(log
, indent
,
1027 "TLV size does not match expected size for Remote AS number!\n");
1028 stream_forward_getp(s
, subtlv_len
);
1030 exts
->remote_as
= stream_getl(s
);
1031 SET_SUBTLV(exts
, EXT_RMT_AS
);
1034 case ISIS_SUBTLV_RIP
:
1035 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1036 sbuf_push(log
, indent
,
1037 "TLV size does not match expected size for Remote ASBR IP Address!\n");
1038 stream_forward_getp(s
, subtlv_len
);
1040 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
1041 SET_SUBTLV(exts
, EXT_RMT_IP
);
1044 /* Extended Metrics as defined in RFC 7810 */
1045 case ISIS_SUBTLV_AV_DELAY
:
1046 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1047 sbuf_push(log
, indent
,
1048 "TLV size does not match expected size for Average Link Delay!\n");
1049 stream_forward_getp(s
, subtlv_len
);
1051 exts
->delay
= stream_getl(s
);
1052 SET_SUBTLV(exts
, EXT_DELAY
);
1055 case ISIS_SUBTLV_MM_DELAY
:
1056 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
1057 sbuf_push(log
, indent
,
1058 "TLV size does not match expected size for Min/Max Link Delay!\n");
1059 stream_forward_getp(s
, subtlv_len
);
1061 exts
->min_delay
= stream_getl(s
);
1062 exts
->max_delay
= stream_getl(s
);
1063 SET_SUBTLV(exts
, EXT_MM_DELAY
);
1066 case ISIS_SUBTLV_DELAY_VAR
:
1067 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1068 sbuf_push(log
, indent
,
1069 "TLV size does not match expected size for Delay Variation!\n");
1070 stream_forward_getp(s
, subtlv_len
);
1072 exts
->delay_var
= stream_getl(s
);
1073 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
1076 case ISIS_SUBTLV_PKT_LOSS
:
1077 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1078 sbuf_push(log
, indent
,
1079 "TLV size does not match expected size for Link Packet Loss!\n");
1080 stream_forward_getp(s
, subtlv_len
);
1082 exts
->pkt_loss
= stream_getl(s
);
1083 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
1086 case ISIS_SUBTLV_RES_BW
:
1087 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1088 sbuf_push(log
, indent
,
1089 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
1090 stream_forward_getp(s
, subtlv_len
);
1092 exts
->res_bw
= stream_getf(s
);
1093 SET_SUBTLV(exts
, EXT_RES_BW
);
1096 case ISIS_SUBTLV_AVA_BW
:
1097 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1098 sbuf_push(log
, indent
,
1099 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
1100 stream_forward_getp(s
, subtlv_len
);
1102 exts
->ava_bw
= stream_getf(s
);
1103 SET_SUBTLV(exts
, EXT_AVA_BW
);
1106 case ISIS_SUBTLV_USE_BW
:
1107 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1108 sbuf_push(log
, indent
,
1109 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
1110 stream_forward_getp(s
, subtlv_len
);
1112 exts
->use_bw
= stream_getf(s
);
1113 SET_SUBTLV(exts
, EXT_USE_BW
);
1116 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1117 case ISIS_SUBTLV_ADJ_SID
:
1118 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
1119 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
1120 sbuf_push(log
, indent
,
1121 "TLV size does not match expected size for Adjacency SID!\n");
1122 stream_forward_getp(s
, subtlv_len
);
1124 struct isis_adj_sid
*adj
;
1126 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1127 sizeof(struct isis_adj_sid
));
1128 adj
->flags
= stream_getc(s
);
1129 adj
->weight
= stream_getc(s
);
1130 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1131 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
1134 "TLV size does not match expected size for Adjacency SID!\n");
1135 stream_forward_getp(s
, subtlv_len
- 2);
1136 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
1140 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1142 != ISIS_SUBTLV_ADJ_SID_SIZE
1146 "TLV size does not match expected size for Adjacency SID!\n");
1147 stream_forward_getp(s
, subtlv_len
- 2);
1148 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
1152 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1153 adj
->sid
= stream_get3(s
);
1154 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
1156 adj
->sid
= stream_getl(s
);
1158 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1159 adj
->family
= AF_INET
;
1160 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1161 adj
->family
= AF_INET6
;
1162 append_item(&exts
->adj_sid
,
1163 (struct isis_item
*)adj
);
1164 SET_SUBTLV(exts
, EXT_ADJ_SID
);
1167 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1168 case ISIS_SUBTLV_LAN_ADJ_SID
:
1169 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1170 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
1171 sbuf_push(log
, indent
,
1172 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1173 stream_forward_getp(s
, subtlv_len
);
1175 struct isis_lan_adj_sid
*lan
;
1177 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1178 sizeof(struct isis_lan_adj_sid
));
1179 lan
->flags
= stream_getc(s
);
1180 lan
->weight
= stream_getc(s
);
1181 stream_get(&(lan
->neighbor_id
), s
,
1184 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1186 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
1189 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1190 stream_forward_getp(
1193 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
1197 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1199 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1203 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1204 stream_forward_getp(
1207 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
1211 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1212 lan
->sid
= stream_get3(s
);
1213 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
1215 lan
->sid
= stream_getl(s
);
1217 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1218 lan
->family
= AF_INET
;
1219 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1220 lan
->family
= AF_INET6
;
1221 append_item(&exts
->lan_sid
,
1222 (struct isis_item
*)lan
);
1223 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
1227 /* Skip unknown TLV */
1228 stream_forward_getp(s
, subtlv_len
);
1231 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
1237 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1238 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
1240 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1241 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1243 rv
->flags
= sid
->flags
;
1244 rv
->algorithm
= sid
->algorithm
;
1245 rv
->value
= sid
->value
;
1246 return (struct isis_item
*)rv
;
1249 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
1250 struct sbuf
*buf
, struct json_object
*json
,
1253 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1256 struct json_object
*sr_json
;
1257 sr_json
= json_object_new_object();
1258 json_object_object_add(json
, "sr", sr_json
);
1259 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1260 json_object_int_add(sr_json
, "label", sid
->value
);
1262 json_object_int_add(sr_json
, "index", sid
->value
);
1264 json_object_int_add(sr_json
, "alg", sid
->algorithm
);
1265 json_object_string_add(
1266 sr_json
, "readvertised",
1267 ((sid
->flags
& ISIS_PREFIX_SID_READVERTISED
) ? "yes"
1269 json_object_string_add(
1271 ((sid
->flags
& ISIS_PREFIX_SID_NODE
) ? "yes" : ""));
1272 json_object_string_add(sr_json
, "php",
1273 ((sid
->flags
& ISIS_PREFIX_SID_NO_PHP
)
1276 json_object_string_add(
1277 sr_json
, "explicit-null",
1278 ((sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
) ? "yes"
1280 json_object_string_add(
1282 ((sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? "yes" : ""));
1283 json_object_string_add(
1285 ((sid
->flags
& ISIS_PREFIX_SID_LOCAL
) ? "yes" : ""));
1288 sbuf_push(buf
, indent
, "SR Prefix-SID ");
1289 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1290 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
1292 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
1294 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
1295 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
1296 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
1299 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
1300 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP"
1302 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
1305 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
1306 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
1310 static void free_item_prefix_sid(struct isis_item
*i
)
1312 XFREE(MTYPE_ISIS_SUBTLV
, i
);
1315 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
1318 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1320 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
1322 if (STREAM_WRITEABLE(s
) < size
) {
1327 stream_putc(s
, sid
->flags
);
1328 stream_putc(s
, sid
->algorithm
);
1330 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1331 stream_put3(s
, sid
->value
);
1333 stream_putl(s
, sid
->value
);
1339 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1340 struct sbuf
*log
, void *dest
, int indent
)
1342 struct isis_subtlvs
*subtlvs
= dest
;
1343 struct isis_prefix_sid sid
= {
1346 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
1349 sbuf_push(log
, indent
,
1350 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1355 sid
.flags
= stream_getc(s
);
1356 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1357 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
1358 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
1362 sid
.algorithm
= stream_getc(s
);
1364 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1365 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1366 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
1367 if (len
!= expected_size
) {
1368 sbuf_push(log
, indent
,
1369 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1370 expected_size
, len
);
1374 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
1375 sid
.value
= stream_get3(s
);
1376 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
1377 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
1382 sid
.value
= stream_getl(s
);
1385 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, NULL
, indent
+ 2);
1386 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
1390 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1392 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
1397 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1398 rv
->family
= p
->family
;
1399 rv
->prefixlen
= p
->prefixlen
;
1400 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
1404 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1406 struct json_object
*json
,
1412 char prefixbuf
[PREFIX2STR_BUFFER
];
1414 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
));
1415 json_object_string_add(json
, "ipv6-src-prefix", prefixbuf
);
1417 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1418 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1422 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1428 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1431 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1432 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1433 stream_putc(s
, p
->prefixlen
);
1434 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1438 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1439 uint8_t tlv_type
, uint8_t tlv_len
,
1440 struct stream
*s
, struct sbuf
*log
,
1441 void *dest
, int indent
)
1443 struct isis_subtlvs
*subtlvs
= dest
;
1444 struct prefix_ipv6 p
= {
1448 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1451 sbuf_push(log
, indent
,
1452 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1457 p
.prefixlen
= stream_getc(s
);
1458 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1459 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1464 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1467 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1468 1 + PSIZE(p
.prefixlen
), tlv_len
);
1472 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1474 if (subtlvs
->source_prefix
) {
1477 "WARNING: source prefix Sub-TLV present multiple times.\n");
1478 /* Ignore all but first occurrence of the source prefix Sub-TLV
1483 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1484 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1488 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1489 enum isis_tlv_type type
,
1490 struct isis_item
*item
);
1491 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1492 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1493 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1494 enum isis_tlv_type type
, struct isis_item_list
*items
,
1495 struct sbuf
*buf
, struct json_object
*json
,
1497 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1498 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1499 struct isis_item_list
*items
);
1500 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1501 enum isis_tlv_type type
, struct isis_item_list
*items
,
1502 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1503 const struct pack_order_entry
*pe
,
1504 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1505 struct list
*new_fragment_arg
);
1506 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1508 /* Functions related to subtlvs */
1510 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1512 struct isis_subtlvs
*result
;
1514 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1515 result
->context
= context
;
1517 init_item_list(&result
->prefix_sids
);
1522 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1527 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1529 rv
->context
= subtlvs
->context
;
1531 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1532 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1535 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1539 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1540 struct json_object
*json
, int indent
)
1542 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1543 &subtlvs
->prefix_sids
, buf
, json
, indent
);
1545 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, json
, indent
);
1548 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1553 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1554 &subtlvs
->prefix_sids
);
1556 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1558 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1561 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1564 size_t subtlv_len_pos
= stream_get_endp(s
);
1566 if (STREAM_WRITEABLE(s
) < 1)
1569 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1571 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1572 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1576 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1580 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1581 if (subtlv_len
> 255)
1584 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1588 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1589 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1590 int indent
, bool *unpacked_known_tlvs
);
1592 /* Functions related to TLVs 1 Area Addresses */
1594 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1596 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1597 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1599 rv
->len
= addr
->len
;
1600 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1601 return (struct isis_item
*)rv
;
1604 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1605 struct sbuf
*buf
, struct json_object
*json
,
1608 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1611 json_object_string_add(json
, "area-addr",
1612 isonet_print(addr
->addr
, addr
->len
));
1614 sbuf_push(buf
, indent
, "Area Address: %s\n",
1615 isonet_print(addr
->addr
, addr
->len
));
1619 static void free_item_area_address(struct isis_item
*i
)
1621 XFREE(MTYPE_ISIS_TLV
, i
);
1624 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
1627 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1629 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
1630 *min_len
= (unsigned)1 + addr
->len
;
1633 stream_putc(s
, addr
->len
);
1634 stream_put(s
, addr
->addr
, addr
->len
);
1638 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1639 struct stream
*s
, struct sbuf
*log
,
1640 void *dest
, int indent
)
1642 struct isis_tlvs
*tlvs
= dest
;
1643 struct isis_area_address
*rv
= NULL
;
1645 sbuf_push(log
, indent
, "Unpack area address...\n");
1649 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1654 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1655 rv
->len
= stream_getc(s
);
1657 if (len
< 1 + rv
->len
) {
1658 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1663 if (rv
->len
< 1 || rv
->len
> 20) {
1664 sbuf_push(log
, indent
,
1665 "Implausible area address length %hhu\n",
1670 stream_get(rv
->addr
, s
, rv
->len
);
1672 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1673 log
, NULL
, indent
+ 2);
1674 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1677 XFREE(MTYPE_ISIS_TLV
, rv
);
1681 /* Functions related to TLV 2 (Old-Style) IS Reach */
1682 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1684 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1685 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1687 memcpy(rv
->id
, r
->id
, 7);
1688 rv
->metric
= r
->metric
;
1689 return (struct isis_item
*)rv
;
1692 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1694 struct json_object
*json
, int indent
)
1696 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1699 struct json_object
*old_json
;
1700 old_json
= json_object_new_object();
1701 json_object_object_add(json
, "old-reach-style", old_json
);
1702 json_object_string_add(old_json
, "is-reach",
1703 isis_format_id(r
->id
, 7));
1704 json_object_int_add(old_json
, "metric", r
->metric
);
1706 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
1707 isis_format_id(r
->id
, 7), r
->metric
);
1710 static void free_item_oldstyle_reach(struct isis_item
*i
)
1712 XFREE(MTYPE_ISIS_TLV
, i
);
1715 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
1718 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1720 if (STREAM_WRITEABLE(s
) < 11) {
1725 stream_putc(s
, r
->metric
);
1726 stream_putc(s
, 0x80); /* delay metric - unsupported */
1727 stream_putc(s
, 0x80); /* expense metric - unsupported */
1728 stream_putc(s
, 0x80); /* error metric - unsupported */
1729 stream_put(s
, r
->id
, 7);
1734 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1735 struct stream
*s
, struct sbuf
*log
,
1736 void *dest
, int indent
)
1738 struct isis_tlvs
*tlvs
= dest
;
1740 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1744 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1749 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1750 rv
->metric
= stream_getc(s
);
1751 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1752 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1755 stream_forward_getp(s
, 3); /* Skip other metrics */
1756 stream_get(rv
->id
, s
, 7);
1758 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1760 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1764 /* Functions related to TLV 6 LAN Neighbors */
1765 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1767 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1768 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1770 memcpy(rv
->mac
, n
->mac
, 6);
1771 return (struct isis_item
*)rv
;
1774 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1775 struct sbuf
*buf
, struct json_object
*json
,
1778 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1781 json_object_string_add(json
, "lan-neighbor",
1782 isis_format_id(n
->mac
, 6));
1784 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n",
1785 isis_format_id(n
->mac
, 6));
1788 static void free_item_lan_neighbor(struct isis_item
*i
)
1790 XFREE(MTYPE_ISIS_TLV
, i
);
1793 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
1796 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1798 if (STREAM_WRITEABLE(s
) < 6) {
1803 stream_put(s
, n
->mac
, 6);
1808 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1809 struct stream
*s
, struct sbuf
*log
,
1810 void *dest
, int indent
)
1812 struct isis_tlvs
*tlvs
= dest
;
1814 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1818 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1823 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1824 stream_get(rv
->mac
, s
, 6);
1826 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1827 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1831 /* Functions related to TLV 9 LSP Entry */
1832 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1834 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1835 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1837 rv
->rem_lifetime
= e
->rem_lifetime
;
1838 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1839 rv
->seqno
= e
->seqno
;
1840 rv
->checksum
= e
->checksum
;
1842 return (struct isis_item
*)rv
;
1845 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1846 struct sbuf
*buf
, struct json_object
*json
,
1849 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1853 struct json_object
*lsp_json
;
1854 lsp_json
= json_object_new_object();
1855 json_object_object_add(json
, "lsp-entry", lsp_json
);
1856 json_object_string_add(lsp_json
, "id", isis_format_id(e
->id
, 8));
1857 snprintfrr(buf
,sizeof(buf
),"0x%08x",e
->seqno
);
1858 json_object_string_add(lsp_json
, "seq", buf
);
1859 snprintfrr(buf
,sizeof(buf
),"0x%04hx",e
->checksum
);
1860 json_object_string_add(lsp_json
, "chksum", buf
);
1861 json_object_int_add(lsp_json
, "lifetime", e
->checksum
);
1863 sbuf_push(buf
, indent
,
1864 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1865 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1869 static void free_item_lsp_entry(struct isis_item
*i
)
1871 XFREE(MTYPE_ISIS_TLV
, i
);
1874 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
1877 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1879 if (STREAM_WRITEABLE(s
) < 16) {
1884 stream_putw(s
, e
->rem_lifetime
);
1885 stream_put(s
, e
->id
, 8);
1886 stream_putl(s
, e
->seqno
);
1887 stream_putw(s
, e
->checksum
);
1892 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1893 struct sbuf
*log
, void *dest
, int indent
)
1895 struct isis_tlvs
*tlvs
= dest
;
1897 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1901 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1906 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1907 rv
->rem_lifetime
= stream_getw(s
);
1908 stream_get(rv
->id
, s
, 8);
1909 rv
->seqno
= stream_getl(s
);
1910 rv
->checksum
= stream_getw(s
);
1912 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1913 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1917 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1919 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1921 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1922 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1924 memcpy(rv
->id
, r
->id
, 7);
1925 rv
->metric
= r
->metric
;
1928 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1930 return (struct isis_item
*)rv
;
1933 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1935 struct json_object
*json
, int indent
)
1937 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1940 struct json_object
*reach_json
;
1941 reach_json
= json_object_new_object();
1942 json_object_object_add(json
, "ext-reach", reach_json
);
1943 json_object_string_add(
1944 reach_json
, "mt-id",
1945 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
1946 json_object_string_add(reach_json
, "id",
1947 isis_format_id(r
->id
, 7));
1948 json_object_int_add(reach_json
, "metric", r
->metric
);
1949 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1950 json_object_string_add(reach_json
, "mt-name",
1951 isis_mtid2str(mtid
));
1954 format_item_ext_subtlvs(r
->subtlvs
, NULL
, json
,
1957 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1958 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1959 isis_format_id(r
->id
, 7), r
->metric
);
1960 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1961 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1962 sbuf_push(buf
, 0, "\n");
1965 format_item_ext_subtlvs(r
->subtlvs
, buf
, NULL
,
1970 static void free_item_extended_reach(struct isis_item
*i
)
1972 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1974 if (item
->subtlvs
!= NULL
)
1975 free_item_ext_subtlvs(item
->subtlvs
);
1976 XFREE(MTYPE_ISIS_TLV
, item
);
1979 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
1982 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1986 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
1987 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
1991 stream_put(s
, r
->id
, sizeof(r
->id
));
1992 stream_put3(s
, r
->metric
);
1993 len_pos
= stream_get_endp(s
);
1994 /* Real length will be adjust after adding subTLVs */
1997 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
1999 len
= stream_get_endp(s
) - len_pos
- 1;
2000 stream_putc_at(s
, len_pos
, len
);
2004 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
2005 struct stream
*s
, struct sbuf
*log
,
2006 void *dest
, int indent
)
2008 struct isis_tlvs
*tlvs
= dest
;
2009 struct isis_extended_reach
*rv
= NULL
;
2011 struct isis_item_list
*items
;
2013 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2014 items
= &tlvs
->extended_reach
;
2016 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
2019 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
2020 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2023 sbuf_push(log
, indent
,
2024 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
2029 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2030 stream_get(rv
->id
, s
, 7);
2031 rv
->metric
= stream_get3(s
);
2032 subtlv_len
= stream_getc(s
);
2034 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
2035 sbuf_push(log
, indent
,
2036 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
2037 subtlv_len
, len
- 11);
2041 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
2045 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
2051 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2053 append_item(items
, (struct isis_item
*)rv
);
2057 free_item_extended_reach((struct isis_item
*)rv
);
2062 /* Functions related to TLV 128 (Old-Style) IP Reach */
2063 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
2065 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2066 struct isis_oldstyle_ip_reach
*rv
=
2067 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2069 rv
->metric
= r
->metric
;
2070 rv
->prefix
= r
->prefix
;
2071 return (struct isis_item
*)rv
;
2074 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2076 struct json_object
*json
, int indent
)
2078 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2079 char prefixbuf
[PREFIX2STR_BUFFER
];
2082 struct json_object
*old_json
;
2083 old_json
= json_object_new_object();
2084 json_object_object_add(json
, "old-ip-reach-style", old_json
);
2085 json_object_string_add(old_json
, "prefix",
2086 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2087 json_object_int_add(old_json
, "metric", r
->metric
);
2089 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
2090 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2094 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
2096 XFREE(MTYPE_ISIS_TLV
, i
);
2099 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
2102 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2104 if (STREAM_WRITEABLE(s
) < 12) {
2109 stream_putc(s
, r
->metric
);
2110 stream_putc(s
, 0x80); /* delay metric - unsupported */
2111 stream_putc(s
, 0x80); /* expense metric - unsupported */
2112 stream_putc(s
, 0x80); /* error metric - unsupported */
2113 stream_put(s
, &r
->prefix
.prefix
, 4);
2115 struct in_addr mask
;
2116 masklen2ip(r
->prefix
.prefixlen
, &mask
);
2117 stream_put(s
, &mask
, sizeof(mask
));
2122 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
2123 struct stream
*s
, struct sbuf
*log
,
2124 void *dest
, int indent
)
2126 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
2130 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2135 struct isis_oldstyle_ip_reach
*rv
=
2136 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2137 rv
->metric
= stream_getc(s
);
2138 if ((rv
->metric
& 0x7f) != rv
->metric
) {
2139 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2142 stream_forward_getp(s
, 3); /* Skip other metrics */
2143 rv
->prefix
.family
= AF_INET
;
2144 stream_get(&rv
->prefix
.prefix
, s
, 4);
2146 struct in_addr mask
;
2147 stream_get(&mask
, s
, 4);
2148 rv
->prefix
.prefixlen
= ip_masklen(mask
);
2150 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2152 append_item(dest
, (struct isis_item
*)rv
);
2157 /* Functions related to TLV 129 protocols supported */
2159 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
2160 struct isis_protocols_supported
*dest
)
2162 if (!src
->protocols
|| !src
->count
)
2164 dest
->count
= src
->count
;
2165 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
2166 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
2169 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2171 struct json_object
*json
, int indent
)
2173 if (!p
|| !p
->count
|| !p
->protocols
)
2177 struct json_object
*protocol_json
;
2180 protocol_json
= json_object_new_object();
2181 json_object_object_add(json
, "protocols-supported",
2183 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2184 snprintfrr(buf
, sizeof(buf
), "%d", i
);
2185 json_object_string_add(protocol_json
, buf
,
2186 nlpid2str(p
->protocols
[i
]));
2189 sbuf_push(buf
, indent
, "Protocols Supported: ");
2190 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2191 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
2192 (i
+ 1 < p
->count
) ? ", " : "");
2194 sbuf_push(buf
, 0, "\n");
2198 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
2200 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
2203 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2206 if (!p
|| !p
->count
|| !p
->protocols
)
2209 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
2212 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
2213 stream_putc(s
, p
->count
);
2214 stream_put(s
, p
->protocols
, p
->count
);
2218 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
2219 uint8_t tlv_type
, uint8_t tlv_len
,
2220 struct stream
*s
, struct sbuf
*log
,
2221 void *dest
, int indent
)
2223 struct isis_tlvs
*tlvs
= dest
;
2225 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
2227 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
2230 if (tlvs
->protocols_supported
.protocols
) {
2233 "WARNING: protocols supported TLV present multiple times.\n");
2234 stream_forward_getp(s
, tlv_len
);
2238 tlvs
->protocols_supported
.count
= tlv_len
;
2239 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
2240 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
2242 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
, NULL
,
2247 /* Functions related to TLV 132 IPv4 Interface addresses */
2248 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
2250 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2251 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2254 return (struct isis_item
*)rv
;
2257 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
2258 struct sbuf
*buf
, struct json_object
*json
,
2261 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2262 char addrbuf
[INET_ADDRSTRLEN
];
2264 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2266 json_object_string_add(json
, "ipv4", addrbuf
);
2268 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
2272 static void free_item_ipv4_address(struct isis_item
*i
)
2274 XFREE(MTYPE_ISIS_TLV
, i
);
2277 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
2280 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2282 if (STREAM_WRITEABLE(s
) < 4) {
2287 stream_put(s
, &a
->addr
, 4);
2292 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
2293 struct stream
*s
, struct sbuf
*log
,
2294 void *dest
, int indent
)
2296 struct isis_tlvs
*tlvs
= dest
;
2298 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
2302 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2307 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2308 stream_get(&rv
->addr
, s
, 4);
2310 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2311 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
2316 /* Functions related to TLV 232 IPv6 Interface addresses */
2317 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
2319 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2320 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2323 return (struct isis_item
*)rv
;
2326 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2327 struct sbuf
*buf
, struct json_object
*json
,
2330 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2331 char addrbuf
[INET6_ADDRSTRLEN
];
2333 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2335 json_object_string_add(json
, "ipv6", addrbuf
);
2337 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
2340 static void free_item_ipv6_address(struct isis_item
*i
)
2342 XFREE(MTYPE_ISIS_TLV
, i
);
2345 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2348 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2350 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2351 *min_len
= IPV6_MAX_BYTELEN
;
2355 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2360 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
2361 struct stream
*s
, struct sbuf
*log
,
2362 void *dest
, int indent
)
2364 struct isis_tlvs
*tlvs
= dest
;
2366 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
2370 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2375 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2376 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2378 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2379 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
2384 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2385 static struct isis_item
*copy_item_global_ipv6_address(struct isis_item
*i
)
2387 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2388 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2391 return (struct isis_item
*)rv
;
2394 static void format_item_global_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2396 struct json_object
*json
,
2399 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2400 char addrbuf
[INET6_ADDRSTRLEN
];
2402 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2404 json_object_string_add(json
, "global-ipv6", addrbuf
);
2406 sbuf_push(buf
, indent
, "Global IPv6 Interface Address: %s\n",
2410 static void free_item_global_ipv6_address(struct isis_item
*i
)
2412 XFREE(MTYPE_ISIS_TLV
, i
);
2415 static int pack_item_global_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2418 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2420 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2421 *min_len
= IPV6_MAX_BYTELEN
;
2425 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2430 static int unpack_item_global_ipv6_address(uint16_t mtid
, uint8_t len
,
2431 struct stream
*s
, struct sbuf
*log
,
2432 void *dest
, int indent
)
2434 struct isis_tlvs
*tlvs
= dest
;
2436 sbuf_push(log
, indent
, "Unpack Global IPv6 Interface address...\n");
2437 if (len
< IPV6_MAX_BYTELEN
) {
2440 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2445 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2446 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2448 format_item_global_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2450 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)rv
);
2454 /* Functions related to TLV 229 MT Router information */
2455 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
2457 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2458 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2460 rv
->overload
= info
->overload
;
2461 rv
->attached
= info
->attached
;
2462 rv
->mtid
= info
->mtid
;
2463 return (struct isis_item
*)rv
;
2466 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
2468 struct json_object
*json
, int indent
)
2470 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2473 struct json_object
*mt_json
;
2474 mt_json
= json_object_new_object();
2475 json_object_object_add(json
, "mt", mt_json
);
2476 json_object_int_add(mt_json
, "mtid", info
->mtid
);
2477 json_object_string_add(mt_json
, "overload", info
->overload
?"true":"false");
2478 json_object_string_add(mt_json
, "attached", info
->attached
?"true":"false");
2480 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
2481 isis_mtid2str_fake(info
->mtid
),
2482 info
->overload
? " Overload" : "",
2483 info
->attached
? " Attached" : "");
2486 static void free_item_mt_router_info(struct isis_item
*i
)
2488 XFREE(MTYPE_ISIS_TLV
, i
);
2491 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
2494 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2496 if (STREAM_WRITEABLE(s
) < 2) {
2501 uint16_t entry
= info
->mtid
;
2504 entry
|= ISIS_MT_OL_MASK
;
2506 entry
|= ISIS_MT_AT_MASK
;
2508 stream_putw(s
, entry
);
2513 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
2514 struct stream
*s
, struct sbuf
*log
,
2515 void *dest
, int indent
)
2517 struct isis_tlvs
*tlvs
= dest
;
2519 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
2523 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2528 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2530 uint16_t entry
= stream_getw(s
);
2531 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
2532 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
2533 rv
->mtid
= entry
& ISIS_MT_MASK
;
2535 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2537 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
2541 /* Functions related to TLV 134 TE Router ID */
2543 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
2548 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2549 memcpy(rv
, id
, sizeof(*rv
));
2553 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
2554 struct json_object
*json
, int indent
)
2559 char addrbuf
[INET_ADDRSTRLEN
];
2560 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
2562 json_object_string_add(json
, "te-router-id", addrbuf
);
2564 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
2567 static void free_tlv_te_router_id(struct in_addr
*id
)
2569 XFREE(MTYPE_ISIS_TLV
, id
);
2572 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
2577 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2580 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
2582 stream_put(s
, id
, 4);
2586 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
2587 uint8_t tlv_type
, uint8_t tlv_len
,
2588 struct stream
*s
, struct sbuf
*log
,
2589 void *dest
, int indent
)
2591 struct isis_tlvs
*tlvs
= dest
;
2593 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
2595 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2599 if (tlvs
->te_router_id
) {
2600 sbuf_push(log
, indent
,
2601 "WARNING: TE Router ID present multiple times.\n");
2602 stream_forward_getp(s
, tlv_len
);
2606 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
2607 stream_get(tlvs
->te_router_id
, s
, 4);
2608 format_tlv_te_router_id(tlvs
->te_router_id
, log
, NULL
, indent
+ 2);
2613 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
2615 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
2617 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2618 struct isis_extended_ip_reach
*rv
=
2619 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2621 rv
->metric
= r
->metric
;
2623 rv
->prefix
= r
->prefix
;
2624 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2626 return (struct isis_item
*)rv
;
2629 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2631 struct json_object
*json
, int indent
)
2633 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2634 char prefixbuf
[PREFIX2STR_BUFFER
];
2637 struct json_object
*ext_json
;
2638 ext_json
= json_object_new_object();
2639 json_object_object_add(json
, "ext-ip-reach", ext_json
);
2640 json_object_string_add(
2642 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
2643 json_object_string_add(
2645 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2646 json_object_int_add(json
, "ip-reach-metric", r
->metric
);
2647 json_object_string_add(json
, "down", r
->down
? "yes" : "");
2648 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2649 json_object_string_add(json
, "mt-name",
2650 isis_mtid2str(mtid
));
2652 struct json_object
*subtlv_json
;
2653 subtlv_json
= json_object_new_object();
2654 json_object_object_add(json
, "subtlvs", subtlv_json
);
2655 format_subtlvs(r
->subtlvs
, NULL
, subtlv_json
, 0);
2658 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
2659 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2660 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2661 r
->metric
, r
->down
? " Down" : "");
2662 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2663 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2664 sbuf_push(buf
, 0, "\n");
2667 sbuf_push(buf
, indent
, " Subtlvs:\n");
2668 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
2673 static void free_item_extended_ip_reach(struct isis_item
*i
)
2675 struct isis_extended_ip_reach
*item
=
2676 (struct isis_extended_ip_reach
*)i
;
2677 isis_free_subtlvs(item
->subtlvs
);
2678 XFREE(MTYPE_ISIS_TLV
, item
);
2681 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
2684 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2687 if (STREAM_WRITEABLE(s
) < 5) {
2691 stream_putl(s
, r
->metric
);
2693 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
2694 control
|= r
->prefix
.prefixlen
;
2695 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
2697 stream_putc(s
, control
);
2699 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2700 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2703 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2706 return pack_subtlvs(r
->subtlvs
, s
);
2710 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2711 struct stream
*s
, struct sbuf
*log
,
2712 void *dest
, int indent
)
2714 struct isis_tlvs
*tlvs
= dest
;
2715 struct isis_extended_ip_reach
*rv
= NULL
;
2717 uint8_t control
, subtlv_len
;
2718 struct isis_item_list
*items
;
2720 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2721 items
= &tlvs
->extended_ip_reach
;
2723 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2726 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2727 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2730 if (len
< consume
) {
2731 sbuf_push(log
, indent
,
2732 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2737 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2739 rv
->metric
= stream_getl(s
);
2740 control
= stream_getc(s
);
2741 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2742 rv
->prefix
.family
= AF_INET
;
2743 rv
->prefix
.prefixlen
= control
& 0x3f;
2744 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
2745 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2746 rv
->prefix
.prefixlen
);
2750 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2751 if (len
< consume
) {
2752 sbuf_push(log
, indent
,
2753 "Expected %u bytes of prefix, but only %u bytes available.\n",
2754 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2757 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2758 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2759 apply_mask_ipv4(&rv
->prefix
);
2760 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2761 sbuf_push(log
, indent
+ 2,
2762 "WARNING: Prefix had hostbits set.\n");
2763 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2766 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2768 if (len
< consume
) {
2769 sbuf_push(log
, indent
,
2770 "Expected 1 byte of subtlv len, but no more data present.\n");
2773 subtlv_len
= stream_getc(s
);
2776 sbuf_push(log
, indent
+ 2,
2777 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2779 consume
+= subtlv_len
;
2780 if (len
< consume
) {
2781 sbuf_push(log
, indent
,
2782 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2784 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2788 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2789 bool unpacked_known_tlvs
= false;
2791 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2792 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2795 if (!unpacked_known_tlvs
) {
2796 isis_free_subtlvs(rv
->subtlvs
);
2801 append_item(items
, (struct isis_item
*)rv
);
2805 free_item_extended_ip_reach((struct isis_item
*)rv
);
2809 /* Functions related to TLV 137 Dynamic Hostname */
2811 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2816 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2819 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2820 struct json_object
*json
, int indent
)
2826 json_object_string_add(json
, "hostname", hostname
);
2828 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2831 static void free_tlv_dynamic_hostname(char *hostname
)
2833 XFREE(MTYPE_ISIS_TLV
, hostname
);
2836 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2841 uint8_t name_len
= strlen(hostname
);
2843 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2846 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2847 stream_putc(s
, name_len
);
2848 stream_put(s
, hostname
, name_len
);
2852 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2853 uint8_t tlv_type
, uint8_t tlv_len
,
2854 struct stream
*s
, struct sbuf
*log
,
2855 void *dest
, int indent
)
2857 struct isis_tlvs
*tlvs
= dest
;
2859 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2861 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2865 if (tlvs
->hostname
) {
2866 sbuf_push(log
, indent
,
2867 "WARNING: Hostname present multiple times.\n");
2868 stream_forward_getp(s
, tlv_len
);
2872 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2873 stream_get(tlvs
->hostname
, s
, tlv_len
);
2874 tlvs
->hostname
[tlv_len
] = '\0';
2877 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2878 if ((unsigned char)tlvs
->hostname
[i
] > 127
2879 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2881 tlvs
->hostname
[i
] = '?';
2887 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2893 /* Functions related to TLV 140 IPv6 TE Router ID */
2895 static struct in6_addr
*copy_tlv_te_router_id_ipv6(const struct in6_addr
*id
)
2900 struct in6_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2901 memcpy(rv
, id
, sizeof(*rv
));
2905 static void format_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2907 struct json_object
*json
, int indent
)
2912 char addrbuf
[INET6_ADDRSTRLEN
];
2913 inet_ntop(AF_INET6
, id
, addrbuf
, sizeof(addrbuf
));
2915 json_object_string_add(json
, "ipv6-te-router-id", addrbuf
);
2917 sbuf_push(buf
, indent
, "IPv6 TE Router ID: %s\n", addrbuf
);
2920 static void free_tlv_te_router_id_ipv6(struct in6_addr
*id
)
2922 XFREE(MTYPE_ISIS_TLV
, id
);
2925 static int pack_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2931 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2934 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID_IPV6
);
2935 stream_putc(s
, IPV6_MAX_BYTELEN
);
2936 stream_put(s
, id
, IPV6_MAX_BYTELEN
);
2940 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context
,
2941 uint8_t tlv_type
, uint8_t tlv_len
,
2942 struct stream
*s
, struct sbuf
*log
,
2943 void *dest
, int indent
)
2945 struct isis_tlvs
*tlvs
= dest
;
2947 sbuf_push(log
, indent
, "Unpacking IPv6 TE Router ID TLV...\n");
2948 if (tlv_len
!= IPV6_MAX_BYTELEN
) {
2949 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2953 if (tlvs
->te_router_id_ipv6
) {
2956 "WARNING: IPv6 TE Router ID present multiple times.\n");
2957 stream_forward_getp(s
, tlv_len
);
2961 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, IPV6_MAX_BYTELEN
);
2962 stream_get(tlvs
->te_router_id_ipv6
, s
, IPV6_MAX_BYTELEN
);
2963 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, log
, NULL
, indent
+ 2);
2968 /* Functions related to TLV 150 Spine-Leaf-Extension */
2970 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2971 const struct isis_spine_leaf
*spine_leaf
)
2976 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2977 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2982 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2983 struct sbuf
*buf
, struct json_object
*json
,
2992 struct json_object
*spine_json
;
2993 spine_json
= json_object_new_object();
2994 json_object_object_add(json
, "spine-leaf-extension",
2996 if (spine_leaf
->has_tier
) {
2997 snprintfrr(aux_buf
, sizeof(aux_buf
), "%hhu",
2999 json_object_string_add(
3001 (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
)
3005 json_object_string_add(spine_json
, "flag-leaf",
3006 spine_leaf
->is_leaf
? "yes" : "");
3007 json_object_string_add(spine_json
, "flag-spine",
3008 spine_leaf
->is_spine
? "yes" : "");
3009 json_object_string_add(spine_json
, "flag-backup",
3010 spine_leaf
->is_backup
? "yes" : "");
3012 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
3013 if (spine_leaf
->has_tier
) {
3014 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
3015 sbuf_push(buf
, indent
, " Tier: undefined\n");
3017 sbuf_push(buf
, indent
, " Tier: %hhu\n",
3022 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
3023 spine_leaf
->is_leaf
? " LEAF" : "",
3024 spine_leaf
->is_spine
? " SPINE" : "",
3025 spine_leaf
->is_backup
? " BACKUP" : "");
3029 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
3031 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
3034 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
3035 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
3036 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
3037 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
3039 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
3045 uint8_t tlv_len
= 2;
3047 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3050 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
3051 stream_putc(s
, tlv_len
);
3053 uint16_t spine_leaf_flags
= 0;
3055 if (spine_leaf
->has_tier
) {
3056 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
3057 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
3060 if (spine_leaf
->is_leaf
)
3061 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
3063 if (spine_leaf
->is_spine
)
3064 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
3066 if (spine_leaf
->is_backup
)
3067 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
3069 stream_putw(s
, spine_leaf_flags
);
3074 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
3075 uint8_t tlv_type
, uint8_t tlv_len
,
3076 struct stream
*s
, struct sbuf
*log
,
3077 void *dest
, int indent
)
3079 struct isis_tlvs
*tlvs
= dest
;
3081 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
3083 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3084 stream_forward_getp(s
, tlv_len
);
3088 if (tlvs
->spine_leaf
) {
3089 sbuf_push(log
, indent
,
3090 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3091 stream_forward_getp(s
, tlv_len
);
3095 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3097 uint16_t spine_leaf_flags
= stream_getw(s
);
3099 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
3100 tlvs
->spine_leaf
->has_tier
= true;
3101 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
3104 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
3105 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
3106 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
3108 stream_forward_getp(s
, tlv_len
- 2);
3112 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3114 const char *isis_threeway_state_name(enum isis_threeway_state state
)
3117 case ISIS_THREEWAY_DOWN
:
3119 case ISIS_THREEWAY_INITIALIZING
:
3120 return "Initializing";
3121 case ISIS_THREEWAY_UP
:
3128 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
3129 const struct isis_threeway_adj
*threeway_adj
)
3134 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3135 memcpy(rv
, threeway_adj
, sizeof(*rv
));
3141 format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3142 struct sbuf
*buf
, struct json_object
*json
, int indent
)
3148 struct json_object
*three_json
;
3149 three_json
= json_object_new_object();
3150 json_object_object_add(json
, "p2p-three-way-adj", three_json
);
3151 json_object_string_add(
3152 three_json
, "state-name",
3153 isis_threeway_state_name(threeway_adj
->state
));
3154 json_object_int_add(three_json
, "state", threeway_adj
->state
);
3155 json_object_int_add(three_json
, "ext-local-circuit-id",
3156 threeway_adj
->local_circuit_id
);
3157 if (!threeway_adj
->neighbor_set
)
3159 json_object_string_add(
3160 three_json
, "neigh-system-id",
3161 isis_format_id(threeway_adj
->neighbor_id
, 6));
3162 json_object_int_add(three_json
, "neigh-ext-circuit-id",
3163 threeway_adj
->neighbor_circuit_id
);
3165 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
3166 sbuf_push(buf
, indent
, " State: %s (%d)\n",
3167 isis_threeway_state_name(threeway_adj
->state
),
3168 threeway_adj
->state
);
3169 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
3170 threeway_adj
->local_circuit_id
);
3171 if (!threeway_adj
->neighbor_set
)
3174 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
3175 isis_format_id(threeway_adj
->neighbor_id
, 6));
3176 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
3177 threeway_adj
->neighbor_circuit_id
);
3181 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
3183 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
3186 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3192 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
3194 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3197 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
3198 stream_putc(s
, tlv_len
);
3199 stream_putc(s
, threeway_adj
->state
);
3200 stream_putl(s
, threeway_adj
->local_circuit_id
);
3202 if (threeway_adj
->neighbor_set
) {
3203 stream_put(s
, threeway_adj
->neighbor_id
, 6);
3204 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
3210 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
3211 uint8_t tlv_type
, uint8_t tlv_len
,
3212 struct stream
*s
, struct sbuf
*log
,
3213 void *dest
, int indent
)
3215 struct isis_tlvs
*tlvs
= dest
;
3217 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
3218 if (tlv_len
!= 5 && tlv_len
!= 15) {
3219 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3220 stream_forward_getp(s
, tlv_len
);
3224 if (tlvs
->threeway_adj
) {
3225 sbuf_push(log
, indent
,
3226 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3227 stream_forward_getp(s
, tlv_len
);
3231 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3233 tlvs
->threeway_adj
->state
= stream_getc(s
);
3234 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
3236 if (tlv_len
== 15) {
3237 tlvs
->threeway_adj
->neighbor_set
= true;
3238 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
3239 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
3245 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3246 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
3248 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3249 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3251 rv
->metric
= r
->metric
;
3253 rv
->external
= r
->external
;
3254 rv
->prefix
= r
->prefix
;
3255 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3257 return (struct isis_item
*)rv
;
3260 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
3261 struct sbuf
*buf
, struct json_object
*json
,
3264 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3265 char prefixbuf
[PREFIX2STR_BUFFER
];
3268 struct json_object
*reach_json
;
3269 reach_json
= json_object_new_object();
3270 json_object_object_add(json
, "ipv6-reach", reach_json
);
3271 json_object_string_add(reach_json
, "mt-id",
3272 (mtid
== ISIS_MT_IPV4_UNICAST
) ? ""
3274 json_object_string_add(
3275 reach_json
, "prefix",
3276 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3277 json_object_int_add(reach_json
, "metric", r
->metric
);
3278 json_object_string_add(reach_json
, "down",
3279 r
->down
? "yes" : "");
3280 json_object_string_add(reach_json
, "external",
3281 r
->external
? "yes" : "");
3282 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3283 json_object_string_add(reach_json
, "mt-name",
3284 isis_mtid2str(mtid
));
3286 struct json_object
*subtlvs_json
;
3287 subtlvs_json
= json_object_new_object();
3288 json_object_object_add(json
, "subtlvs", subtlvs_json
);
3289 format_subtlvs(r
->subtlvs
, NULL
, subtlvs_json
, 0);
3292 sbuf_push(buf
, indent
,
3293 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3294 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
3295 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3296 r
->metric
, r
->down
? " Down" : "",
3297 r
->external
? " External" : "");
3298 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3299 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3300 sbuf_push(buf
, 0, "\n");
3303 sbuf_push(buf
, indent
, " Subtlvs:\n");
3304 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3309 static void free_item_ipv6_reach(struct isis_item
*i
)
3311 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
3313 isis_free_subtlvs(item
->subtlvs
);
3314 XFREE(MTYPE_ISIS_TLV
, item
);
3317 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
3320 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3323 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3324 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3327 stream_putl(s
, r
->metric
);
3329 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
3330 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
3331 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
3333 stream_putc(s
, control
);
3334 stream_putc(s
, r
->prefix
.prefixlen
);
3336 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
3339 return pack_subtlvs(r
->subtlvs
, s
);
3344 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3345 struct sbuf
*log
, void *dest
, int indent
)
3347 struct isis_tlvs
*tlvs
= dest
;
3348 struct isis_ipv6_reach
*rv
= NULL
;
3350 uint8_t control
, subtlv_len
;
3351 struct isis_item_list
*items
;
3353 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3354 items
= &tlvs
->ipv6_reach
;
3356 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3359 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
3360 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
3362 if (len
< consume
) {
3363 sbuf_push(log
, indent
,
3364 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3369 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3371 rv
->metric
= stream_getl(s
);
3372 control
= stream_getc(s
);
3373 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
3374 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
3376 rv
->prefix
.family
= AF_INET6
;
3377 rv
->prefix
.prefixlen
= stream_getc(s
);
3378 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
3379 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
3380 rv
->prefix
.prefixlen
);
3384 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3385 if (len
< consume
) {
3386 sbuf_push(log
, indent
,
3387 "Expected %u bytes of prefix, but only %u bytes available.\n",
3388 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
3391 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3392 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
3394 apply_mask_ipv6(&rv
->prefix
);
3395 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
3396 sbuf_push(log
, indent
+ 2,
3397 "WARNING: Prefix had hostbits set.\n");
3398 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3400 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
3402 if (len
< consume
) {
3403 sbuf_push(log
, indent
,
3404 "Expected 1 byte of subtlv len, but no more data persent.\n");
3407 subtlv_len
= stream_getc(s
);
3410 sbuf_push(log
, indent
+ 2,
3411 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3413 consume
+= subtlv_len
;
3414 if (len
< consume
) {
3415 sbuf_push(log
, indent
,
3416 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3418 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3422 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3423 bool unpacked_known_tlvs
= false;
3425 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
3426 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3429 if (!unpacked_known_tlvs
) {
3430 isis_free_subtlvs(rv
->subtlvs
);
3435 append_item(items
, (struct isis_item
*)rv
);
3439 free_item_ipv6_reach((struct isis_item
*)rv
);
3443 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3444 static struct isis_router_cap
*copy_tlv_router_cap(
3445 const struct isis_router_cap
*router_cap
)
3447 struct isis_router_cap
*rv
;
3452 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3454 memcpy(rv
, router_cap
, sizeof(*rv
));
3459 static void format_tlv_router_cap_json(const struct isis_router_cap
*router_cap
,
3460 struct json_object
*json
)
3462 char addrbuf
[INET_ADDRSTRLEN
];
3467 /* Router ID and Flags */
3468 struct json_object
*cap_json
;
3469 cap_json
= json_object_new_object();
3470 json_object_object_add(json
, "router-capability", cap_json
);
3471 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3472 json_object_string_add(cap_json
, "id", addrbuf
);
3473 json_object_string_add(
3475 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? "1" : "0");
3476 json_object_string_add(
3478 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? "1" : "0");
3480 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3481 if (router_cap
->srgb
.range_size
!= 0) {
3482 struct json_object
*gb_json
;
3483 gb_json
= json_object_new_object();
3484 json_object_object_add(json
, "segment-routing-gb", gb_json
);
3485 json_object_string_add(gb_json
, "ipv4",
3486 IS_SR_IPV4(&router_cap
->srgb
) ? "1"
3488 json_object_string_add(gb_json
, "ipv6",
3489 IS_SR_IPV6(&router_cap
->srgb
) ? "1"
3491 json_object_int_add(gb_json
, "global-block-base",
3492 router_cap
->srgb
.lower_bound
);
3493 json_object_int_add(gb_json
, "global-block-range",
3494 router_cap
->srgb
.range_size
);
3497 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3498 if (router_cap
->srlb
.range_size
!= 0) {
3499 struct json_object
*lb_json
;
3500 lb_json
= json_object_new_object();
3501 json_object_object_add(json
, "segment-routing-lb", lb_json
);
3502 json_object_int_add(lb_json
, "global-block-base",
3503 router_cap
->srlb
.lower_bound
);
3504 json_object_int_add(lb_json
, "global-block-range",
3505 router_cap
->srlb
.range_size
);
3508 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3509 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3511 struct json_object
*alg_json
;
3512 alg_json
= json_object_new_object();
3513 json_object_object_add(json
, "segment-routing-algorithm",
3515 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3516 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
) {
3517 snprintfrr(buf
, sizeof(buf
), "%d", i
);
3518 json_object_string_add(alg_json
, buf
,
3519 router_cap
->algo
[i
] == 0
3525 /* Segment Routing Node MSD as per RFC8491 section #2 */
3526 if (router_cap
->msd
!= 0)
3527 json_object_int_add(json
, "msd", router_cap
->msd
);
3530 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3531 struct sbuf
*buf
, int indent
)
3533 char addrbuf
[INET_ADDRSTRLEN
];
3538 /* Router ID and Flags */
3539 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3540 sbuf_push(buf
, indent
, "Router Capability:");
3541 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
3542 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
3543 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
3545 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3546 if (router_cap
->srgb
.range_size
!= 0)
3549 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
3550 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
3551 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
3552 router_cap
->srgb
.lower_bound
,
3553 router_cap
->srgb
.range_size
);
3555 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3556 if (router_cap
->srlb
.range_size
!= 0)
3557 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
3558 router_cap
->srlb
.lower_bound
,
3559 router_cap
->srlb
.range_size
);
3561 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3562 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3563 sbuf_push(buf
, indent
, " SR Algorithm:\n");
3564 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3565 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
3566 sbuf_push(buf
, indent
, " %u: %s\n", i
,
3567 router_cap
->algo
[i
] == 0
3572 /* Segment Routing Node MSD as per RFC8491 section #2 */
3573 if (router_cap
->msd
!= 0)
3574 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
3578 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
3580 XFREE(MTYPE_ISIS_TLV
, router_cap
);
3583 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3586 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
3593 /* Compute Maximum TLV size */
3594 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
3595 + ISIS_SUBTLV_HDR_SIZE
3596 + ISIS_SUBTLV_ALGORITHM_SIZE
3597 + ISIS_SUBTLV_NODE_MSD_SIZE
;
3599 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
3602 /* Add Router Capability TLV 242 with Router ID and Flags */
3603 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
3604 /* Real length will be adjusted later */
3605 len_pos
= stream_get_endp(s
);
3606 stream_putc(s
, tlv_len
);
3607 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
3608 stream_putc(s
, router_cap
->flags
);
3610 /* Add SRGB if set as per RFC8667 section #3.1 */
3611 if ((router_cap
->srgb
.range_size
!= 0)
3612 && (router_cap
->srgb
.lower_bound
!= 0)) {
3613 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
3614 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3615 stream_putc(s
, router_cap
->srgb
.flags
);
3616 stream_put3(s
, router_cap
->srgb
.range_size
);
3617 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3618 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3619 stream_put3(s
, router_cap
->srgb
.lower_bound
);
3621 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
3622 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
3623 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
3626 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
3627 stream_putc(s
, nb_algo
);
3628 for (int i
= 0; i
< nb_algo
; i
++)
3629 stream_putc(s
, router_cap
->algo
[i
]);
3632 /* Local Block if defined as per RFC8667 section #3.3 */
3633 if ((router_cap
->srlb
.range_size
!= 0)
3634 && (router_cap
->srlb
.lower_bound
!= 0)) {
3635 stream_putc(s
, ISIS_SUBTLV_SRLB
);
3636 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3637 /* No Flags are defined for SRLB */
3639 stream_put3(s
, router_cap
->srlb
.range_size
);
3640 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3641 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3642 stream_put3(s
, router_cap
->srlb
.lower_bound
);
3645 /* And finish with MSD if set as per RFC8491 section #2 */
3646 if (router_cap
->msd
!= 0) {
3647 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
3648 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
3649 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
3650 stream_putc(s
, router_cap
->msd
);
3654 /* Adjust TLV length which depends on subTLVs presence */
3655 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
3656 stream_putc_at(s
, len_pos
, tlv_len
);
3661 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
3662 uint8_t tlv_type
, uint8_t tlv_len
,
3663 struct stream
*s
, struct sbuf
*log
, void *dest
,
3666 struct isis_tlvs
*tlvs
= dest
;
3667 struct isis_router_cap
*rcap
;
3673 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
3674 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
3675 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3676 stream_forward_getp(s
, tlv_len
);
3680 if (tlvs
->router_cap
) {
3681 sbuf_push(log
, indent
,
3682 "WARNING: Router Capability TLV present multiple times.\n");
3683 stream_forward_getp(s
, tlv_len
);
3687 /* Allocate router cap structure and initialize SR Algorithms */
3688 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
3689 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3690 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
3692 /* Get Router ID and Flags */
3693 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
3694 rcap
->flags
= stream_getc(s
);
3696 /* Parse remaining part of the TLV if present */
3697 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
3698 while (subtlv_len
> 2) {
3701 type
= stream_getc(s
);
3702 length
= stream_getc(s
);
3704 if (length
> STREAM_READABLE(s
) || length
> subtlv_len
- 2) {
3707 "WARNING: Router Capability subTLV length too large compared to expected size\n");
3708 stream_forward_getp(s
, STREAM_READABLE(s
));
3709 XFREE(MTYPE_ISIS_TLV
, rcap
);
3714 case ISIS_SUBTLV_SID_LABEL_RANGE
:
3715 /* Check that SRGB is correctly formated */
3716 if (length
< SUBTLV_RANGE_LABEL_SIZE
3717 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3718 stream_forward_getp(s
, length
);
3721 /* Only one SRGB is supported. Skip subsequent one */
3722 if (rcap
->srgb
.range_size
!= 0) {
3723 stream_forward_getp(s
, length
);
3726 rcap
->srgb
.flags
= stream_getc(s
);
3727 rcap
->srgb
.range_size
= stream_get3(s
);
3728 /* Skip Type and get Length of SID Label */
3730 size
= stream_getc(s
);
3732 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3733 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3734 stream_forward_getp(s
, length
- 6);
3738 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3739 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3740 stream_forward_getp(s
, length
- 6);
3744 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3745 rcap
->srgb
.lower_bound
= stream_get3(s
);
3746 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3747 rcap
->srgb
.lower_bound
= stream_getl(s
);
3749 stream_forward_getp(s
, length
- 6);
3753 /* SRGB sanity checks. */
3754 if (rcap
->srgb
.range_size
== 0
3755 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3756 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
3757 > MPLS_LABEL_UNRESERVED_MAX
)) {
3758 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
3759 rcap
->srgb
.lower_bound
= 0;
3760 rcap
->srgb
.range_size
= 0;
3762 /* Only one range is supported. Skip subsequent one */
3763 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3765 stream_forward_getp(s
, size
);
3768 case ISIS_SUBTLV_ALGORITHM
:
3771 /* Only 2 algorithms are supported: SPF & Strict SPF */
3772 stream_get(&rcap
->algo
, s
,
3773 length
> SR_ALGORITHM_COUNT
3774 ? SR_ALGORITHM_COUNT
3776 if (length
> SR_ALGORITHM_COUNT
)
3777 stream_forward_getp(
3778 s
, length
- SR_ALGORITHM_COUNT
);
3780 case ISIS_SUBTLV_SRLB
:
3781 /* Check that SRLB is correctly formated */
3782 if (length
< SUBTLV_RANGE_LABEL_SIZE
3783 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3784 stream_forward_getp(s
, length
);
3787 /* RFC 8667 section #3.3: Only one SRLB is authorized */
3788 if (rcap
->srlb
.range_size
!= 0) {
3789 stream_forward_getp(s
, length
);
3792 /* Ignore Flags which are not defined */
3794 rcap
->srlb
.range_size
= stream_get3(s
);
3795 /* Skip Type and get Length of SID Label */
3797 size
= stream_getc(s
);
3799 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3800 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3801 stream_forward_getp(s
, length
- 6);
3805 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3806 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3807 stream_forward_getp(s
, length
- 6);
3811 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3812 rcap
->srlb
.lower_bound
= stream_get3(s
);
3813 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3814 rcap
->srlb
.lower_bound
= stream_getl(s
);
3816 stream_forward_getp(s
, length
- 6);
3820 /* SRLB sanity checks. */
3821 if (rcap
->srlb
.range_size
== 0
3822 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3823 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
3824 > MPLS_LABEL_UNRESERVED_MAX
)) {
3825 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
3826 rcap
->srlb
.lower_bound
= 0;
3827 rcap
->srlb
.range_size
= 0;
3829 /* Only one range is supported. Skip subsequent one */
3830 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3832 stream_forward_getp(s
, size
);
3835 case ISIS_SUBTLV_NODE_MSD
:
3836 /* Check that MSD is correctly formated */
3837 if (length
< MSD_TLV_SIZE
) {
3838 stream_forward_getp(s
, length
);
3841 msd_type
= stream_getc(s
);
3842 rcap
->msd
= stream_getc(s
);
3843 /* Only BMI-MSD type has been defined in RFC 8491 */
3844 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
3846 /* Only one MSD is standardized. Skip others */
3847 if (length
> MSD_TLV_SIZE
)
3848 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
3851 stream_forward_getp(s
, length
);
3854 subtlv_len
= subtlv_len
- length
- 2;
3856 tlvs
->router_cap
= rcap
;
3860 /* Functions related to TLV 10 Authentication */
3861 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
3863 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3864 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3866 rv
->type
= auth
->type
;
3867 rv
->length
= auth
->length
;
3868 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
3869 return (struct isis_item
*)rv
;
3872 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
3873 struct sbuf
*buf
, struct json_object
*json
,
3876 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3880 json_object_string_add(json
, "test-auth", "ok");
3882 sbuf_push(buf
, indent
, "Authentication:\n");
3883 switch (auth
->type
) {
3884 case ISIS_PASSWD_TYPE_CLEARTXT
:
3885 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
3887 json_object_string_add(json
, "auth-pass", obuf
);
3889 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
3891 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3892 for (unsigned int j
= 0; j
< 16; j
++) {
3893 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
, "%02hhx",
3897 json_object_string_add(json
, "auth-hmac-md5", obuf
);
3899 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
3903 json_object_int_add(json
, "auth-unknown", auth
->type
);
3905 sbuf_push(buf
, indent
, " Unknown (%hhu)\n",
3911 static void free_item_auth(struct isis_item
*i
)
3913 XFREE(MTYPE_ISIS_TLV
, i
);
3916 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
3919 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3921 if (STREAM_WRITEABLE(s
) < 1) {
3925 stream_putc(s
, auth
->type
);
3927 switch (auth
->type
) {
3928 case ISIS_PASSWD_TYPE_CLEARTXT
:
3929 if (STREAM_WRITEABLE(s
) < auth
->length
) {
3930 *min_len
= 1 + auth
->length
;
3933 stream_put(s
, auth
->passwd
, auth
->length
);
3935 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3936 if (STREAM_WRITEABLE(s
) < 16) {
3940 auth
->offset
= stream_get_endp(s
);
3941 stream_put(s
, NULL
, 16);
3950 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3951 struct sbuf
*log
, void *dest
, int indent
)
3953 struct isis_tlvs
*tlvs
= dest
;
3955 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
3959 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
3964 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3966 rv
->type
= stream_getc(s
);
3967 rv
->length
= len
- 1;
3969 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
3972 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
3974 XFREE(MTYPE_ISIS_TLV
, rv
);
3978 rv
->offset
= stream_get_getp(s
);
3979 stream_get(rv
->value
, s
, rv
->length
);
3980 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3981 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
3985 /* Functions related to TLV 13 Purge Originator */
3987 static struct isis_purge_originator
*copy_tlv_purge_originator(
3988 struct isis_purge_originator
*poi
)
3993 struct isis_purge_originator
*rv
;
3995 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3996 rv
->sender_set
= poi
->sender_set
;
3997 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3998 if (poi
->sender_set
)
3999 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
4003 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
4005 struct json_object
*json
, int indent
)
4011 struct json_object
*purge_json
;
4012 purge_json
= json_object_new_object();
4013 json_object_object_add(json
, "purge_originator", purge_json
);
4015 json_object_string_add(
4017 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
4018 if (poi
->sender_set
) {
4019 json_object_string_add(
4020 purge_json
, "rec-from",
4021 isis_format_id(poi
->sender
,
4022 sizeof(poi
->sender
)));
4025 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
4027 buf
, indent
, " Generator: %s\n",
4028 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
4029 if (poi
->sender_set
) {
4030 sbuf_push(buf
, indent
, " Received-From: %s\n",
4031 isis_format_id(poi
->sender
,
4032 sizeof(poi
->sender
)));
4037 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
4039 XFREE(MTYPE_ISIS_TLV
, poi
);
4042 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
4048 uint8_t data_len
= 1 + sizeof(poi
->generator
);
4050 if (poi
->sender_set
)
4051 data_len
+= sizeof(poi
->sender
);
4053 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
4056 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
4057 stream_putc(s
, data_len
);
4058 stream_putc(s
, poi
->sender_set
? 2 : 1);
4059 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
4060 if (poi
->sender_set
)
4061 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
4065 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
4066 uint8_t tlv_type
, uint8_t tlv_len
,
4067 struct stream
*s
, struct sbuf
*log
,
4068 void *dest
, int indent
)
4070 struct isis_tlvs
*tlvs
= dest
;
4071 struct isis_purge_originator poi
= {};
4073 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
4075 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
4079 uint8_t number_of_ids
= stream_getc(s
);
4081 if (number_of_ids
== 1) {
4082 poi
.sender_set
= false;
4083 } else if (number_of_ids
== 2) {
4084 poi
.sender_set
= true;
4086 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
4090 if (tlv_len
!= 1 + 6 * number_of_ids
) {
4091 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
4095 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
4097 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
4099 if (tlvs
->purge_originator
) {
4100 sbuf_push(log
, indent
,
4101 "WARNING: Purge originator present multiple times, ignoring.\n");
4105 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
4110 /* Functions relating to item TLVs */
4112 static void init_item_list(struct isis_item_list
*items
)
4115 items
->tail
= &items
->head
;
4119 static struct isis_item
*copy_item(enum isis_tlv_context context
,
4120 enum isis_tlv_type type
,
4121 struct isis_item
*item
)
4123 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4125 if (ops
&& ops
->copy_item
)
4126 return ops
->copy_item(item
);
4128 assert(!"Unknown item tlv type!");
4132 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4133 struct isis_item_list
*src
, struct isis_item_list
*dest
)
4135 struct isis_item
*item
;
4137 init_item_list(dest
);
4139 for (item
= src
->head
; item
; item
= item
->next
) {
4140 append_item(dest
, copy_item(context
, type
, item
));
4144 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
4145 enum isis_tlv_type type
, struct isis_item
*i
,
4146 struct sbuf
*buf
, struct json_object
*json
, int indent
)
4148 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4150 if (ops
&& ops
->format_item
) {
4151 ops
->format_item(mtid
, i
, buf
, json
, indent
);
4155 assert(!"Unknown item tlv type!");
4158 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
4159 enum isis_tlv_type type
, struct isis_item_list
*items
,
4160 struct sbuf
*buf
, struct json_object
*json
,
4163 struct isis_item
*i
;
4165 for (i
= items
->head
; i
; i
= i
->next
)
4166 format_item(mtid
, context
, type
, i
, buf
, json
, indent
);
4169 static void free_item(enum isis_tlv_context tlv_context
,
4170 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
4172 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
4174 if (ops
&& ops
->free_item
) {
4175 ops
->free_item(item
);
4179 assert(!"Unknown item tlv type!");
4182 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4183 struct isis_item_list
*items
)
4185 struct isis_item
*item
, *next_item
;
4187 for (item
= items
->head
; item
; item
= next_item
) {
4188 next_item
= item
->next
;
4189 free_item(context
, type
, item
);
4193 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
4194 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
4195 struct isis_tlvs
**fragment_tlvs
,
4196 const struct pack_order_entry
*pe
, uint16_t mtid
)
4198 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4200 if (ops
&& ops
->pack_item
) {
4201 return ops
->pack_item(i
, s
, min_len
);
4204 assert(!"Unknown item tlv type!");
4208 static void add_item_to_fragment(struct isis_item
*i
,
4209 const struct pack_order_entry
*pe
,
4210 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
4212 struct isis_item_list
*l
;
4214 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4215 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4217 struct isis_mt_item_list
*m
;
4218 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4219 l
= isis_get_mt_items(m
, mtid
);
4222 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
4225 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
4226 enum isis_tlv_type type
, struct isis_item_list
*items
,
4227 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
4228 const struct pack_order_entry
*pe
,
4229 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4230 struct list
*new_fragment_arg
)
4232 size_t len_pos
, last_len
, len
;
4233 struct isis_item
*item
= NULL
;
4241 if (STREAM_WRITEABLE(s
) < 2)
4244 stream_putc(s
, type
);
4245 len_pos
= stream_get_endp(s
);
4246 stream_putc(s
, 0); /* Put 0 as length for now */
4248 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
4249 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
4250 if (STREAM_WRITEABLE(s
) < 2)
4252 stream_putw(s
, mtid
);
4255 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
4256 if (STREAM_WRITEABLE(s
) < 1)
4258 stream_putc(s
, 0); /* Virtual flag is set to 0 */
4262 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
4263 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
4268 len
= stream_get_endp(s
) - len_pos
- 1;
4270 /* Multiple auths don't go into one TLV, so always break */
4271 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
4276 /* Multiple prefix-sids don't go into one TLV, so always break */
4277 if (type
== ISIS_SUBTLV_PREFIX_SID
4278 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
4279 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
4285 if (!last_len
) /* strange, not a single item fit */
4287 /* drop last tlv, otherwise, its too long */
4288 stream_set_endp(s
, len_pos
+ 1 + last_len
);
4294 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
4299 stream_putc_at(s
, len_pos
, len
);
4308 if (STREAM_WRITEABLE(s
) < min_len
)
4310 *fragment_tlvs
= new_fragment(new_fragment_arg
);
4313 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
4315 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
4318 dest
->tail
= &(*dest
->tail
)->next
;
4322 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
4324 struct isis_item
*item
, *prev
= NULL
, *next
;
4327 if ((dest
== NULL
) || (del
== NULL
))
4331 * TODO: delete is tricky because "dest" is a singly linked list.
4332 * We need to switch a doubly linked list.
4334 for (item
= dest
->head
; item
; item
= next
) {
4335 if (item
->next
== del
) {
4342 prev
->next
= del
->next
;
4343 if (dest
->head
== del
)
4344 dest
->head
= del
->next
;
4345 if ((struct isis_item
*)dest
->tail
== del
) {
4348 dest
->tail
= &(*dest
->tail
)->next
;
4350 dest
->tail
= &dest
->head
;
4355 static struct isis_item
*last_item(struct isis_item_list
*list
)
4357 return container_of(list
->tail
, struct isis_item
, next
);
4360 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
4361 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
4362 struct sbuf
*log
, void *dest
, int indent
)
4364 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
4366 if (ops
&& ops
->unpack_item
)
4367 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
4369 assert(!"Unknown item tlv type!");
4370 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
4374 static int unpack_tlv_with_items(enum isis_tlv_context context
,
4375 uint8_t tlv_type
, uint8_t tlv_len
,
4376 struct stream
*s
, struct sbuf
*log
, void *dest
,
4384 tlv_start
= stream_get_getp(s
);
4387 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
4389 sbuf_push(log
, indent
,
4390 "TLV is too short to contain MTID\n");
4393 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
4395 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
4396 isis_mtid2str_fake(mtid
));
4398 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
4399 mtid
= ISIS_MT_IPV4_UNICAST
;
4402 if (context
== ISIS_CONTEXT_LSP
4403 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
4404 if (tlv_len
- tlv_pos
< 1) {
4405 sbuf_push(log
, indent
,
4406 "TLV is too short for old style reach\n");
4409 stream_forward_getp(s
, 1);
4413 if (context
== ISIS_CONTEXT_LSP
4414 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
4415 struct isis_tlvs
*tlvs
= dest
;
4416 dest
= &tlvs
->oldstyle_ip_reach
;
4417 } else if (context
== ISIS_CONTEXT_LSP
4418 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
4419 struct isis_tlvs
*tlvs
= dest
;
4420 dest
= &tlvs
->oldstyle_ip_reach_ext
;
4423 if (context
== ISIS_CONTEXT_LSP
4424 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
4425 struct isis_tlvs
*tlvs
= dest
;
4426 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
4429 while (tlv_pos
< (size_t)tlv_len
) {
4430 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
4431 log
, dest
, indent
+ 2);
4435 tlv_pos
= stream_get_getp(s
) - tlv_start
;
4441 /* Functions to manipulate mt_item_lists */
4443 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
4444 const struct isis_item_list
*b
)
4446 if (a
->mtid
< b
->mtid
)
4448 if (a
->mtid
> b
->mtid
)
4453 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4454 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4456 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
4459 struct isis_item_list
*rv
;
4461 rv
= isis_lookup_mt_items(m
, mtid
);
4463 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
4466 RB_INSERT(isis_mt_item_list
, m
, rv
);
4472 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
4475 struct isis_item_list key
= {.mtid
= mtid
};
4477 return RB_FIND(isis_mt_item_list
, m
, &key
);
4480 static void free_mt_items(enum isis_tlv_context context
,
4481 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
4483 struct isis_item_list
*n
, *nnext
;
4485 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
4486 free_items(context
, type
, n
);
4487 RB_REMOVE(isis_mt_item_list
, m
, n
);
4488 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
4492 static void format_mt_items(enum isis_tlv_context context
,
4493 enum isis_tlv_type type
,
4494 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
4495 struct json_object
*json
, int indent
)
4497 struct isis_item_list
*n
;
4499 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4500 format_items_(n
->mtid
, context
, type
, n
, buf
, json
, indent
);
4504 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4505 struct isis_mt_item_list
*m
, struct stream
*s
,
4506 struct isis_tlvs
**fragment_tlvs
,
4507 const struct pack_order_entry
*pe
,
4508 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4509 struct list
*new_fragment_arg
)
4511 struct isis_item_list
*n
;
4513 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4516 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
4517 pe
, new_fragment
, new_fragment_arg
);
4525 static void copy_mt_items(enum isis_tlv_context context
,
4526 enum isis_tlv_type type
,
4527 struct isis_mt_item_list
*src
,
4528 struct isis_mt_item_list
*dest
)
4530 struct isis_item_list
*n
;
4532 RB_INIT(isis_mt_item_list
, dest
);
4534 RB_FOREACH (n
, isis_mt_item_list
, src
) {
4535 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
4539 /* Functions related to tlvs in general */
4541 struct isis_tlvs
*isis_alloc_tlvs(void)
4543 struct isis_tlvs
*result
;
4545 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
4547 init_item_list(&result
->isis_auth
);
4548 init_item_list(&result
->area_addresses
);
4549 init_item_list(&result
->mt_router_info
);
4550 init_item_list(&result
->oldstyle_reach
);
4551 init_item_list(&result
->lan_neighbor
);
4552 init_item_list(&result
->lsp_entries
);
4553 init_item_list(&result
->extended_reach
);
4554 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
4555 init_item_list(&result
->oldstyle_ip_reach
);
4556 init_item_list(&result
->oldstyle_ip_reach_ext
);
4557 init_item_list(&result
->ipv4_address
);
4558 init_item_list(&result
->ipv6_address
);
4559 init_item_list(&result
->global_ipv6_address
);
4560 init_item_list(&result
->extended_ip_reach
);
4561 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
4562 init_item_list(&result
->ipv6_reach
);
4563 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
4568 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
4570 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4572 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
4575 rv
->purge_originator
=
4576 copy_tlv_purge_originator(tlvs
->purge_originator
);
4578 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4579 &tlvs
->area_addresses
, &rv
->area_addresses
);
4581 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4582 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
4584 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
4586 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4587 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
4589 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4590 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
4592 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4595 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4596 &tlvs
->extended_reach
, &rv
->extended_reach
);
4598 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4601 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4602 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
4604 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
4605 &rv
->protocols_supported
);
4607 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4608 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
4610 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
4613 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
4616 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4617 &tlvs
->global_ipv6_address
, &rv
->global_ipv6_address
);
4619 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
4621 rv
->te_router_id_ipv6
=
4622 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4624 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4625 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
4627 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4628 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
4630 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
4632 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4635 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4636 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
4638 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4640 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
4642 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4647 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, struct json_object
*json
, int indent
)
4649 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, json
,
4652 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
4655 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, json
, indent
);
4657 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4658 &tlvs
->area_addresses
, buf
, json
, indent
);
4660 if (tlvs
->mt_router_info_empty
) {
4662 json_object_string_add(json
, "mt-router-info", "none");
4664 sbuf_push(buf
, indent
, "MT Router Info: None\n");
4666 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4667 &tlvs
->mt_router_info
, buf
, json
, indent
);
4670 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4671 &tlvs
->oldstyle_reach
, buf
, json
, indent
);
4673 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4674 &tlvs
->lan_neighbor
, buf
, json
, indent
);
4676 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4679 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, json
, indent
);
4680 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, json
, indent
);
4681 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, buf
, json
,
4684 format_tlv_router_cap_json(tlvs
->router_cap
, json
);
4686 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
4688 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4689 &tlvs
->extended_reach
, buf
, json
, indent
);
4691 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4694 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4695 &tlvs
->oldstyle_ip_reach
, buf
, json
, indent
);
4697 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4698 &tlvs
->oldstyle_ip_reach_ext
, buf
, json
, indent
);
4700 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4701 &tlvs
->ipv4_address
, buf
, json
, indent
);
4703 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4704 &tlvs
->ipv6_address
, buf
, json
, indent
);
4706 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4707 &tlvs
->global_ipv6_address
, buf
, json
, indent
);
4709 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4710 &tlvs
->extended_ip_reach
, buf
, json
, indent
);
4712 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4713 &tlvs
->mt_ip_reach
, buf
, json
, indent
);
4715 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4718 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4719 &tlvs
->mt_ipv6_reach
, buf
, json
, indent
);
4721 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, json
, indent
);
4723 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, json
, indent
);
4726 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
, struct json_object
*json
)
4729 format_tlvs(tlvs
, NULL
, json
, 0);
4732 static struct sbuf buf
;
4734 if (!sbuf_buf(&buf
))
4735 sbuf_init(&buf
, NULL
, 0);
4738 format_tlvs(tlvs
, &buf
, NULL
, 0);
4739 return sbuf_buf(&buf
);
4743 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
4748 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4749 free_tlv_purge_originator(tlvs
->purge_originator
);
4750 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4751 &tlvs
->area_addresses
);
4752 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4753 &tlvs
->mt_router_info
);
4754 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4755 &tlvs
->oldstyle_reach
);
4756 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4757 &tlvs
->lan_neighbor
);
4758 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
4759 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4760 &tlvs
->extended_reach
);
4761 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
4762 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4763 &tlvs
->oldstyle_ip_reach
);
4764 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
4765 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4766 &tlvs
->oldstyle_ip_reach_ext
);
4767 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4768 &tlvs
->ipv4_address
);
4769 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4770 &tlvs
->ipv6_address
);
4771 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4772 &tlvs
->global_ipv6_address
);
4773 free_tlv_te_router_id(tlvs
->te_router_id
);
4774 free_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4775 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4776 &tlvs
->extended_ip_reach
);
4777 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4778 &tlvs
->mt_ip_reach
);
4779 free_tlv_dynamic_hostname(tlvs
->hostname
);
4780 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
4781 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4782 &tlvs
->mt_ipv6_reach
);
4783 free_tlv_threeway_adj(tlvs
->threeway_adj
);
4784 free_tlv_router_cap(tlvs
->router_cap
);
4785 free_tlv_spine_leaf(tlvs
->spine_leaf
);
4787 XFREE(MTYPE_ISIS_TLV
, tlvs
);
4790 static void add_padding(struct stream
*s
)
4792 while (STREAM_WRITEABLE(s
)) {
4793 if (STREAM_WRITEABLE(s
) == 1)
4795 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
4797 if (padding_len
> 255) {
4798 if (padding_len
== 256)
4804 stream_putc(s
, ISIS_TLV_PADDING
);
4805 stream_putc(s
, padding_len
);
4806 stream_put(s
, NULL
, padding_len
);
4810 #define LSP_REM_LIFETIME_OFF 10
4811 #define LSP_CHECKSUM_OFF 24
4812 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
4813 uint16_t *rem_lifetime
)
4815 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
4816 sizeof(*rem_lifetime
));
4817 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
4818 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
4819 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
4822 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
4823 uint16_t rem_lifetime
)
4825 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
4826 sizeof(rem_lifetime
));
4827 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
4830 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
4834 uint16_t checksum
, rem_lifetime
;
4837 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
4839 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
4840 #ifdef CRYPTO_OPENSSL
4841 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
4842 auth
->plength
, STREAM_DATA(s
),
4843 stream_get_endp(s
), NULL
, NULL
);
4845 memcpy(digest
, result
, 16);
4846 #elif CRYPTO_INTERNAL
4847 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
4848 auth
->plength
, digest
);
4850 memcpy(auth
->value
, digest
, 16);
4851 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
4854 restore_auth_md5(s
, checksum
, rem_lifetime
);
4857 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
4859 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4861 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
4862 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
4863 update_auth_hmac_md5(auth
, s
, is_lsp
);
4867 static int handle_pack_entry(const struct pack_order_entry
*pe
,
4868 struct isis_tlvs
*tlvs
, struct stream
*stream
,
4869 struct isis_tlvs
**fragment_tlvs
,
4870 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4871 struct list
*new_fragment_arg
)
4875 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4876 struct isis_item_list
*l
;
4877 l
= (struct isis_item_list
*)(((char *)tlvs
)
4878 + pe
->what_to_pack
);
4879 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
4880 pe
, new_fragment
, new_fragment_arg
);
4882 struct isis_mt_item_list
*l
;
4883 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
4884 + pe
->what_to_pack
);
4885 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
4886 fragment_tlvs
, pe
, new_fragment
,
4893 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4894 struct isis_tlvs
*fragment_tlvs
,
4895 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4896 struct list
*new_fragment_arg
)
4900 /* When fragmenting, don't add auth as it's already accounted for in the
4901 * size we are given. */
4902 if (!fragment_tlvs
) {
4903 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
4904 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
4910 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
4913 if (fragment_tlvs
) {
4914 fragment_tlvs
->purge_originator
=
4915 copy_tlv_purge_originator(tlvs
->purge_originator
);
4918 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
4921 if (fragment_tlvs
) {
4922 copy_tlv_protocols_supported(
4923 &tlvs
->protocols_supported
,
4924 &fragment_tlvs
->protocols_supported
);
4927 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4928 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
4931 if (fragment_tlvs
) {
4932 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4933 &tlvs
->area_addresses
,
4934 &fragment_tlvs
->area_addresses
);
4938 if (tlvs
->mt_router_info_empty
) {
4939 if (STREAM_WRITEABLE(stream
) < 2)
4941 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
4942 stream_putc(stream
, 0);
4944 fragment_tlvs
->mt_router_info_empty
= true;
4946 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4947 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
4951 if (fragment_tlvs
) {
4952 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4953 &tlvs
->mt_router_info
,
4954 &fragment_tlvs
->mt_router_info
);
4958 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
4962 fragment_tlvs
->hostname
=
4963 copy_tlv_dynamic_hostname(tlvs
->hostname
);
4965 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
4968 if (fragment_tlvs
) {
4969 fragment_tlvs
->router_cap
=
4970 copy_tlv_router_cap(tlvs
->router_cap
);
4973 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
4976 if (fragment_tlvs
) {
4977 fragment_tlvs
->te_router_id
=
4978 copy_tlv_te_router_id(tlvs
->te_router_id
);
4981 rv
= pack_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, stream
);
4984 if (fragment_tlvs
) {
4985 fragment_tlvs
->te_router_id_ipv6
=
4986 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4989 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
4992 if (fragment_tlvs
) {
4993 fragment_tlvs
->threeway_adj
=
4994 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4997 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
5000 if (fragment_tlvs
) {
5001 fragment_tlvs
->spine_leaf
=
5002 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
5005 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
5007 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
5008 fragment_tlvs
? &fragment_tlvs
: NULL
,
5009 new_fragment
, new_fragment_arg
);
5018 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
5019 size_t len_pointer
, bool pad
, bool is_lsp
)
5023 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
5028 add_padding(stream
);
5030 if (len_pointer
!= (size_t)-1) {
5031 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
5034 update_auth(tlvs
, stream
, is_lsp
);
5039 static struct isis_tlvs
*new_fragment(struct list
*l
)
5041 struct isis_tlvs
*rv
= isis_alloc_tlvs();
5043 listnode_add(l
, rv
);
5047 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
5049 struct stream
*dummy_stream
= stream_new(size
);
5050 struct list
*rv
= list_new();
5051 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
5053 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
5054 struct listnode
*node
;
5055 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
5056 isis_free_tlvs(fragment_tlvs
);
5060 stream_free(dummy_stream
);
5064 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
5065 uint8_t tlv_len
, struct stream
*s
,
5066 struct sbuf
*log
, int indent
)
5068 stream_forward_getp(s
, tlv_len
);
5069 sbuf_push(log
, indent
,
5070 "Skipping unknown TLV %hhu (%hhu bytes)\n",
5075 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
5076 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5077 int indent
, bool *unpacked_known_tlvs
)
5079 uint8_t tlv_type
, tlv_len
;
5080 const struct tlv_ops
*ops
;
5082 sbuf_push(log
, indent
, "Unpacking TLV...\n");
5084 if (avail_len
< 2) {
5087 "Available data %zu too short to contain a TLV header.\n",
5092 tlv_type
= stream_getc(stream
);
5093 tlv_len
= stream_getc(stream
);
5095 sbuf_push(log
, indent
+ 2,
5096 "Found TLV of type %hhu and len %hhu.\n",
5099 if (avail_len
< ((size_t)tlv_len
) + 2) {
5100 sbuf_push(log
, indent
+ 2,
5101 "Available data %zu too short for claimed TLV len %hhu.\n",
5102 avail_len
- 2, tlv_len
);
5106 ops
= tlv_table
[context
][tlv_type
];
5107 if (ops
&& ops
->unpack
) {
5108 if (unpacked_known_tlvs
)
5109 *unpacked_known_tlvs
= true;
5110 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
5114 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
5118 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
5119 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5120 int indent
, bool *unpacked_known_tlvs
)
5123 size_t tlv_start
, tlv_pos
;
5125 tlv_start
= stream_get_getp(stream
);
5128 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
5129 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
5131 while (tlv_pos
< avail_len
) {
5132 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
5133 indent
+ 2, unpacked_known_tlvs
);
5137 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
5143 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
5144 struct isis_tlvs
**dest
, const char **log
)
5146 static struct sbuf logbuf
;
5149 struct isis_tlvs
*result
;
5151 if (!sbuf_buf(&logbuf
))
5152 sbuf_init(&logbuf
, NULL
, 0);
5154 sbuf_reset(&logbuf
);
5155 if (avail_len
> STREAM_READABLE(stream
)) {
5156 sbuf_push(&logbuf
, indent
,
5157 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5158 avail_len
, STREAM_READABLE(stream
));
5162 result
= isis_alloc_tlvs();
5163 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
5166 *log
= sbuf_buf(&logbuf
);
5172 #define TLV_OPS(_name_, _desc_) \
5173 static const struct tlv_ops tlv_##_name_##_ops = { \
5174 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5177 #define ITEM_TLV_OPS(_name_, _desc_) \
5178 static const struct tlv_ops tlv_##_name_##_ops = { \
5180 .unpack = unpack_tlv_with_items, \
5182 .pack_item = pack_item_##_name_, \
5183 .free_item = free_item_##_name_, \
5184 .unpack_item = unpack_item_##_name_, \
5185 .format_item = format_item_##_name_, \
5186 .copy_item = copy_item_##_name_}
5188 #define SUBTLV_OPS(_name_, _desc_) \
5189 static const struct tlv_ops subtlv_##_name_##_ops = { \
5190 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5193 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5194 ITEM_TLV_OPS(_name_, _desc_)
5196 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
5197 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
5198 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
5199 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
5200 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
5201 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
5202 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
5203 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
5204 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
5205 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
5206 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
5207 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
5208 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
5209 TLV_OPS(te_router_id_ipv6
, "TLV 140 IPv6 TE Router ID");
5210 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
5211 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
5212 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
5213 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
5214 ITEM_TLV_OPS(global_ipv6_address
, "TLV 233 Global IPv6 Interface Address");
5215 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
5216 TLV_OPS(router_cap
, "TLV 242 Router Capability");
5218 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
5219 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
5221 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
5222 [ISIS_CONTEXT_LSP
] = {
5223 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
5224 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
5225 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
5226 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
5227 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
5228 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
5229 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
5230 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
5231 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
5232 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
5233 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
5234 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
5235 [ISIS_TLV_TE_ROUTER_ID_IPV6
] = &tlv_te_router_id_ipv6_ops
,
5236 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5237 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
5238 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
5239 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
5240 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
5241 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
5242 [ISIS_TLV_GLOBAL_IPV6_ADDRESS
] = &tlv_global_ipv6_address_ops
,
5243 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5244 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5245 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5246 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
5247 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
5249 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
5250 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
5251 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5253 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
5254 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5255 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
5259 /* Accessor functions */
5261 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
5263 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
5264 init_item_list(&tlvs
->isis_auth
);
5266 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
5269 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
5271 auth
->type
= passwd
->type
;
5273 auth
->plength
= passwd
->len
;
5274 memcpy(auth
->passwd
, passwd
->passwd
,
5275 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
5277 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
5278 auth
->length
= passwd
->len
;
5279 memcpy(auth
->value
, passwd
->passwd
,
5280 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
5283 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
5286 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
5287 struct list
*addresses
)
5289 struct listnode
*node
;
5290 struct area_addr
*area_addr
;
5292 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
5293 struct isis_area_address
*a
=
5294 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5296 a
->len
= area_addr
->addr_len
;
5297 memcpy(a
->addr
, area_addr
->area_addr
, 20);
5298 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
5302 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
5304 struct listnode
*node
;
5307 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
5308 struct isis_lan_neighbor
*n
=
5309 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
5311 memcpy(n
->mac
, snpa
, 6);
5312 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
5316 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
5317 struct nlpids
*nlpids
)
5319 tlvs
->protocols_supported
.count
= nlpids
->count
;
5320 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
5321 if (nlpids
->count
) {
5322 tlvs
->protocols_supported
.protocols
=
5323 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
5324 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
5327 tlvs
->protocols_supported
.protocols
= NULL
;
5331 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5332 bool overload
, bool attached
)
5334 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
5336 i
->overload
= overload
;
5337 i
->attached
= attached
;
5339 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
5342 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
5344 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5346 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
5350 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
5351 struct list
*addresses
)
5353 struct listnode
*node
;
5354 struct prefix_ipv4
*ip_addr
;
5355 unsigned int addr_count
= 0;
5357 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5358 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
5360 if (addr_count
>= 63)
5365 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
5366 struct list
*addresses
)
5368 struct listnode
*node
;
5369 struct prefix_ipv6
*ip_addr
;
5370 unsigned int addr_count
= 0;
5372 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5373 if (addr_count
>= 15)
5376 struct isis_ipv6_address
*a
=
5377 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5379 a
->addr
= ip_addr
->prefix
;
5380 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
5385 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs
*tlvs
,
5386 struct list
*addresses
)
5388 struct listnode
*node
;
5389 struct prefix_ipv6
*ip_addr
;
5390 unsigned int addr_count
= 0;
5392 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5393 if (addr_count
>= 15)
5396 struct isis_ipv6_address
*a
=
5397 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5399 a
->addr
= ip_addr
->prefix
;
5400 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)a
);
5405 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
5406 struct stream
*stream
,
5407 struct isis_auth
*auth
, bool is_lsp
);
5409 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
5410 struct stream
*stream
,
5411 struct isis_auth
*auth
, bool is_lsp
)
5413 return (auth
->length
== passwd
->len
5414 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
5417 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
5418 struct stream
*stream
,
5419 struct isis_auth
*auth
, bool is_lsp
)
5423 uint16_t rem_lifetime
;
5426 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
5428 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
5429 #ifdef CRYPTO_OPENSSL
5430 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
5431 passwd
->len
, STREAM_DATA(stream
),
5432 stream_get_endp(stream
), NULL
, NULL
);
5434 memcpy(digest
, result
, 16);
5435 #elif CRYPTO_INTERNAL
5436 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
5437 passwd
->len
, digest
);
5439 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
5441 bool rv
= !memcmp(digest
, auth
->value
, 16);
5444 restore_auth_md5(stream
, checksum
, rem_lifetime
);
5449 static const auth_validator_func auth_validators
[] = {
5450 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
5451 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
5454 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
5455 struct stream
*stream
, bool is_lsp
)
5457 /* If no auth is set, always pass authentication */
5459 return ISIS_AUTH_OK
;
5461 /* If we don't known how to validate the auth, return invalid */
5462 if (passwd
->type
>= array_size(auth_validators
)
5463 || !auth_validators
[passwd
->type
])
5464 return ISIS_AUTH_NO_VALIDATOR
;
5466 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
5467 struct isis_auth
*auth
;
5468 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
5469 if (auth
->type
== passwd
->type
)
5473 /* If matching auth TLV could not be found, return invalid */
5475 return ISIS_AUTH_TYPE_FAILURE
;
5478 /* Perform validation and return result */
5479 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
5480 return ISIS_AUTH_OK
;
5482 return ISIS_AUTH_FAILURE
;
5485 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
5486 struct list
*addresses
)
5488 struct isis_area_address
*addr_head
;
5490 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
5491 for (struct isis_area_address
*addr
= addr_head
; addr
;
5492 addr
= addr
->next
) {
5493 struct listnode
*node
;
5494 struct area_addr
*a
;
5496 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
5497 if (a
->addr_len
== addr
->len
5498 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
5506 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
5507 struct isis_adjacency
*adj
,
5510 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
5511 uint32_t oc
= adj
->area_address_count
;
5514 adj
->area_address_count
= tlvs
->area_addresses
.count
;
5515 adj
->area_addresses
= XREALLOC(
5516 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
5517 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
5519 for (; oc
< adj
->area_address_count
; oc
++) {
5520 adj
->area_addresses
[oc
].addr_len
= 0;
5521 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
5522 sizeof(adj
->area_addresses
[oc
].area_addr
));
5526 struct isis_area_address
*addr
= NULL
;
5527 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
5529 addr
= (struct isis_area_address
*)
5530 tlvs
->area_addresses
.head
;
5534 if (adj
->area_addresses
[i
].addr_len
== addr
->len
5535 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
5541 adj
->area_addresses
[i
].addr_len
= addr
->len
;
5542 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
5546 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
5547 struct isis_adjacency
*adj
,
5550 bool ipv4_supported
= false, ipv6_supported
= false;
5552 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
5553 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
5554 ipv4_supported
= true;
5555 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
5556 ipv6_supported
= true;
5559 struct nlpids reduced
= {};
5561 if (ipv4_supported
&& ipv6_supported
) {
5563 reduced
.nlpids
[0] = NLPID_IP
;
5564 reduced
.nlpids
[1] = NLPID_IPV6
;
5565 } else if (ipv4_supported
) {
5567 reduced
.nlpids
[0] = NLPID_IP
;
5568 } else if (ipv6_supported
) {
5570 reduced
.nlpids
[0] = NLPID_IPV6
;
5575 if (adj
->nlpids
.count
== reduced
.count
5576 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
5580 adj
->nlpids
.count
= reduced
.count
;
5581 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
5584 DEFINE_HOOK(isis_adj_ip_enabled_hook
,
5585 (struct isis_adjacency
* adj
, int family
, bool global
),
5586 (adj
, family
, global
));
5587 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
5588 (struct isis_adjacency
* adj
, int family
, bool global
),
5589 (adj
, family
, global
));
5591 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
5592 struct isis_adjacency
*adj
,
5595 bool ipv4_enabled
= false;
5597 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
5598 ipv4_enabled
= true;
5599 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
5600 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
, false);
5602 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
5603 uint32_t oc
= adj
->ipv4_address_count
;
5606 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
5607 adj
->ipv4_addresses
= XREALLOC(
5608 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
5609 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
5611 for (; oc
< adj
->ipv4_address_count
; oc
++) {
5612 memset(&adj
->ipv4_addresses
[oc
], 0,
5613 sizeof(adj
->ipv4_addresses
[oc
]));
5617 struct isis_ipv4_address
*addr
= NULL
;
5618 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
5620 addr
= (struct isis_ipv4_address
*)
5621 tlvs
->ipv4_address
.head
;
5625 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
5626 sizeof(addr
->addr
)))
5630 adj
->ipv4_addresses
[i
] = addr
->addr
;
5634 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
, false);
5637 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5638 struct isis_adjacency
*adj
,
5641 bool ipv6_enabled
= false;
5643 if (adj
->ll_ipv6_count
== 0 && tlvs
->ipv6_address
.count
> 0)
5644 ipv6_enabled
= true;
5645 else if (adj
->ll_ipv6_count
> 0 && tlvs
->ipv6_address
.count
== 0)
5646 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, false);
5648 if (adj
->ll_ipv6_count
!= tlvs
->ipv6_address
.count
) {
5649 uint32_t oc
= adj
->ll_ipv6_count
;
5652 adj
->ll_ipv6_count
= tlvs
->ipv6_address
.count
;
5653 adj
->ll_ipv6_addrs
= XREALLOC(
5654 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
,
5655 adj
->ll_ipv6_count
* sizeof(*adj
->ll_ipv6_addrs
));
5657 for (; oc
< adj
->ll_ipv6_count
; oc
++) {
5658 memset(&adj
->ll_ipv6_addrs
[oc
], 0,
5659 sizeof(adj
->ll_ipv6_addrs
[oc
]));
5663 struct isis_ipv6_address
*addr
= NULL
;
5664 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
5666 addr
= (struct isis_ipv6_address
*)
5667 tlvs
->ipv6_address
.head
;
5671 if (!memcmp(&adj
->ll_ipv6_addrs
[i
], &addr
->addr
,
5672 sizeof(addr
->addr
)))
5676 adj
->ll_ipv6_addrs
[i
] = addr
->addr
;
5680 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, false);
5684 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5685 struct isis_adjacency
*adj
,
5688 bool global_ipv6_enabled
= false;
5690 if (adj
->global_ipv6_count
== 0 && tlvs
->global_ipv6_address
.count
> 0)
5691 global_ipv6_enabled
= true;
5692 else if (adj
->global_ipv6_count
> 0
5693 && tlvs
->global_ipv6_address
.count
== 0)
5694 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, true);
5696 if (adj
->global_ipv6_count
!= tlvs
->global_ipv6_address
.count
) {
5697 uint32_t oc
= adj
->global_ipv6_count
;
5700 adj
->global_ipv6_count
= tlvs
->global_ipv6_address
.count
;
5701 adj
->global_ipv6_addrs
= XREALLOC(
5702 MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
,
5703 adj
->global_ipv6_count
5704 * sizeof(*adj
->global_ipv6_addrs
));
5706 for (; oc
< adj
->global_ipv6_count
; oc
++) {
5707 memset(&adj
->global_ipv6_addrs
[oc
], 0,
5708 sizeof(adj
->global_ipv6_addrs
[oc
]));
5712 struct isis_ipv6_address
*addr
= NULL
;
5713 for (unsigned int i
= 0; i
< tlvs
->global_ipv6_address
.count
; i
++) {
5715 addr
= (struct isis_ipv6_address
*)
5716 tlvs
->global_ipv6_address
.head
;
5720 if (!memcmp(&adj
->global_ipv6_addrs
[i
], &addr
->addr
,
5721 sizeof(addr
->addr
)))
5725 adj
->global_ipv6_addrs
[i
] = addr
->addr
;
5728 if (global_ipv6_enabled
)
5729 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, true);
5732 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
5737 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
5738 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
5739 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
5740 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5741 tlvs_global_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5744 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
5746 struct isis_lan_neighbor
*ne_head
;
5748 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
5749 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
5750 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
5757 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
5759 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
5761 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
5762 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
5763 entry
->checksum
= lsp
->hdr
.checksum
;
5764 entry
->seqno
= lsp
->hdr
.seqno
;
5767 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
5770 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
5771 uint8_t *stop_id
, uint16_t num_lsps
,
5772 struct lspdb_head
*head
,
5773 struct isis_lsp
**last_lsp
)
5775 struct isis_lsp searchfor
;
5776 struct isis_lsp
*first
, *lsp
;
5778 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
5779 first
= lspdb_find_gteq(head
, &searchfor
);
5783 frr_each_from (lspdb
, head
, lsp
, first
) {
5784 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
5785 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
5788 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
5793 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
5794 const char *hostname
)
5796 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
5798 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
5801 /* Set Router Capability TLV parameters */
5802 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
5803 const struct isis_router_cap
*cap
)
5805 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
5809 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
5810 *tlvs
->router_cap
= *cap
;
5813 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
5814 const struct in_addr
*id
)
5816 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
5819 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5820 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
5823 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs
*tlvs
,
5824 const struct in6_addr
*id
)
5826 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id_ipv6
);
5829 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5830 memcpy(tlvs
->te_router_id_ipv6
, id
, sizeof(*id
));
5833 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
5834 struct prefix_ipv4
*dest
, uint8_t metric
)
5836 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5839 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5840 apply_mask_ipv4(&r
->prefix
);
5841 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
5844 /* Add IS-IS SR Adjacency-SID subTLVs */
5845 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
5846 struct isis_adj_sid
*adj
)
5848 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5849 SET_SUBTLV(exts
, EXT_ADJ_SID
);
5852 /* Delete IS-IS SR Adjacency-SID subTLVs */
5853 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
5854 struct isis_adj_sid
*adj
)
5856 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5857 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
5858 if (exts
->adj_sid
.count
== 0)
5859 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
5862 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
5863 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5864 struct isis_lan_adj_sid
*lan
)
5866 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5867 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5870 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
5871 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5872 struct isis_lan_adj_sid
*lan
)
5874 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5875 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
5876 if (exts
->lan_sid
.count
== 0)
5877 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5880 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
5881 struct prefix_ipv4
*dest
, uint32_t metric
,
5882 bool external
, struct sr_prefix_cfg
*pcfg
)
5884 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5887 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5888 apply_mask_ipv4(&r
->prefix
);
5890 struct isis_prefix_sid
*psid
=
5891 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5893 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5894 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5895 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5897 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
5900 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5901 struct prefix_ipv6
*dest
, uint32_t metric
,
5902 bool external
, struct sr_prefix_cfg
*pcfg
)
5904 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5907 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5908 apply_mask_ipv6(&r
->prefix
);
5910 struct isis_prefix_sid
*psid
=
5911 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5913 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5914 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5915 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5918 struct isis_item_list
*l
;
5919 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
5921 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
5922 append_item(l
, (struct isis_item
*)r
);
5925 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5926 struct prefix_ipv6
*dest
,
5927 struct prefix_ipv6
*src
,
5930 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
5931 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
5934 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
5935 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
5936 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
5937 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
5940 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
5943 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5946 memcpy(r
->id
, id
, sizeof(r
->id
));
5947 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
5950 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5951 uint8_t *id
, uint32_t metric
,
5952 struct isis_ext_subtlvs
*exts
)
5954 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5956 memcpy(r
->id
, id
, sizeof(r
->id
));
5959 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
5961 struct isis_item_list
*l
;
5962 if ((mtid
== ISIS_MT_IPV4_UNICAST
) || (mtid
== ISIS_MT_DISABLE
))
5963 l
= &tlvs
->extended_reach
;
5965 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
5966 append_item(l
, (struct isis_item
*)r
);
5969 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
5970 enum isis_threeway_state state
,
5971 uint32_t local_circuit_id
,
5972 const uint8_t *neighbor_id
,
5973 uint32_t neighbor_circuit_id
)
5975 assert(!tlvs
->threeway_adj
);
5977 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
5978 tlvs
->threeway_adj
->state
= state
;
5979 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
5982 tlvs
->threeway_adj
->neighbor_set
= true;
5983 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
5984 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
5988 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
5989 bool has_tier
, bool is_leaf
, bool is_spine
,
5992 assert(!tlvs
->spine_leaf
);
5994 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
5997 tlvs
->spine_leaf
->tier
= tier
;
6000 tlvs
->spine_leaf
->has_tier
= has_tier
;
6001 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
6002 tlvs
->spine_leaf
->is_spine
= is_spine
;
6003 tlvs
->spine_leaf
->is_backup
= is_backup
;
6006 struct isis_mt_router_info
*
6007 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
6009 if (!tlvs
|| tlvs
->mt_router_info_empty
)
6012 struct isis_mt_router_info
*rv
;
6013 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
6015 if (rv
->mtid
== mtid
)
6022 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
6023 const uint8_t *generator
,
6024 const uint8_t *sender
)
6026 assert(!tlvs
->purge_originator
);
6028 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
6029 sizeof(*tlvs
->purge_originator
));
6030 memcpy(tlvs
->purge_originator
->generator
, generator
,
6031 sizeof(tlvs
->purge_originator
->generator
));
6033 tlvs
->purge_originator
->sender_set
= true;
6034 memcpy(tlvs
->purge_originator
->sender
, sender
,
6035 sizeof(tlvs
->purge_originator
->sender
));