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 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
123 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
125 struct isis_ext_subtlvs
*ext
;
127 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
128 init_item_list(&ext
->adj_sid
);
129 init_item_list(&ext
->lan_sid
);
135 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
136 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
137 * that MT is disabled i.e. IS-IS is working with a Single Topology.
139 static struct isis_ext_subtlvs
*
140 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, uint16_t mtid
)
142 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
143 struct isis_adj_sid
*adj
;
144 struct isis_lan_adj_sid
*lan
;
146 /* Copy the Extended IS main part */
147 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
149 /* Disable IPv4 / IPv6 advertisement in function of MTID */
150 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
151 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR6
);
152 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR6
);
154 if (mtid
== ISIS_MT_IPV6_UNICAST
) {
155 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR
);
156 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR
);
159 /* Prepare (LAN)-Adjacency Segment Routing ID*/
160 init_item_list(&rv
->adj_sid
);
161 init_item_list(&rv
->lan_sid
);
163 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
164 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
166 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
167 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
169 if ((mtid
!= ISIS_MT_DISABLE
)
170 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
171 && (adj
->family
!= AF_INET
))
172 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
173 && (adj
->family
!= AF_INET6
))))
176 struct isis_adj_sid
*new;
178 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
179 new->family
= adj
->family
;
180 new->flags
= adj
->flags
;
181 new->weight
= adj
->weight
;
183 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
184 SET_SUBTLV(rv
, EXT_ADJ_SID
);
187 /* Same for LAN Adj SID */
188 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
190 if ((mtid
!= ISIS_MT_DISABLE
)
191 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
192 && (lan
->family
!= AF_INET
))
193 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
194 && (lan
->family
!= AF_INET6
))))
197 struct isis_lan_adj_sid
*new;
199 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
200 new->family
= lan
->family
;
201 new->flags
= lan
->flags
;
202 new->weight
= lan
->weight
;
203 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
205 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
206 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
212 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
213 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
214 struct sbuf
*buf
, struct json_object
*json
,
215 int indent
, uint16_t mtid
)
220 /* Standard metrics */
221 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
223 snprintfrr(aux_buf
, sizeof(aux_buf
), "0x%x",
225 json_object_string_add(json
, "adm-group", aux_buf
);
227 sbuf_push(buf
, indent
, "Administrative Group: 0x%x\n",
230 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
232 json_object_int_add(json
, "link-local-id",
234 json_object_int_add(json
, "link-remote-id",
237 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
239 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
243 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
245 inet_ntop(AF_INET
, &exts
->local_addr
, aux_buf
,
247 json_object_string_add(json
, "local-iface-ip", aux_buf
);
249 sbuf_push(buf
, indent
,
250 "Local Interface IP Address(es): %pI4\n",
253 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
255 inet_ntop(AF_INET
, &exts
->neigh_addr
, aux_buf
,
257 json_object_string_add(json
, "remote-iface-ip",
260 sbuf_push(buf
, indent
,
261 "Remote Interface IP Address(es): %pI4\n",
264 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
266 inet_ntop(AF_INET6
, &exts
->local_addr6
, aux_buf
,
268 json_object_string_add(json
, "local-iface-ipv6",
271 sbuf_push(buf
, indent
,
272 "Local Interface IPv6 Address(es): %pI6\n",
275 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
277 inet_ntop(AF_INET6
, &exts
->neigh_addr6
, aux_buf
,
279 json_object_string_add(json
, "remote-iface-ipv6",
282 sbuf_push(buf
, indent
,
283 "Remote Interface IPv6 Address(es): %pI6\n",
286 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
288 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
290 json_object_string_add(json
, "max-bandwith-bytes-sec",
293 sbuf_push(buf
, indent
,
294 "Maximum Bandwidth: %g (Bytes/sec)\n",
297 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
299 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
301 json_object_string_add(
302 json
, "max-res-bandwith-bytes-sec", aux_buf
);
306 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
309 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
311 struct json_object
*unrsv_json
;
312 unrsv_json
= json_object_new_object();
313 json_object_object_add(json
, "unrsv-bandwith-bytes-sec",
315 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 1) {
316 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d", j
);
317 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
319 json_object_string_add(unrsv_json
, cnt_buf
,
323 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
324 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
327 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
328 j
, exts
->unrsv_bw
[j
], j
+ 1,
329 exts
->unrsv_bw
[j
+ 1]);
333 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
335 json_object_int_add(json
, "te-metric", exts
->te_metric
);
337 sbuf_push(buf
, indent
,
338 "Traffic Engineering Metric: %u\n",
341 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
343 json_object_int_add(json
, "inter-as-te-remote-as",
346 sbuf_push(buf
, indent
,
347 "Inter-AS TE Remote AS number: %u\n",
350 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
352 inet_ntop(AF_INET6
, &exts
->remote_ip
, aux_buf
,
354 json_object_string_add(
355 json
, "inter-as-te-remote-asbr-ip", aux_buf
);
357 sbuf_push(buf
, indent
,
358 "Inter-AS TE Remote ASBR IP address: %pI4\n",
361 /* Extended metrics */
362 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
364 struct json_object
*avg_json
;
365 avg_json
= json_object_new_object();
366 json_object_object_add(json
, "avg-delay", avg_json
);
367 json_object_string_add(avg_json
, "delay",
368 IS_ANORMAL(exts
->delay
)
371 json_object_int_add(avg_json
, "micro-sec", exts
->delay
);
373 sbuf_push(buf
, indent
,
374 "%s Average Link Delay: %u (micro-sec)\n",
375 IS_ANORMAL(exts
->delay
) ? "Anomalous"
379 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
381 struct json_object
*avg_json
;
382 avg_json
= json_object_new_object();
383 json_object_object_add(json
, "max-min-delay", avg_json
);
384 json_object_string_add(avg_json
, "delay",
385 IS_ANORMAL(exts
->min_delay
)
388 snprintfrr(aux_buf
, sizeof(aux_buf
), "%u / %u",
389 exts
->min_delay
& TE_EXT_MASK
,
390 exts
->max_delay
& TE_EXT_MASK
);
391 json_object_string_add(avg_json
, "micro-sec", aux_buf
);
396 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
397 IS_ANORMAL(exts
->min_delay
) ? "Anomalous"
399 exts
->min_delay
& TE_EXT_MASK
,
400 exts
->max_delay
& TE_EXT_MASK
);
402 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
404 json_object_int_add(json
, "delay-variation-micro-sec",
405 exts
->delay_var
& TE_EXT_MASK
);
407 sbuf_push(buf
, indent
,
408 "Delay Variation: %u (micro-sec)\n",
409 exts
->delay_var
& TE_EXT_MASK
);
411 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
413 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
414 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
416 struct json_object
*link_json
;
417 link_json
= json_object_new_object();
418 json_object_object_add(json
, "link-packet-loss",
420 json_object_string_add(link_json
, "loss",
421 IS_ANORMAL(exts
->pkt_loss
)
424 json_object_string_add(link_json
, "percentaje",
427 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
428 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous"
430 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
433 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
435 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
437 json_object_string_add(json
,
438 "unidir-residual-band-bytes-sec",
443 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
446 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
448 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
450 json_object_string_add(
451 json
, "unidir-available-band-bytes-sec",
456 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
459 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
461 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
463 json_object_string_add(json
,
464 "unidir-utilized-band-bytes-sec",
469 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
472 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
473 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
474 struct isis_adj_sid
*adj
;
477 struct json_object
*arr_adj_json
, *flags_json
;
478 arr_adj_json
= json_object_new_array();
479 json_object_object_add(json
, "adj-sid", arr_adj_json
);
480 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
481 adj
; adj
= adj
->next
) {
482 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
484 flags_json
= json_object_new_object();
485 json_object_int_add(flags_json
, "sid",
487 json_object_int_add(flags_json
, "weight",
489 json_object_string_add(
490 flags_json
, "flag-f",
491 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
494 json_object_string_add(
495 flags_json
, "flag-b",
496 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
499 json_object_string_add(
500 flags_json
, "flag-v",
501 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
504 json_object_string_add(
505 flags_json
, "flag-l",
506 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
509 json_object_string_add(
510 flags_json
, "flag-s",
511 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
514 json_object_string_add(
515 flags_json
, "flag-p",
516 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
519 json_object_array_add(arr_adj_json
, flags_json
);
522 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
523 adj
; adj
= adj
->next
) {
526 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
527 adj
->sid
, adj
->weight
,
528 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
531 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
534 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
537 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
540 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
543 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
548 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
549 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
550 struct isis_lan_adj_sid
*lan
;
552 struct json_object
*arr_adj_json
, *flags_json
;
553 arr_adj_json
= json_object_new_array();
554 json_object_object_add(json
, "lan-adj-sid",
556 for (lan
= (struct isis_lan_adj_sid
*)
558 lan
; lan
= lan
->next
) {
559 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
560 (lan
->family
!= AF_INET
)) ||
561 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
562 (lan
->family
!= AF_INET6
)))
564 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
566 flags_json
= json_object_new_object();
567 json_object_int_add(flags_json
, "sid",
569 json_object_int_add(flags_json
, "weight",
571 json_object_string_add(
572 flags_json
, "flag-f",
573 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
576 json_object_string_add(
577 flags_json
, "flag-b",
578 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
581 json_object_string_add(
582 flags_json
, "flag-v",
583 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
586 json_object_string_add(
587 flags_json
, "flag-l",
588 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
591 json_object_string_add(
592 flags_json
, "flag-s",
593 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
596 json_object_string_add(
597 flags_json
, "flag-p",
598 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
601 json_object_array_add(arr_adj_json
, flags_json
);
605 for (lan
= (struct isis_lan_adj_sid
*)
607 lan
; lan
= lan
->next
) {
608 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
609 (lan
->family
!= AF_INET
)) ||
610 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
611 (lan
->family
!= AF_INET6
)))
615 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
616 " Neighbor-ID: %s\n",
617 lan
->sid
, lan
->weight
,
618 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
621 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
624 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
627 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
630 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
633 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
636 isis_format_id(lan
->neighbor_id
, 6));
641 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
643 struct isis_item
*item
, *next_item
;
645 /* First, free Adj SID and LAN Adj SID list if needed */
646 for (item
= exts
->adj_sid
.head
; item
; item
= next_item
) {
647 next_item
= item
->next
;
648 XFREE(MTYPE_ISIS_SUBTLV
, item
);
650 for (item
= exts
->lan_sid
.head
; item
; item
= next_item
) {
651 next_item
= item
->next
;
652 XFREE(MTYPE_ISIS_SUBTLV
, item
);
654 XFREE(MTYPE_ISIS_SUBTLV
, exts
);
657 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
658 struct stream
*s
, size_t *min_len
)
662 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
663 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
667 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
668 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
669 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
670 stream_putl(s
, exts
->adm_group
);
672 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
673 stream_putc(s
, ISIS_SUBTLV_LLRI
);
674 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
675 stream_putl(s
, exts
->local_llri
);
676 stream_putl(s
, exts
->remote_llri
);
678 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
679 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
680 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
681 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
683 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
684 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
685 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
686 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
688 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
689 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
690 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
691 stream_put(s
, &exts
->local_addr6
, 16);
693 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
694 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
695 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
696 stream_put(s
, &exts
->neigh_addr6
, 16);
698 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
699 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
700 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
701 stream_putf(s
, exts
->max_bw
);
703 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
704 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
705 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
706 stream_putf(s
, exts
->max_rsv_bw
);
708 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
709 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
710 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
711 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
712 stream_putf(s
, exts
->unrsv_bw
[j
]);
714 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
715 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
716 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
717 stream_put3(s
, exts
->te_metric
);
719 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
720 stream_putc(s
, ISIS_SUBTLV_RAS
);
721 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
722 stream_putl(s
, exts
->remote_as
);
724 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
725 stream_putc(s
, ISIS_SUBTLV_RIP
);
726 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
727 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
729 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
730 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
731 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
732 stream_putl(s
, exts
->delay
);
734 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
735 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
736 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
737 stream_putl(s
, exts
->min_delay
);
738 stream_putl(s
, exts
->max_delay
);
740 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
741 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
742 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
743 stream_putl(s
, exts
->delay_var
);
745 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
746 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
747 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
748 stream_putl(s
, exts
->pkt_loss
);
750 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
751 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
752 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
753 stream_putf(s
, exts
->res_bw
);
755 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
756 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
757 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
758 stream_putf(s
, exts
->ava_bw
);
760 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
761 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
762 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
763 stream_putf(s
, exts
->use_bw
);
765 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
766 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
767 struct isis_adj_sid
*adj
;
769 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
771 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
772 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
773 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
775 stream_putc(s
, size
);
776 stream_putc(s
, adj
->flags
);
777 stream_putc(s
, adj
->weight
);
778 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
779 stream_put3(s
, adj
->sid
);
781 stream_putl(s
, adj
->sid
);
785 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
786 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
787 struct isis_lan_adj_sid
*lan
;
789 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
791 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
792 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
793 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
795 stream_putc(s
, size
);
796 stream_putc(s
, lan
->flags
);
797 stream_putc(s
, lan
->weight
);
798 stream_put(s
, lan
->neighbor_id
, 6);
799 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
800 stream_put3(s
, lan
->sid
);
802 stream_putl(s
, lan
->sid
);
809 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
810 struct sbuf
*log
, void *dest
, int indent
)
816 struct isis_extended_reach
*rv
= dest
;
817 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
822 * Parse subTLVs until reach subTLV length
823 * Check that it remains at least 2 bytes: subTLV Type & Length
825 while (len
> sum
+ 2) {
826 /* Read SubTLV Type and Length */
827 subtlv_type
= stream_getc(s
);
828 subtlv_len
= stream_getc(s
);
829 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
832 "TLV %hhu: Available data %u is less than TLV size %u !\n",
833 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
838 switch (subtlv_type
) {
839 /* Standard Metric as defined in RFC5305 */
840 case ISIS_SUBTLV_ADMIN_GRP
:
841 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
842 sbuf_push(log
, indent
,
843 "TLV size does not match expected size for Administrative Group!\n");
844 stream_forward_getp(s
, subtlv_len
);
846 exts
->adm_group
= stream_getl(s
);
847 SET_SUBTLV(exts
, EXT_ADM_GRP
);
850 case ISIS_SUBTLV_LLRI
:
851 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
852 sbuf_push(log
, indent
,
853 "TLV size does not match expected size for Link ID!\n");
854 stream_forward_getp(s
, subtlv_len
);
856 exts
->local_llri
= stream_getl(s
);
857 exts
->remote_llri
= stream_getl(s
);
858 SET_SUBTLV(exts
, EXT_LLRI
);
861 case ISIS_SUBTLV_LOCAL_IPADDR
:
862 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
863 sbuf_push(log
, indent
,
864 "TLV size does not match expected size for Local IP address!\n");
865 stream_forward_getp(s
, subtlv_len
);
867 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
868 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
871 case ISIS_SUBTLV_RMT_IPADDR
:
872 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
873 sbuf_push(log
, indent
,
874 "TLV size does not match expected size for Remote IP address!\n");
875 stream_forward_getp(s
, subtlv_len
);
877 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
878 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
881 case ISIS_SUBTLV_LOCAL_IPADDR6
:
882 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
883 sbuf_push(log
, indent
,
884 "TLV size does not match expected size for Local IPv6 address!\n");
885 stream_forward_getp(s
, subtlv_len
);
887 stream_get(&exts
->local_addr6
, s
, 16);
888 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
891 case ISIS_SUBTLV_RMT_IPADDR6
:
892 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
893 sbuf_push(log
, indent
,
894 "TLV size does not match expected size for Remote IPv6 address!\n");
895 stream_forward_getp(s
, subtlv_len
);
897 stream_get(&exts
->neigh_addr6
, s
, 16);
898 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
901 case ISIS_SUBTLV_MAX_BW
:
902 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
903 sbuf_push(log
, indent
,
904 "TLV size does not match expected size for Maximum Bandwidth!\n");
905 stream_forward_getp(s
, subtlv_len
);
907 exts
->max_bw
= stream_getf(s
);
908 SET_SUBTLV(exts
, EXT_MAX_BW
);
911 case ISIS_SUBTLV_MAX_RSV_BW
:
912 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
913 sbuf_push(log
, indent
,
914 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
915 stream_forward_getp(s
, subtlv_len
);
917 exts
->max_rsv_bw
= stream_getf(s
);
918 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
921 case ISIS_SUBTLV_UNRSV_BW
:
922 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
923 sbuf_push(log
, indent
,
924 "TLV size does not match expected size for Unreserved Bandwidth!\n");
925 stream_forward_getp(s
, subtlv_len
);
927 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
928 exts
->unrsv_bw
[i
] = stream_getf(s
);
929 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
932 case ISIS_SUBTLV_TE_METRIC
:
933 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
934 sbuf_push(log
, indent
,
935 "TLV size does not match expected size for Traffic Engineering Metric!\n");
936 stream_forward_getp(s
, subtlv_len
);
938 exts
->te_metric
= stream_get3(s
);
939 SET_SUBTLV(exts
, EXT_TE_METRIC
);
942 case ISIS_SUBTLV_RAS
:
943 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
944 sbuf_push(log
, indent
,
945 "TLV size does not match expected size for Remote AS number!\n");
946 stream_forward_getp(s
, subtlv_len
);
948 exts
->remote_as
= stream_getl(s
);
949 SET_SUBTLV(exts
, EXT_RMT_AS
);
952 case ISIS_SUBTLV_RIP
:
953 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
954 sbuf_push(log
, indent
,
955 "TLV size does not match expected size for Remote ASBR IP Address!\n");
956 stream_forward_getp(s
, subtlv_len
);
958 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
959 SET_SUBTLV(exts
, EXT_RMT_IP
);
962 /* Extended Metrics as defined in RFC 7810 */
963 case ISIS_SUBTLV_AV_DELAY
:
964 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
965 sbuf_push(log
, indent
,
966 "TLV size does not match expected size for Average Link Delay!\n");
967 stream_forward_getp(s
, subtlv_len
);
969 exts
->delay
= stream_getl(s
);
970 SET_SUBTLV(exts
, EXT_DELAY
);
973 case ISIS_SUBTLV_MM_DELAY
:
974 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
975 sbuf_push(log
, indent
,
976 "TLV size does not match expected size for Min/Max Link Delay!\n");
977 stream_forward_getp(s
, subtlv_len
);
979 exts
->min_delay
= stream_getl(s
);
980 exts
->max_delay
= stream_getl(s
);
981 SET_SUBTLV(exts
, EXT_MM_DELAY
);
984 case ISIS_SUBTLV_DELAY_VAR
:
985 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
986 sbuf_push(log
, indent
,
987 "TLV size does not match expected size for Delay Variation!\n");
988 stream_forward_getp(s
, subtlv_len
);
990 exts
->delay_var
= stream_getl(s
);
991 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
994 case ISIS_SUBTLV_PKT_LOSS
:
995 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
996 sbuf_push(log
, indent
,
997 "TLV size does not match expected size for Link Packet Loss!\n");
998 stream_forward_getp(s
, subtlv_len
);
1000 exts
->pkt_loss
= stream_getl(s
);
1001 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
1004 case ISIS_SUBTLV_RES_BW
:
1005 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1006 sbuf_push(log
, indent
,
1007 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
1008 stream_forward_getp(s
, subtlv_len
);
1010 exts
->res_bw
= stream_getf(s
);
1011 SET_SUBTLV(exts
, EXT_RES_BW
);
1014 case ISIS_SUBTLV_AVA_BW
:
1015 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1016 sbuf_push(log
, indent
,
1017 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
1018 stream_forward_getp(s
, subtlv_len
);
1020 exts
->ava_bw
= stream_getf(s
);
1021 SET_SUBTLV(exts
, EXT_AVA_BW
);
1024 case ISIS_SUBTLV_USE_BW
:
1025 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1026 sbuf_push(log
, indent
,
1027 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
1028 stream_forward_getp(s
, subtlv_len
);
1030 exts
->use_bw
= stream_getf(s
);
1031 SET_SUBTLV(exts
, EXT_USE_BW
);
1034 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1035 case ISIS_SUBTLV_ADJ_SID
:
1036 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
1037 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
1038 sbuf_push(log
, indent
,
1039 "TLV size does not match expected size for Adjacency SID!\n");
1040 stream_forward_getp(s
, subtlv_len
);
1042 struct isis_adj_sid
*adj
;
1044 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1045 sizeof(struct isis_adj_sid
));
1046 adj
->flags
= stream_getc(s
);
1047 adj
->weight
= stream_getc(s
);
1048 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1049 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
1052 "TLV size does not match expected size for Adjacency SID!\n");
1053 stream_forward_getp(s
, subtlv_len
- 2);
1057 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1059 != ISIS_SUBTLV_ADJ_SID_SIZE
1063 "TLV size does not match expected size for Adjacency SID!\n");
1064 stream_forward_getp(s
, subtlv_len
- 2);
1068 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1069 adj
->sid
= stream_get3(s
);
1070 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
1072 adj
->sid
= stream_getl(s
);
1074 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1075 adj
->family
= AF_INET
;
1076 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1077 adj
->family
= AF_INET6
;
1078 append_item(&exts
->adj_sid
,
1079 (struct isis_item
*)adj
);
1080 SET_SUBTLV(exts
, EXT_ADJ_SID
);
1083 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1084 case ISIS_SUBTLV_LAN_ADJ_SID
:
1085 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1086 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
1087 sbuf_push(log
, indent
,
1088 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1089 stream_forward_getp(s
, subtlv_len
);
1091 struct isis_lan_adj_sid
*lan
;
1093 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1094 sizeof(struct isis_lan_adj_sid
));
1095 lan
->flags
= stream_getc(s
);
1096 lan
->weight
= stream_getc(s
);
1097 stream_get(&(lan
->neighbor_id
), s
,
1100 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1102 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
1105 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1106 stream_forward_getp(
1112 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1114 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1118 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1119 stream_forward_getp(
1125 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1126 lan
->sid
= stream_get3(s
);
1127 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
1129 lan
->sid
= stream_getl(s
);
1131 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1132 lan
->family
= AF_INET
;
1133 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1134 lan
->family
= AF_INET6
;
1135 append_item(&exts
->lan_sid
,
1136 (struct isis_item
*)lan
);
1137 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
1141 /* Skip unknown TLV */
1142 stream_forward_getp(s
, subtlv_len
);
1145 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
1151 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1152 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
1154 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1155 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1157 rv
->flags
= sid
->flags
;
1158 rv
->algorithm
= sid
->algorithm
;
1159 rv
->value
= sid
->value
;
1160 return (struct isis_item
*)rv
;
1163 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
1164 struct sbuf
*buf
, struct json_object
*json
,
1167 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1170 struct json_object
*sr_json
;
1171 sr_json
= json_object_new_object();
1172 json_object_object_add(json
, "sr", sr_json
);
1173 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1174 json_object_int_add(sr_json
, "label", sid
->value
);
1176 json_object_int_add(sr_json
, "index", sid
->value
);
1178 json_object_int_add(sr_json
, "alg", sid
->algorithm
);
1179 json_object_string_add(
1180 sr_json
, "readvertised",
1181 ((sid
->flags
& ISIS_PREFIX_SID_READVERTISED
) ? "yes"
1183 json_object_string_add(
1185 ((sid
->flags
& ISIS_PREFIX_SID_NODE
) ? "yes" : ""));
1186 json_object_string_add(sr_json
, "php",
1187 ((sid
->flags
& ISIS_PREFIX_SID_NO_PHP
)
1190 json_object_string_add(
1191 sr_json
, "explicit-null",
1192 ((sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
) ? "yes"
1194 json_object_string_add(
1196 ((sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? "yes" : ""));
1197 json_object_string_add(
1199 ((sid
->flags
& ISIS_PREFIX_SID_LOCAL
) ? "yes" : ""));
1202 sbuf_push(buf
, indent
, "SR Prefix-SID ");
1203 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1204 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
1206 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
1208 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
1209 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
1210 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
1213 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
1214 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP"
1216 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
1219 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
1220 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
1224 static void free_item_prefix_sid(struct isis_item
*i
)
1226 XFREE(MTYPE_ISIS_SUBTLV
, i
);
1229 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
1232 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1234 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
1236 if (STREAM_WRITEABLE(s
) < size
) {
1241 stream_putc(s
, sid
->flags
);
1242 stream_putc(s
, sid
->algorithm
);
1244 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1245 stream_put3(s
, sid
->value
);
1247 stream_putl(s
, sid
->value
);
1253 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1254 struct sbuf
*log
, void *dest
, int indent
)
1256 struct isis_subtlvs
*subtlvs
= dest
;
1257 struct isis_prefix_sid sid
= {
1260 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
1263 sbuf_push(log
, indent
,
1264 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1269 sid
.flags
= stream_getc(s
);
1270 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1271 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
1272 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
1276 sid
.algorithm
= stream_getc(s
);
1278 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1279 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1280 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
1281 if (len
!= expected_size
) {
1282 sbuf_push(log
, indent
,
1283 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1284 expected_size
, len
);
1288 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
1289 sid
.value
= stream_get3(s
);
1290 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
1291 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
1296 sid
.value
= stream_getl(s
);
1299 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, NULL
, indent
+ 2);
1300 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
1304 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1306 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
1311 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1312 rv
->family
= p
->family
;
1313 rv
->prefixlen
= p
->prefixlen
;
1314 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
1318 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1320 struct json_object
*json
,
1326 char prefixbuf
[PREFIX2STR_BUFFER
];
1328 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
));
1329 json_object_string_add(json
, "ipv6-src-prefix", prefixbuf
);
1331 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1332 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1336 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1342 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1345 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1346 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1347 stream_putc(s
, p
->prefixlen
);
1348 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1352 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1353 uint8_t tlv_type
, uint8_t tlv_len
,
1354 struct stream
*s
, struct sbuf
*log
,
1355 void *dest
, int indent
)
1357 struct isis_subtlvs
*subtlvs
= dest
;
1358 struct prefix_ipv6 p
= {
1362 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1365 sbuf_push(log
, indent
,
1366 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1371 p
.prefixlen
= stream_getc(s
);
1372 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1373 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1378 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1381 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1382 1 + PSIZE(p
.prefixlen
), tlv_len
);
1386 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1388 if (subtlvs
->source_prefix
) {
1391 "WARNING: source prefix Sub-TLV present multiple times.\n");
1392 /* Ignore all but first occurrence of the source prefix Sub-TLV
1397 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1398 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1402 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1403 enum isis_tlv_type type
,
1404 struct isis_item
*item
);
1405 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1406 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1407 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1408 enum isis_tlv_type type
, struct isis_item_list
*items
,
1409 struct sbuf
*buf
, struct json_object
*json
,
1411 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1412 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1413 struct isis_item_list
*items
);
1414 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1415 enum isis_tlv_type type
, struct isis_item_list
*items
,
1416 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1417 const struct pack_order_entry
*pe
,
1418 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1419 struct list
*new_fragment_arg
);
1420 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1422 /* Functions related to subtlvs */
1424 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1426 struct isis_subtlvs
*result
;
1428 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1429 result
->context
= context
;
1431 init_item_list(&result
->prefix_sids
);
1436 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1441 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1443 rv
->context
= subtlvs
->context
;
1445 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1446 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1449 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1453 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1454 struct json_object
*json
, int indent
)
1456 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1457 &subtlvs
->prefix_sids
, buf
, json
, indent
);
1459 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, json
, indent
);
1462 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1467 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1468 &subtlvs
->prefix_sids
);
1470 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1472 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1475 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1478 size_t subtlv_len_pos
= stream_get_endp(s
);
1480 if (STREAM_WRITEABLE(s
) < 1)
1483 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1485 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1486 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1490 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1494 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1495 if (subtlv_len
> 255)
1498 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1502 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1503 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1504 int indent
, bool *unpacked_known_tlvs
);
1506 /* Functions related to TLVs 1 Area Addresses */
1508 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1510 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1511 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1513 rv
->len
= addr
->len
;
1514 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1515 return (struct isis_item
*)rv
;
1518 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1519 struct sbuf
*buf
, struct json_object
*json
,
1522 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1525 json_object_string_add(json
, "area-addr",
1526 isonet_print(addr
->addr
, addr
->len
));
1528 sbuf_push(buf
, indent
, "Area Address: %s\n",
1529 isonet_print(addr
->addr
, addr
->len
));
1533 static void free_item_area_address(struct isis_item
*i
)
1535 XFREE(MTYPE_ISIS_TLV
, i
);
1538 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
1541 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1543 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
1544 *min_len
= (unsigned)1 + addr
->len
;
1547 stream_putc(s
, addr
->len
);
1548 stream_put(s
, addr
->addr
, addr
->len
);
1552 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1553 struct stream
*s
, struct sbuf
*log
,
1554 void *dest
, int indent
)
1556 struct isis_tlvs
*tlvs
= dest
;
1557 struct isis_area_address
*rv
= NULL
;
1559 sbuf_push(log
, indent
, "Unpack area address...\n");
1563 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1568 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1569 rv
->len
= stream_getc(s
);
1571 if (len
< 1 + rv
->len
) {
1572 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1577 if (rv
->len
< 1 || rv
->len
> 20) {
1578 sbuf_push(log
, indent
,
1579 "Implausible area address length %hhu\n",
1584 stream_get(rv
->addr
, s
, rv
->len
);
1586 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1587 log
, NULL
, indent
+ 2);
1588 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1591 XFREE(MTYPE_ISIS_TLV
, rv
);
1595 /* Functions related to TLV 2 (Old-Style) IS Reach */
1596 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1598 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1599 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1601 memcpy(rv
->id
, r
->id
, 7);
1602 rv
->metric
= r
->metric
;
1603 return (struct isis_item
*)rv
;
1606 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1608 struct json_object
*json
, int indent
)
1610 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1613 struct json_object
*old_json
;
1614 old_json
= json_object_new_object();
1615 json_object_object_add(json
, "old-reach-style", old_json
);
1616 json_object_string_add(old_json
, "is-reach",
1617 isis_format_id(r
->id
, 7));
1618 json_object_int_add(old_json
, "metric", r
->metric
);
1620 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
1621 isis_format_id(r
->id
, 7), r
->metric
);
1624 static void free_item_oldstyle_reach(struct isis_item
*i
)
1626 XFREE(MTYPE_ISIS_TLV
, i
);
1629 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
1632 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1634 if (STREAM_WRITEABLE(s
) < 11) {
1639 stream_putc(s
, r
->metric
);
1640 stream_putc(s
, 0x80); /* delay metric - unsupported */
1641 stream_putc(s
, 0x80); /* expense metric - unsupported */
1642 stream_putc(s
, 0x80); /* error metric - unsupported */
1643 stream_put(s
, r
->id
, 7);
1648 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1649 struct stream
*s
, struct sbuf
*log
,
1650 void *dest
, int indent
)
1652 struct isis_tlvs
*tlvs
= dest
;
1654 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1658 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1663 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1664 rv
->metric
= stream_getc(s
);
1665 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1666 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1669 stream_forward_getp(s
, 3); /* Skip other metrics */
1670 stream_get(rv
->id
, s
, 7);
1672 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1674 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1678 /* Functions related to TLV 6 LAN Neighbors */
1679 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1681 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1682 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1684 memcpy(rv
->mac
, n
->mac
, 6);
1685 return (struct isis_item
*)rv
;
1688 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1689 struct sbuf
*buf
, struct json_object
*json
,
1692 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1695 json_object_string_add(json
, "lan-neighbor",
1696 isis_format_id(n
->mac
, 6));
1698 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n",
1699 isis_format_id(n
->mac
, 6));
1702 static void free_item_lan_neighbor(struct isis_item
*i
)
1704 XFREE(MTYPE_ISIS_TLV
, i
);
1707 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
1710 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1712 if (STREAM_WRITEABLE(s
) < 6) {
1717 stream_put(s
, n
->mac
, 6);
1722 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1723 struct stream
*s
, struct sbuf
*log
,
1724 void *dest
, int indent
)
1726 struct isis_tlvs
*tlvs
= dest
;
1728 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1732 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1737 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1738 stream_get(rv
->mac
, s
, 6);
1740 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1741 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1745 /* Functions related to TLV 9 LSP Entry */
1746 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1748 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1749 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1751 rv
->rem_lifetime
= e
->rem_lifetime
;
1752 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1753 rv
->seqno
= e
->seqno
;
1754 rv
->checksum
= e
->checksum
;
1756 return (struct isis_item
*)rv
;
1759 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1760 struct sbuf
*buf
, struct json_object
*json
,
1763 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1767 struct json_object
*lsp_json
;
1768 lsp_json
= json_object_new_object();
1769 json_object_object_add(json
, "lsp-entry", lsp_json
);
1770 json_object_string_add(lsp_json
, "id", isis_format_id(e
->id
, 8));
1771 snprintfrr(buf
,sizeof(buf
),"0x%08x",e
->seqno
);
1772 json_object_string_add(lsp_json
, "seq", buf
);
1773 snprintfrr(buf
,sizeof(buf
),"0x%04hx",e
->checksum
);
1774 json_object_string_add(lsp_json
, "chksum", buf
);
1775 json_object_int_add(lsp_json
, "lifetime", e
->checksum
);
1777 sbuf_push(buf
, indent
,
1778 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1779 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1783 static void free_item_lsp_entry(struct isis_item
*i
)
1785 XFREE(MTYPE_ISIS_TLV
, i
);
1788 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
1791 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1793 if (STREAM_WRITEABLE(s
) < 16) {
1798 stream_putw(s
, e
->rem_lifetime
);
1799 stream_put(s
, e
->id
, 8);
1800 stream_putl(s
, e
->seqno
);
1801 stream_putw(s
, e
->checksum
);
1806 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1807 struct sbuf
*log
, void *dest
, int indent
)
1809 struct isis_tlvs
*tlvs
= dest
;
1811 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1815 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1820 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1821 rv
->rem_lifetime
= stream_getw(s
);
1822 stream_get(rv
->id
, s
, 8);
1823 rv
->seqno
= stream_getl(s
);
1824 rv
->checksum
= stream_getw(s
);
1826 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1827 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1831 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1833 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1835 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1836 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1838 memcpy(rv
->id
, r
->id
, 7);
1839 rv
->metric
= r
->metric
;
1842 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1844 return (struct isis_item
*)rv
;
1847 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1849 struct json_object
*json
, int indent
)
1851 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1854 struct json_object
*reach_json
;
1855 reach_json
= json_object_new_object();
1856 json_object_object_add(json
, "ext-reach", reach_json
);
1857 json_object_string_add(
1858 reach_json
, "mt-id",
1859 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
1860 json_object_string_add(reach_json
, "id",
1861 isis_format_id(r
->id
, 7));
1862 json_object_int_add(reach_json
, "metric", r
->metric
);
1863 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1864 json_object_string_add(reach_json
, "mt-name",
1865 isis_mtid2str(mtid
));
1868 format_item_ext_subtlvs(r
->subtlvs
, NULL
, json
,
1871 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1872 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1873 isis_format_id(r
->id
, 7), r
->metric
);
1874 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1875 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1876 sbuf_push(buf
, 0, "\n");
1879 format_item_ext_subtlvs(r
->subtlvs
, buf
, NULL
,
1884 static void free_item_extended_reach(struct isis_item
*i
)
1886 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1887 if (item
->subtlvs
!= NULL
)
1888 free_item_ext_subtlvs(item
->subtlvs
);
1889 XFREE(MTYPE_ISIS_TLV
, item
);
1892 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
1895 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1899 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
1900 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
1904 stream_put(s
, r
->id
, sizeof(r
->id
));
1905 stream_put3(s
, r
->metric
);
1906 len_pos
= stream_get_endp(s
);
1907 /* Real length will be adjust after adding subTLVs */
1910 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
1912 len
= stream_get_endp(s
) - len_pos
- 1;
1913 stream_putc_at(s
, len_pos
, len
);
1917 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1918 struct stream
*s
, struct sbuf
*log
,
1919 void *dest
, int indent
)
1921 struct isis_tlvs
*tlvs
= dest
;
1922 struct isis_extended_reach
*rv
= NULL
;
1924 struct isis_item_list
*items
;
1926 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1927 items
= &tlvs
->extended_reach
;
1929 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1932 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1933 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1936 sbuf_push(log
, indent
,
1937 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
1942 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1943 stream_get(rv
->id
, s
, 7);
1944 rv
->metric
= stream_get3(s
);
1945 subtlv_len
= stream_getc(s
);
1947 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1948 sbuf_push(log
, indent
,
1949 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
1950 subtlv_len
, len
- 11);
1954 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
1958 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1964 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1966 append_item(items
, (struct isis_item
*)rv
);
1970 free_item_extended_reach((struct isis_item
*)rv
);
1975 /* Functions related to TLV 128 (Old-Style) IP Reach */
1976 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1978 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1979 struct isis_oldstyle_ip_reach
*rv
=
1980 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1982 rv
->metric
= r
->metric
;
1983 rv
->prefix
= r
->prefix
;
1984 return (struct isis_item
*)rv
;
1987 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1989 struct json_object
*json
, int indent
)
1991 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1992 char prefixbuf
[PREFIX2STR_BUFFER
];
1995 struct json_object
*old_json
;
1996 old_json
= json_object_new_object();
1997 json_object_object_add(json
, "old-ip-reach-style", old_json
);
1998 json_object_string_add(old_json
, "prefix",
1999 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2000 json_object_int_add(old_json
, "metric", r
->metric
);
2002 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
2003 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2007 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
2009 XFREE(MTYPE_ISIS_TLV
, i
);
2012 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
2015 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2017 if (STREAM_WRITEABLE(s
) < 12) {
2022 stream_putc(s
, r
->metric
);
2023 stream_putc(s
, 0x80); /* delay metric - unsupported */
2024 stream_putc(s
, 0x80); /* expense metric - unsupported */
2025 stream_putc(s
, 0x80); /* error metric - unsupported */
2026 stream_put(s
, &r
->prefix
.prefix
, 4);
2028 struct in_addr mask
;
2029 masklen2ip(r
->prefix
.prefixlen
, &mask
);
2030 stream_put(s
, &mask
, sizeof(mask
));
2035 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
2036 struct stream
*s
, struct sbuf
*log
,
2037 void *dest
, int indent
)
2039 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
2043 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2048 struct isis_oldstyle_ip_reach
*rv
=
2049 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2050 rv
->metric
= stream_getc(s
);
2051 if ((rv
->metric
& 0x7f) != rv
->metric
) {
2052 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2055 stream_forward_getp(s
, 3); /* Skip other metrics */
2056 rv
->prefix
.family
= AF_INET
;
2057 stream_get(&rv
->prefix
.prefix
, s
, 4);
2059 struct in_addr mask
;
2060 stream_get(&mask
, s
, 4);
2061 rv
->prefix
.prefixlen
= ip_masklen(mask
);
2063 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2065 append_item(dest
, (struct isis_item
*)rv
);
2070 /* Functions related to TLV 129 protocols supported */
2072 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
2073 struct isis_protocols_supported
*dest
)
2075 if (!src
->protocols
|| !src
->count
)
2077 dest
->count
= src
->count
;
2078 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
2079 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
2082 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2084 struct json_object
*json
, int indent
)
2086 if (!p
|| !p
->count
|| !p
->protocols
)
2090 struct json_object
*protocol_json
;
2093 protocol_json
= json_object_new_object();
2094 json_object_object_add(json
, "protocols-supported",
2096 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2097 snprintfrr(buf
, sizeof(buf
), "%d", i
);
2098 json_object_string_add(protocol_json
, buf
,
2099 nlpid2str(p
->protocols
[i
]));
2102 sbuf_push(buf
, indent
, "Protocols Supported: ");
2103 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2104 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
2105 (i
+ 1 < p
->count
) ? ", " : "");
2107 sbuf_push(buf
, 0, "\n");
2111 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
2113 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
2116 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2119 if (!p
|| !p
->count
|| !p
->protocols
)
2122 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
2125 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
2126 stream_putc(s
, p
->count
);
2127 stream_put(s
, p
->protocols
, p
->count
);
2131 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
2132 uint8_t tlv_type
, uint8_t tlv_len
,
2133 struct stream
*s
, struct sbuf
*log
,
2134 void *dest
, int indent
)
2136 struct isis_tlvs
*tlvs
= dest
;
2138 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
2140 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
2143 if (tlvs
->protocols_supported
.protocols
) {
2146 "WARNING: protocols supported TLV present multiple times.\n");
2147 stream_forward_getp(s
, tlv_len
);
2151 tlvs
->protocols_supported
.count
= tlv_len
;
2152 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
2153 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
2155 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
, NULL
,
2160 /* Functions related to TLV 132 IPv4 Interface addresses */
2161 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
2163 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2164 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2167 return (struct isis_item
*)rv
;
2170 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
2171 struct sbuf
*buf
, struct json_object
*json
,
2174 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2175 char addrbuf
[INET_ADDRSTRLEN
];
2177 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2179 json_object_string_add(json
, "ipv4", addrbuf
);
2181 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
2185 static void free_item_ipv4_address(struct isis_item
*i
)
2187 XFREE(MTYPE_ISIS_TLV
, i
);
2190 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
2193 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2195 if (STREAM_WRITEABLE(s
) < 4) {
2200 stream_put(s
, &a
->addr
, 4);
2205 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
2206 struct stream
*s
, struct sbuf
*log
,
2207 void *dest
, int indent
)
2209 struct isis_tlvs
*tlvs
= dest
;
2211 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
2215 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2220 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2221 stream_get(&rv
->addr
, s
, 4);
2223 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2224 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
2229 /* Functions related to TLV 232 IPv6 Interface addresses */
2230 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
2232 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2233 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2236 return (struct isis_item
*)rv
;
2239 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2240 struct sbuf
*buf
, struct json_object
*json
,
2243 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2244 char addrbuf
[INET6_ADDRSTRLEN
];
2246 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2248 json_object_string_add(json
, "ipv6", addrbuf
);
2250 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
2253 static void free_item_ipv6_address(struct isis_item
*i
)
2255 XFREE(MTYPE_ISIS_TLV
, i
);
2258 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2261 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2263 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2264 *min_len
= IPV6_MAX_BYTELEN
;
2268 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2273 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
2274 struct stream
*s
, struct sbuf
*log
,
2275 void *dest
, int indent
)
2277 struct isis_tlvs
*tlvs
= dest
;
2279 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
2283 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2288 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2289 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2291 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2292 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
2297 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2298 static struct isis_item
*copy_item_global_ipv6_address(struct isis_item
*i
)
2300 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2301 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2304 return (struct isis_item
*)rv
;
2307 static void format_item_global_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2309 struct json_object
*json
,
2312 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2313 char addrbuf
[INET6_ADDRSTRLEN
];
2315 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2317 json_object_string_add(json
, "global-ipv6", addrbuf
);
2319 sbuf_push(buf
, indent
, "Global IPv6 Interface Address: %s\n",
2323 static void free_item_global_ipv6_address(struct isis_item
*i
)
2325 XFREE(MTYPE_ISIS_TLV
, i
);
2328 static int pack_item_global_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2331 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2333 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2334 *min_len
= IPV6_MAX_BYTELEN
;
2338 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2343 static int unpack_item_global_ipv6_address(uint16_t mtid
, uint8_t len
,
2344 struct stream
*s
, struct sbuf
*log
,
2345 void *dest
, int indent
)
2347 struct isis_tlvs
*tlvs
= dest
;
2349 sbuf_push(log
, indent
, "Unpack Global IPv6 Interface address...\n");
2350 if (len
< IPV6_MAX_BYTELEN
) {
2353 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2358 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2359 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2361 format_item_global_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2363 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)rv
);
2367 /* Functions related to TLV 229 MT Router information */
2368 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
2370 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2371 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2373 rv
->overload
= info
->overload
;
2374 rv
->attached
= info
->attached
;
2375 rv
->mtid
= info
->mtid
;
2376 return (struct isis_item
*)rv
;
2379 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
2381 struct json_object
*json
, int indent
)
2383 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2386 struct json_object
*mt_json
;
2387 mt_json
= json_object_new_object();
2388 json_object_object_add(json
, "mt", mt_json
);
2389 json_object_int_add(mt_json
, "mtid", info
->mtid
);
2390 json_object_string_add(mt_json
, "overload", info
->overload
?"true":"false");
2391 json_object_string_add(mt_json
, "attached", info
->attached
?"true":"false");
2393 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
2394 isis_mtid2str(info
->mtid
),
2395 info
->overload
? " Overload" : "",
2396 info
->attached
? " Attached" : "");
2399 static void free_item_mt_router_info(struct isis_item
*i
)
2401 XFREE(MTYPE_ISIS_TLV
, i
);
2404 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
2407 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2409 if (STREAM_WRITEABLE(s
) < 2) {
2414 uint16_t entry
= info
->mtid
;
2417 entry
|= ISIS_MT_OL_MASK
;
2419 entry
|= ISIS_MT_AT_MASK
;
2421 stream_putw(s
, entry
);
2426 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
2427 struct stream
*s
, struct sbuf
*log
,
2428 void *dest
, int indent
)
2430 struct isis_tlvs
*tlvs
= dest
;
2432 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
2436 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2441 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2443 uint16_t entry
= stream_getw(s
);
2444 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
2445 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
2446 rv
->mtid
= entry
& ISIS_MT_MASK
;
2448 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2450 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
2454 /* Functions related to TLV 134 TE Router ID */
2456 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
2461 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2462 memcpy(rv
, id
, sizeof(*rv
));
2466 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
2467 struct json_object
*json
, int indent
)
2472 char addrbuf
[INET_ADDRSTRLEN
];
2473 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
2475 json_object_string_add(json
, "te-router-id", addrbuf
);
2477 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
2480 static void free_tlv_te_router_id(struct in_addr
*id
)
2482 XFREE(MTYPE_ISIS_TLV
, id
);
2485 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
2490 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2493 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
2495 stream_put(s
, id
, 4);
2499 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
2500 uint8_t tlv_type
, uint8_t tlv_len
,
2501 struct stream
*s
, struct sbuf
*log
,
2502 void *dest
, int indent
)
2504 struct isis_tlvs
*tlvs
= dest
;
2506 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
2508 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2512 if (tlvs
->te_router_id
) {
2513 sbuf_push(log
, indent
,
2514 "WARNING: TE Router ID present multiple times.\n");
2515 stream_forward_getp(s
, tlv_len
);
2519 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
2520 stream_get(tlvs
->te_router_id
, s
, 4);
2521 format_tlv_te_router_id(tlvs
->te_router_id
, log
, NULL
, indent
+ 2);
2526 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
2528 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
2530 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2531 struct isis_extended_ip_reach
*rv
=
2532 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2534 rv
->metric
= r
->metric
;
2536 rv
->prefix
= r
->prefix
;
2537 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2539 return (struct isis_item
*)rv
;
2542 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2544 struct json_object
*json
, int indent
)
2546 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2547 char prefixbuf
[PREFIX2STR_BUFFER
];
2550 struct json_object
*ext_json
;
2551 ext_json
= json_object_new_object();
2552 json_object_object_add(json
, "ext-ip-reach", ext_json
);
2553 json_object_string_add(
2555 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
2556 json_object_string_add(
2558 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2559 json_object_int_add(json
, "ip-reach-metric", r
->metric
);
2560 json_object_string_add(json
, "down", r
->down
? "yes" : "");
2561 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2562 json_object_string_add(json
, "mt-name",
2563 isis_mtid2str(mtid
));
2565 struct json_object
*subtlv_json
;
2566 subtlv_json
= json_object_new_object();
2567 json_object_object_add(json
, "subtlvs", subtlv_json
);
2568 format_subtlvs(r
->subtlvs
, NULL
, subtlv_json
, 0);
2571 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
2572 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2573 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2574 r
->metric
, r
->down
? " Down" : "");
2575 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2576 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2577 sbuf_push(buf
, 0, "\n");
2580 sbuf_push(buf
, indent
, " Subtlvs:\n");
2581 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
2586 static void free_item_extended_ip_reach(struct isis_item
*i
)
2588 struct isis_extended_ip_reach
*item
=
2589 (struct isis_extended_ip_reach
*)i
;
2590 isis_free_subtlvs(item
->subtlvs
);
2591 XFREE(MTYPE_ISIS_TLV
, item
);
2594 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
2597 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2600 if (STREAM_WRITEABLE(s
) < 5) {
2604 stream_putl(s
, r
->metric
);
2606 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
2607 control
|= r
->prefix
.prefixlen
;
2608 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
2610 stream_putc(s
, control
);
2612 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2613 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2616 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2619 return pack_subtlvs(r
->subtlvs
, s
);
2623 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2624 struct stream
*s
, struct sbuf
*log
,
2625 void *dest
, int indent
)
2627 struct isis_tlvs
*tlvs
= dest
;
2628 struct isis_extended_ip_reach
*rv
= NULL
;
2630 uint8_t control
, subtlv_len
;
2631 struct isis_item_list
*items
;
2633 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2634 items
= &tlvs
->extended_ip_reach
;
2636 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2639 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2640 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2643 if (len
< consume
) {
2644 sbuf_push(log
, indent
,
2645 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2650 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2652 rv
->metric
= stream_getl(s
);
2653 control
= stream_getc(s
);
2654 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2655 rv
->prefix
.family
= AF_INET
;
2656 rv
->prefix
.prefixlen
= control
& 0x3f;
2657 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
2658 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2659 rv
->prefix
.prefixlen
);
2663 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2664 if (len
< consume
) {
2665 sbuf_push(log
, indent
,
2666 "Expected %u bytes of prefix, but only %u bytes available.\n",
2667 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2670 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2671 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2672 apply_mask_ipv4(&rv
->prefix
);
2673 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2674 sbuf_push(log
, indent
+ 2,
2675 "WARNING: Prefix had hostbits set.\n");
2676 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2679 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2681 if (len
< consume
) {
2682 sbuf_push(log
, indent
,
2683 "Expected 1 byte of subtlv len, but no more data present.\n");
2686 subtlv_len
= stream_getc(s
);
2689 sbuf_push(log
, indent
+ 2,
2690 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2692 consume
+= subtlv_len
;
2693 if (len
< consume
) {
2694 sbuf_push(log
, indent
,
2695 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2697 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2701 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2702 bool unpacked_known_tlvs
= false;
2704 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2705 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2708 if (!unpacked_known_tlvs
) {
2709 isis_free_subtlvs(rv
->subtlvs
);
2714 append_item(items
, (struct isis_item
*)rv
);
2718 free_item_extended_ip_reach((struct isis_item
*)rv
);
2722 /* Functions related to TLV 137 Dynamic Hostname */
2724 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2729 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2732 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2733 struct json_object
*json
, int indent
)
2739 json_object_string_add(json
, "hostname", hostname
);
2741 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2744 static void free_tlv_dynamic_hostname(char *hostname
)
2746 XFREE(MTYPE_ISIS_TLV
, hostname
);
2749 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2754 uint8_t name_len
= strlen(hostname
);
2756 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2759 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2760 stream_putc(s
, name_len
);
2761 stream_put(s
, hostname
, name_len
);
2765 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2766 uint8_t tlv_type
, uint8_t tlv_len
,
2767 struct stream
*s
, struct sbuf
*log
,
2768 void *dest
, int indent
)
2770 struct isis_tlvs
*tlvs
= dest
;
2772 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2774 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2778 if (tlvs
->hostname
) {
2779 sbuf_push(log
, indent
,
2780 "WARNING: Hostname present multiple times.\n");
2781 stream_forward_getp(s
, tlv_len
);
2785 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2786 stream_get(tlvs
->hostname
, s
, tlv_len
);
2787 tlvs
->hostname
[tlv_len
] = '\0';
2790 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2791 if ((unsigned char)tlvs
->hostname
[i
] > 127
2792 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2794 tlvs
->hostname
[i
] = '?';
2800 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2806 /* Functions related to TLV 140 IPv6 TE Router ID */
2808 static struct in6_addr
*copy_tlv_te_router_id_ipv6(const struct in6_addr
*id
)
2813 struct in6_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2814 memcpy(rv
, id
, sizeof(*rv
));
2818 static void format_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2820 struct json_object
*json
, int indent
)
2825 char addrbuf
[INET6_ADDRSTRLEN
];
2826 inet_ntop(AF_INET6
, id
, addrbuf
, sizeof(addrbuf
));
2828 json_object_string_add(json
, "ipv6-te-router-id", addrbuf
);
2830 sbuf_push(buf
, indent
, "IPv6 TE Router ID: %s\n", addrbuf
);
2833 static void free_tlv_te_router_id_ipv6(struct in6_addr
*id
)
2835 XFREE(MTYPE_ISIS_TLV
, id
);
2838 static int pack_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2844 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2847 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID_IPV6
);
2848 stream_putc(s
, IPV6_MAX_BYTELEN
);
2849 stream_put(s
, id
, IPV6_MAX_BYTELEN
);
2853 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context
,
2854 uint8_t tlv_type
, uint8_t tlv_len
,
2855 struct stream
*s
, struct sbuf
*log
,
2856 void *dest
, int indent
)
2858 struct isis_tlvs
*tlvs
= dest
;
2860 sbuf_push(log
, indent
, "Unpacking IPv6 TE Router ID TLV...\n");
2861 if (tlv_len
!= IPV6_MAX_BYTELEN
) {
2862 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2866 if (tlvs
->te_router_id_ipv6
) {
2869 "WARNING: IPv6 TE Router ID present multiple times.\n");
2870 stream_forward_getp(s
, tlv_len
);
2874 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, IPV6_MAX_BYTELEN
);
2875 stream_get(tlvs
->te_router_id_ipv6
, s
, IPV6_MAX_BYTELEN
);
2876 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, log
, NULL
, indent
+ 2);
2881 /* Functions related to TLV 150 Spine-Leaf-Extension */
2883 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2884 const struct isis_spine_leaf
*spine_leaf
)
2889 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2890 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2895 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2896 struct sbuf
*buf
, struct json_object
*json
,
2905 struct json_object
*spine_json
;
2906 spine_json
= json_object_new_object();
2907 json_object_object_add(json
, "spine-leaf-extension",
2909 if (spine_leaf
->has_tier
) {
2910 snprintfrr(aux_buf
, sizeof(aux_buf
), "%hhu",
2912 json_object_string_add(
2914 (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
)
2918 json_object_string_add(spine_json
, "flag-leaf",
2919 spine_leaf
->is_leaf
? "yes" : "");
2920 json_object_string_add(spine_json
, "flag-spine",
2921 spine_leaf
->is_spine
? "yes" : "");
2922 json_object_string_add(spine_json
, "flag-backup",
2923 spine_leaf
->is_backup
? "yes" : "");
2925 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2926 if (spine_leaf
->has_tier
) {
2927 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2928 sbuf_push(buf
, indent
, " Tier: undefined\n");
2930 sbuf_push(buf
, indent
, " Tier: %hhu\n",
2935 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2936 spine_leaf
->is_leaf
? " LEAF" : "",
2937 spine_leaf
->is_spine
? " SPINE" : "",
2938 spine_leaf
->is_backup
? " BACKUP" : "");
2942 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2944 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2947 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2948 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2949 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2950 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2952 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2958 uint8_t tlv_len
= 2;
2960 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2963 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2964 stream_putc(s
, tlv_len
);
2966 uint16_t spine_leaf_flags
= 0;
2968 if (spine_leaf
->has_tier
) {
2969 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2970 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2973 if (spine_leaf
->is_leaf
)
2974 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2976 if (spine_leaf
->is_spine
)
2977 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
2979 if (spine_leaf
->is_backup
)
2980 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
2982 stream_putw(s
, spine_leaf_flags
);
2987 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
2988 uint8_t tlv_type
, uint8_t tlv_len
,
2989 struct stream
*s
, struct sbuf
*log
,
2990 void *dest
, int indent
)
2992 struct isis_tlvs
*tlvs
= dest
;
2994 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
2996 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2997 stream_forward_getp(s
, tlv_len
);
3001 if (tlvs
->spine_leaf
) {
3002 sbuf_push(log
, indent
,
3003 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3004 stream_forward_getp(s
, tlv_len
);
3008 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3010 uint16_t spine_leaf_flags
= stream_getw(s
);
3012 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
3013 tlvs
->spine_leaf
->has_tier
= true;
3014 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
3017 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
3018 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
3019 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
3021 stream_forward_getp(s
, tlv_len
- 2);
3025 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3027 const char *isis_threeway_state_name(enum isis_threeway_state state
)
3030 case ISIS_THREEWAY_DOWN
:
3032 case ISIS_THREEWAY_INITIALIZING
:
3033 return "Initializing";
3034 case ISIS_THREEWAY_UP
:
3041 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
3042 const struct isis_threeway_adj
*threeway_adj
)
3047 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3048 memcpy(rv
, threeway_adj
, sizeof(*rv
));
3054 format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3055 struct sbuf
*buf
, struct json_object
*json
, int indent
)
3061 struct json_object
*three_json
;
3062 three_json
= json_object_new_object();
3063 json_object_object_add(json
, "p2p-three-way-adj", three_json
);
3064 json_object_string_add(
3065 three_json
, "state-name",
3066 isis_threeway_state_name(threeway_adj
->state
));
3067 json_object_int_add(three_json
, "state", threeway_adj
->state
);
3068 json_object_int_add(three_json
, "ext-local-circuit-id",
3069 threeway_adj
->local_circuit_id
);
3070 if (!threeway_adj
->neighbor_set
)
3072 json_object_string_add(
3073 three_json
, "neigh-system-id",
3074 isis_format_id(threeway_adj
->neighbor_id
, 6));
3075 json_object_int_add(three_json
, "neigh-ext-circuit-id",
3076 threeway_adj
->neighbor_circuit_id
);
3078 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
3079 sbuf_push(buf
, indent
, " State: %s (%d)\n",
3080 isis_threeway_state_name(threeway_adj
->state
),
3081 threeway_adj
->state
);
3082 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
3083 threeway_adj
->local_circuit_id
);
3084 if (!threeway_adj
->neighbor_set
)
3087 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
3088 isis_format_id(threeway_adj
->neighbor_id
, 6));
3089 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
3090 threeway_adj
->neighbor_circuit_id
);
3094 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
3096 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
3099 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3105 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
3107 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3110 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
3111 stream_putc(s
, tlv_len
);
3112 stream_putc(s
, threeway_adj
->state
);
3113 stream_putl(s
, threeway_adj
->local_circuit_id
);
3115 if (threeway_adj
->neighbor_set
) {
3116 stream_put(s
, threeway_adj
->neighbor_id
, 6);
3117 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
3123 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
3124 uint8_t tlv_type
, uint8_t tlv_len
,
3125 struct stream
*s
, struct sbuf
*log
,
3126 void *dest
, int indent
)
3128 struct isis_tlvs
*tlvs
= dest
;
3130 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
3131 if (tlv_len
!= 5 && tlv_len
!= 15) {
3132 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3133 stream_forward_getp(s
, tlv_len
);
3137 if (tlvs
->threeway_adj
) {
3138 sbuf_push(log
, indent
,
3139 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3140 stream_forward_getp(s
, tlv_len
);
3144 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3146 tlvs
->threeway_adj
->state
= stream_getc(s
);
3147 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
3149 if (tlv_len
== 15) {
3150 tlvs
->threeway_adj
->neighbor_set
= true;
3151 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
3152 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
3158 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3159 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
3161 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3162 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3164 rv
->metric
= r
->metric
;
3166 rv
->external
= r
->external
;
3167 rv
->prefix
= r
->prefix
;
3168 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3170 return (struct isis_item
*)rv
;
3173 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
3174 struct sbuf
*buf
, struct json_object
*json
,
3177 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3178 char prefixbuf
[PREFIX2STR_BUFFER
];
3181 struct json_object
*reach_json
;
3182 reach_json
= json_object_new_object();
3183 json_object_object_add(json
, "ipv6-reach", reach_json
);
3184 json_object_string_add(reach_json
, "mt-id",
3185 (mtid
== ISIS_MT_IPV4_UNICAST
) ? ""
3187 json_object_string_add(
3188 reach_json
, "prefix",
3189 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3190 json_object_int_add(reach_json
, "metric", r
->metric
);
3191 json_object_string_add(reach_json
, "down",
3192 r
->down
? "yes" : "");
3193 json_object_string_add(reach_json
, "external",
3194 r
->external
? "yes" : "");
3195 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3196 json_object_string_add(reach_json
, "mt-name",
3197 isis_mtid2str(mtid
));
3199 struct json_object
*subtlvs_json
;
3200 subtlvs_json
= json_object_new_object();
3201 json_object_object_add(json
, "subtlvs", subtlvs_json
);
3202 format_subtlvs(r
->subtlvs
, NULL
, subtlvs_json
, 0);
3205 sbuf_push(buf
, indent
,
3206 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3207 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
3208 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3209 r
->metric
, r
->down
? " Down" : "",
3210 r
->external
? " External" : "");
3211 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3212 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3213 sbuf_push(buf
, 0, "\n");
3216 sbuf_push(buf
, indent
, " Subtlvs:\n");
3217 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3222 static void free_item_ipv6_reach(struct isis_item
*i
)
3224 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
3226 isis_free_subtlvs(item
->subtlvs
);
3227 XFREE(MTYPE_ISIS_TLV
, item
);
3230 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
3233 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3236 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3237 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3240 stream_putl(s
, r
->metric
);
3242 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
3243 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
3244 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
3246 stream_putc(s
, control
);
3247 stream_putc(s
, r
->prefix
.prefixlen
);
3249 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
3252 return pack_subtlvs(r
->subtlvs
, s
);
3257 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3258 struct sbuf
*log
, void *dest
, int indent
)
3260 struct isis_tlvs
*tlvs
= dest
;
3261 struct isis_ipv6_reach
*rv
= NULL
;
3263 uint8_t control
, subtlv_len
;
3264 struct isis_item_list
*items
;
3266 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3267 items
= &tlvs
->ipv6_reach
;
3269 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3272 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
3273 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
3275 if (len
< consume
) {
3276 sbuf_push(log
, indent
,
3277 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3282 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3284 rv
->metric
= stream_getl(s
);
3285 control
= stream_getc(s
);
3286 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
3287 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
3289 rv
->prefix
.family
= AF_INET6
;
3290 rv
->prefix
.prefixlen
= stream_getc(s
);
3291 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
3292 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
3293 rv
->prefix
.prefixlen
);
3297 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3298 if (len
< consume
) {
3299 sbuf_push(log
, indent
,
3300 "Expected %u bytes of prefix, but only %u bytes available.\n",
3301 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
3304 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3305 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
3307 apply_mask_ipv6(&rv
->prefix
);
3308 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
3309 sbuf_push(log
, indent
+ 2,
3310 "WARNING: Prefix had hostbits set.\n");
3311 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3313 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
3315 if (len
< consume
) {
3316 sbuf_push(log
, indent
,
3317 "Expected 1 byte of subtlv len, but no more data persent.\n");
3320 subtlv_len
= stream_getc(s
);
3323 sbuf_push(log
, indent
+ 2,
3324 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3326 consume
+= subtlv_len
;
3327 if (len
< consume
) {
3328 sbuf_push(log
, indent
,
3329 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3331 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3335 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3336 bool unpacked_known_tlvs
= false;
3338 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
3339 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3342 if (!unpacked_known_tlvs
) {
3343 isis_free_subtlvs(rv
->subtlvs
);
3348 append_item(items
, (struct isis_item
*)rv
);
3352 free_item_ipv6_reach((struct isis_item
*)rv
);
3356 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3357 static struct isis_router_cap
*copy_tlv_router_cap(
3358 const struct isis_router_cap
*router_cap
)
3360 struct isis_router_cap
*rv
;
3365 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3367 memcpy(rv
, router_cap
, sizeof(*rv
));
3372 static void format_tlv_router_cap_json(const struct isis_router_cap
*router_cap
,
3373 struct json_object
*json
)
3375 char addrbuf
[INET_ADDRSTRLEN
];
3380 /* Router ID and Flags */
3381 struct json_object
*cap_json
;
3382 cap_json
= json_object_new_object();
3383 json_object_object_add(json
, "router-capability", cap_json
);
3384 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3385 json_object_string_add(cap_json
, "id", addrbuf
);
3386 json_object_string_add(
3388 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? "1" : "0");
3389 json_object_string_add(
3391 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? "1" : "0");
3393 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3394 if (router_cap
->srgb
.range_size
!= 0) {
3395 struct json_object
*gb_json
;
3396 gb_json
= json_object_new_object();
3397 json_object_object_add(json
, "segment-routing-gb", gb_json
);
3398 json_object_string_add(gb_json
, "ipv4",
3399 IS_SR_IPV4(&router_cap
->srgb
) ? "1"
3401 json_object_string_add(gb_json
, "ipv6",
3402 IS_SR_IPV6(&router_cap
->srgb
) ? "1"
3404 json_object_int_add(gb_json
, "global-block-base",
3405 router_cap
->srgb
.lower_bound
);
3406 json_object_int_add(gb_json
, "global-block-range",
3407 router_cap
->srgb
.range_size
);
3410 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3411 if (router_cap
->srlb
.range_size
!= 0) {
3412 struct json_object
*lb_json
;
3413 lb_json
= json_object_new_object();
3414 json_object_object_add(json
, "segment-routing-lb", lb_json
);
3415 json_object_int_add(lb_json
, "global-block-base",
3416 router_cap
->srlb
.lower_bound
);
3417 json_object_int_add(lb_json
, "global-block-range",
3418 router_cap
->srlb
.range_size
);
3421 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3422 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3424 struct json_object
*alg_json
;
3425 alg_json
= json_object_new_object();
3426 json_object_object_add(json
, "segment-routing-algorithm",
3428 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3429 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
) {
3430 snprintfrr(buf
, sizeof(buf
), "%d", i
);
3431 json_object_string_add(alg_json
, buf
,
3432 router_cap
->algo
[i
] == 0
3438 /* Segment Routing Node MSD as per RFC8491 section #2 */
3439 if (router_cap
->msd
!= 0)
3440 json_object_int_add(json
, "msd", router_cap
->msd
);
3443 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3444 struct sbuf
*buf
, int indent
)
3446 char addrbuf
[INET_ADDRSTRLEN
];
3451 /* Router ID and Flags */
3452 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3453 sbuf_push(buf
, indent
, "Router Capability:");
3454 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
3455 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
3456 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
3458 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3459 if (router_cap
->srgb
.range_size
!= 0)
3462 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
3463 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
3464 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
3465 router_cap
->srgb
.lower_bound
,
3466 router_cap
->srgb
.range_size
);
3468 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3469 if (router_cap
->srlb
.range_size
!= 0)
3470 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
3471 router_cap
->srlb
.lower_bound
,
3472 router_cap
->srlb
.range_size
);
3474 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3475 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3476 sbuf_push(buf
, indent
, " SR Algorithm:\n");
3477 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3478 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
3479 sbuf_push(buf
, indent
, " %u: %s\n", i
,
3480 router_cap
->algo
[i
] == 0
3485 /* Segment Routing Node MSD as per RFC8491 section #2 */
3486 if (router_cap
->msd
!= 0)
3487 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
3491 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
3493 XFREE(MTYPE_ISIS_TLV
, router_cap
);
3496 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3499 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
3506 /* Compute Maximum TLV size */
3507 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
3508 + ISIS_SUBTLV_HDR_SIZE
3509 + ISIS_SUBTLV_ALGORITHM_SIZE
3510 + ISIS_SUBTLV_NODE_MSD_SIZE
;
3512 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
3515 /* Add Router Capability TLV 242 with Router ID and Flags */
3516 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
3517 /* Real length will be adjusted later */
3518 len_pos
= stream_get_endp(s
);
3519 stream_putc(s
, tlv_len
);
3520 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
3521 stream_putc(s
, router_cap
->flags
);
3523 /* Add SRGB if set as per RFC8667 section #3.1 */
3524 if ((router_cap
->srgb
.range_size
!= 0)
3525 && (router_cap
->srgb
.lower_bound
!= 0)) {
3526 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
3527 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3528 stream_putc(s
, router_cap
->srgb
.flags
);
3529 stream_put3(s
, router_cap
->srgb
.range_size
);
3530 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3531 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3532 stream_put3(s
, router_cap
->srgb
.lower_bound
);
3534 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
3535 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
3536 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
3539 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
3540 stream_putc(s
, nb_algo
);
3541 for (int i
= 0; i
< nb_algo
; i
++)
3542 stream_putc(s
, router_cap
->algo
[i
]);
3545 /* Local Block if defined as per RFC8667 section #3.3 */
3546 if ((router_cap
->srlb
.range_size
!= 0)
3547 && (router_cap
->srlb
.lower_bound
!= 0)) {
3548 stream_putc(s
, ISIS_SUBTLV_SRLB
);
3549 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3550 /* No Flags are defined for SRLB */
3552 stream_put3(s
, router_cap
->srlb
.range_size
);
3553 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3554 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3555 stream_put3(s
, router_cap
->srlb
.lower_bound
);
3558 /* And finish with MSD if set as per RFC8491 section #2 */
3559 if (router_cap
->msd
!= 0) {
3560 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
3561 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
3562 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
3563 stream_putc(s
, router_cap
->msd
);
3567 /* Adjust TLV length which depends on subTLVs presence */
3568 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
3569 stream_putc_at(s
, len_pos
, tlv_len
);
3574 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
3575 uint8_t tlv_type
, uint8_t tlv_len
,
3576 struct stream
*s
, struct sbuf
*log
,
3577 void *dest
, int indent
)
3579 struct isis_tlvs
*tlvs
= dest
;
3580 struct isis_router_cap
*rcap
;
3586 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
3587 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
3588 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3589 stream_forward_getp(s
, tlv_len
);
3593 if (tlvs
->router_cap
) {
3594 sbuf_push(log
, indent
,
3595 "WARNING: Router Capability TLV present multiple times.\n");
3596 stream_forward_getp(s
, tlv_len
);
3600 /* Allocate router cap structure and initialize SR Algorithms */
3601 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
3602 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3603 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
3605 /* Get Router ID and Flags */
3606 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
3607 rcap
->flags
= stream_getc(s
);
3609 /* Parse remaining part of the TLV if present */
3610 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
3611 while (subtlv_len
> 2) {
3614 type
= stream_getc(s
);
3615 length
= stream_getc(s
);
3617 if (length
> STREAM_READABLE(s
) || length
> subtlv_len
- 2) {
3620 "WARNING: Router Capability subTLV length too large compared to expected size\n");
3621 stream_forward_getp(s
, STREAM_READABLE(s
));
3627 case ISIS_SUBTLV_SID_LABEL_RANGE
:
3628 /* Check that SRGB is correctly formated */
3629 if (length
< SUBTLV_RANGE_LABEL_SIZE
3630 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3631 stream_forward_getp(s
, length
);
3634 /* Only one SRGB is supported. Skip subsequent one */
3635 if (rcap
->srgb
.range_size
!= 0) {
3636 stream_forward_getp(s
, length
);
3639 rcap
->srgb
.flags
= stream_getc(s
);
3640 rcap
->srgb
.range_size
= stream_get3(s
);
3641 /* Skip Type and get Length of SID Label */
3643 size
= stream_getc(s
);
3645 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3646 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3647 stream_forward_getp(s
, length
- 6);
3651 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3652 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3653 stream_forward_getp(s
, length
- 6);
3657 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3658 rcap
->srgb
.lower_bound
= stream_get3(s
);
3659 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3660 rcap
->srgb
.lower_bound
= stream_getl(s
);
3662 stream_forward_getp(s
, length
- 6);
3666 /* SRGB sanity checks. */
3667 if (rcap
->srgb
.range_size
== 0
3668 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3669 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
3670 > MPLS_LABEL_UNRESERVED_MAX
)) {
3671 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
3672 rcap
->srgb
.lower_bound
= 0;
3673 rcap
->srgb
.range_size
= 0;
3675 /* Only one range is supported. Skip subsequent one */
3676 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3678 stream_forward_getp(s
, size
);
3681 case ISIS_SUBTLV_ALGORITHM
:
3684 /* Only 2 algorithms are supported: SPF & Strict SPF */
3685 stream_get(&rcap
->algo
, s
,
3686 length
> SR_ALGORITHM_COUNT
3687 ? SR_ALGORITHM_COUNT
3689 if (length
> SR_ALGORITHM_COUNT
)
3690 stream_forward_getp(
3691 s
, length
- SR_ALGORITHM_COUNT
);
3693 case ISIS_SUBTLV_SRLB
:
3694 /* Check that SRLB is correctly formated */
3695 if (length
< SUBTLV_RANGE_LABEL_SIZE
3696 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3697 stream_forward_getp(s
, length
);
3700 /* RFC 8667 section #3.3: Only one SRLB is authorized */
3701 if (rcap
->srlb
.range_size
!= 0) {
3702 stream_forward_getp(s
, length
);
3705 /* Ignore Flags which are not defined */
3707 rcap
->srlb
.range_size
= stream_get3(s
);
3708 /* Skip Type and get Length of SID Label */
3710 size
= stream_getc(s
);
3712 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3713 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3714 stream_forward_getp(s
, length
- 6);
3718 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3719 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3720 stream_forward_getp(s
, length
- 6);
3724 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3725 rcap
->srlb
.lower_bound
= stream_get3(s
);
3726 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3727 rcap
->srlb
.lower_bound
= stream_getl(s
);
3729 stream_forward_getp(s
, length
- 6);
3733 /* SRLB sanity checks. */
3734 if (rcap
->srlb
.range_size
== 0
3735 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3736 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
3737 > MPLS_LABEL_UNRESERVED_MAX
)) {
3738 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
3739 rcap
->srlb
.lower_bound
= 0;
3740 rcap
->srlb
.range_size
= 0;
3742 /* Only one range is supported. Skip subsequent one */
3743 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3745 stream_forward_getp(s
, size
);
3748 case ISIS_SUBTLV_NODE_MSD
:
3749 /* Check that MSD is correctly formated */
3750 if (length
< MSD_TLV_SIZE
) {
3751 stream_forward_getp(s
, length
);
3754 msd_type
= stream_getc(s
);
3755 rcap
->msd
= stream_getc(s
);
3756 /* Only BMI-MSD type has been defined in RFC 8491 */
3757 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
3759 /* Only one MSD is standardized. Skip others */
3760 if (length
> MSD_TLV_SIZE
)
3761 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
3764 stream_forward_getp(s
, length
);
3767 subtlv_len
= subtlv_len
- length
- 2;
3769 tlvs
->router_cap
= rcap
;
3773 /* Functions related to TLV 10 Authentication */
3774 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
3776 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3777 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3779 rv
->type
= auth
->type
;
3780 rv
->length
= auth
->length
;
3781 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
3782 return (struct isis_item
*)rv
;
3785 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
3786 struct sbuf
*buf
, struct json_object
*json
,
3789 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3793 json_object_string_add(json
, "test-auth", "ok");
3795 sbuf_push(buf
, indent
, "Authentication:\n");
3796 switch (auth
->type
) {
3797 case ISIS_PASSWD_TYPE_CLEARTXT
:
3798 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
3800 json_object_string_add(json
, "auth-pass", obuf
);
3802 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
3804 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3805 for (unsigned int j
= 0; j
< 16; j
++) {
3806 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
, "%02hhx",
3810 json_object_string_add(json
, "auth-hmac-md5", obuf
);
3812 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
3816 json_object_int_add(json
, "auth-unknown", auth
->type
);
3818 sbuf_push(buf
, indent
, " Unknown (%hhu)\n",
3824 static void free_item_auth(struct isis_item
*i
)
3826 XFREE(MTYPE_ISIS_TLV
, i
);
3829 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
3832 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3834 if (STREAM_WRITEABLE(s
) < 1) {
3838 stream_putc(s
, auth
->type
);
3840 switch (auth
->type
) {
3841 case ISIS_PASSWD_TYPE_CLEARTXT
:
3842 if (STREAM_WRITEABLE(s
) < auth
->length
) {
3843 *min_len
= 1 + auth
->length
;
3846 stream_put(s
, auth
->passwd
, auth
->length
);
3848 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3849 if (STREAM_WRITEABLE(s
) < 16) {
3853 auth
->offset
= stream_get_endp(s
);
3854 stream_put(s
, NULL
, 16);
3863 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3864 struct sbuf
*log
, void *dest
, int indent
)
3866 struct isis_tlvs
*tlvs
= dest
;
3868 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
3872 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
3877 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3879 rv
->type
= stream_getc(s
);
3880 rv
->length
= len
- 1;
3882 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
3885 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
3887 XFREE(MTYPE_ISIS_TLV
, rv
);
3891 rv
->offset
= stream_get_getp(s
);
3892 stream_get(rv
->value
, s
, rv
->length
);
3893 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3894 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
3898 /* Functions related to TLV 13 Purge Originator */
3900 static struct isis_purge_originator
*copy_tlv_purge_originator(
3901 struct isis_purge_originator
*poi
)
3906 struct isis_purge_originator
*rv
;
3908 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3909 rv
->sender_set
= poi
->sender_set
;
3910 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3911 if (poi
->sender_set
)
3912 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
3916 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
3918 struct json_object
*json
, int indent
)
3924 struct json_object
*purge_json
;
3925 purge_json
= json_object_new_object();
3926 json_object_object_add(json
, "purge_originator", purge_json
);
3928 json_object_string_add(
3930 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3931 if (poi
->sender_set
) {
3932 json_object_string_add(
3933 purge_json
, "rec-from",
3934 isis_format_id(poi
->sender
,
3935 sizeof(poi
->sender
)));
3938 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
3940 buf
, indent
, " Generator: %s\n",
3941 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3942 if (poi
->sender_set
) {
3943 sbuf_push(buf
, indent
, " Received-From: %s\n",
3944 isis_format_id(poi
->sender
,
3945 sizeof(poi
->sender
)));
3950 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
3952 XFREE(MTYPE_ISIS_TLV
, poi
);
3955 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
3961 uint8_t data_len
= 1 + sizeof(poi
->generator
);
3963 if (poi
->sender_set
)
3964 data_len
+= sizeof(poi
->sender
);
3966 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
3969 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
3970 stream_putc(s
, data_len
);
3971 stream_putc(s
, poi
->sender_set
? 2 : 1);
3972 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
3973 if (poi
->sender_set
)
3974 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
3978 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
3979 uint8_t tlv_type
, uint8_t tlv_len
,
3980 struct stream
*s
, struct sbuf
*log
,
3981 void *dest
, int indent
)
3983 struct isis_tlvs
*tlvs
= dest
;
3984 struct isis_purge_originator poi
= {};
3986 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
3988 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
3992 uint8_t number_of_ids
= stream_getc(s
);
3994 if (number_of_ids
== 1) {
3995 poi
.sender_set
= false;
3996 } else if (number_of_ids
== 2) {
3997 poi
.sender_set
= true;
3999 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
4003 if (tlv_len
!= 1 + 6 * number_of_ids
) {
4004 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
4008 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
4010 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
4012 if (tlvs
->purge_originator
) {
4013 sbuf_push(log
, indent
,
4014 "WARNING: Purge originator present multiple times, ignoring.\n");
4018 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
4023 /* Functions relating to item TLVs */
4025 static void init_item_list(struct isis_item_list
*items
)
4028 items
->tail
= &items
->head
;
4032 static struct isis_item
*copy_item(enum isis_tlv_context context
,
4033 enum isis_tlv_type type
,
4034 struct isis_item
*item
)
4036 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4038 if (ops
&& ops
->copy_item
)
4039 return ops
->copy_item(item
);
4041 assert(!"Unknown item tlv type!");
4045 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4046 struct isis_item_list
*src
, struct isis_item_list
*dest
)
4048 struct isis_item
*item
;
4050 init_item_list(dest
);
4052 for (item
= src
->head
; item
; item
= item
->next
) {
4053 append_item(dest
, copy_item(context
, type
, item
));
4057 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
4058 enum isis_tlv_type type
, struct isis_item
*i
,
4059 struct sbuf
*buf
, struct json_object
*json
, int indent
)
4061 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4063 if (ops
&& ops
->format_item
) {
4064 ops
->format_item(mtid
, i
, buf
, json
, indent
);
4068 assert(!"Unknown item tlv type!");
4071 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
4072 enum isis_tlv_type type
, struct isis_item_list
*items
,
4073 struct sbuf
*buf
, struct json_object
*json
,
4076 struct isis_item
*i
;
4078 for (i
= items
->head
; i
; i
= i
->next
)
4079 format_item(mtid
, context
, type
, i
, buf
, json
, indent
);
4082 static void free_item(enum isis_tlv_context tlv_context
,
4083 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
4085 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
4087 if (ops
&& ops
->free_item
) {
4088 ops
->free_item(item
);
4092 assert(!"Unknown item tlv type!");
4095 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4096 struct isis_item_list
*items
)
4098 struct isis_item
*item
, *next_item
;
4100 for (item
= items
->head
; item
; item
= next_item
) {
4101 next_item
= item
->next
;
4102 free_item(context
, type
, item
);
4106 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
4107 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
4108 struct isis_tlvs
**fragment_tlvs
,
4109 const struct pack_order_entry
*pe
, uint16_t mtid
)
4111 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4113 if (ops
&& ops
->pack_item
) {
4114 return ops
->pack_item(i
, s
, min_len
);
4117 assert(!"Unknown item tlv type!");
4121 static void add_item_to_fragment(struct isis_item
*i
,
4122 const struct pack_order_entry
*pe
,
4123 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
4125 struct isis_item_list
*l
;
4127 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4128 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4130 struct isis_mt_item_list
*m
;
4131 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4132 l
= isis_get_mt_items(m
, mtid
);
4135 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
4138 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
4139 enum isis_tlv_type type
, struct isis_item_list
*items
,
4140 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
4141 const struct pack_order_entry
*pe
,
4142 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4143 struct list
*new_fragment_arg
)
4145 size_t len_pos
, last_len
, len
;
4146 struct isis_item
*item
= NULL
;
4154 if (STREAM_WRITEABLE(s
) < 2)
4157 stream_putc(s
, type
);
4158 len_pos
= stream_get_endp(s
);
4159 stream_putc(s
, 0); /* Put 0 as length for now */
4161 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
4162 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
4163 if (STREAM_WRITEABLE(s
) < 2)
4165 stream_putw(s
, mtid
);
4168 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
4169 if (STREAM_WRITEABLE(s
) < 1)
4171 stream_putc(s
, 0); /* Virtual flag is set to 0 */
4175 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
4176 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
4181 len
= stream_get_endp(s
) - len_pos
- 1;
4183 /* Multiple auths don't go into one TLV, so always break */
4184 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
4189 /* Multiple prefix-sids don't go into one TLV, so always break */
4190 if (type
== ISIS_SUBTLV_PREFIX_SID
4191 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
4192 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
4198 if (!last_len
) /* strange, not a single item fit */
4200 /* drop last tlv, otherwise, its too long */
4201 stream_set_endp(s
, len_pos
+ 1 + last_len
);
4207 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
4212 stream_putc_at(s
, len_pos
, len
);
4221 if (STREAM_WRITEABLE(s
) < min_len
)
4223 *fragment_tlvs
= new_fragment(new_fragment_arg
);
4226 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
4228 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
4231 dest
->tail
= &(*dest
->tail
)->next
;
4235 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
4237 struct isis_item
*item
, *prev
= NULL
, *next
;
4240 if ((dest
== NULL
) || (del
== NULL
))
4244 * TODO: delete is tricky because "dest" is a singly linked list.
4245 * We need to switch a doubly linked list.
4247 for (item
= dest
->head
; item
; item
= next
) {
4248 if (item
->next
== del
) {
4255 prev
->next
= del
->next
;
4256 if (dest
->head
== del
)
4257 dest
->head
= del
->next
;
4258 if ((struct isis_item
*)dest
->tail
== del
) {
4261 dest
->tail
= &(*dest
->tail
)->next
;
4263 dest
->tail
= &dest
->head
;
4268 static struct isis_item
*last_item(struct isis_item_list
*list
)
4270 return container_of(list
->tail
, struct isis_item
, next
);
4273 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
4274 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
4275 struct sbuf
*log
, void *dest
, int indent
)
4277 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
4279 if (ops
&& ops
->unpack_item
)
4280 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
4282 assert(!"Unknown item tlv type!");
4283 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
4287 static int unpack_tlv_with_items(enum isis_tlv_context context
,
4288 uint8_t tlv_type
, uint8_t tlv_len
,
4289 struct stream
*s
, struct sbuf
*log
, void *dest
,
4297 tlv_start
= stream_get_getp(s
);
4300 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
4302 sbuf_push(log
, indent
,
4303 "TLV is too short to contain MTID\n");
4306 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
4308 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
4309 isis_mtid2str(mtid
));
4311 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
4312 mtid
= ISIS_MT_IPV4_UNICAST
;
4315 if (context
== ISIS_CONTEXT_LSP
4316 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
4317 if (tlv_len
- tlv_pos
< 1) {
4318 sbuf_push(log
, indent
,
4319 "TLV is too short for old style reach\n");
4322 stream_forward_getp(s
, 1);
4326 if (context
== ISIS_CONTEXT_LSP
4327 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
4328 struct isis_tlvs
*tlvs
= dest
;
4329 dest
= &tlvs
->oldstyle_ip_reach
;
4330 } else if (context
== ISIS_CONTEXT_LSP
4331 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
4332 struct isis_tlvs
*tlvs
= dest
;
4333 dest
= &tlvs
->oldstyle_ip_reach_ext
;
4336 if (context
== ISIS_CONTEXT_LSP
4337 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
4338 struct isis_tlvs
*tlvs
= dest
;
4339 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
4342 while (tlv_pos
< (size_t)tlv_len
) {
4343 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
4344 log
, dest
, indent
+ 2);
4348 tlv_pos
= stream_get_getp(s
) - tlv_start
;
4354 /* Functions to manipulate mt_item_lists */
4356 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
4357 const struct isis_item_list
*b
)
4359 if (a
->mtid
< b
->mtid
)
4361 if (a
->mtid
> b
->mtid
)
4366 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4367 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4369 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
4372 struct isis_item_list
*rv
;
4374 rv
= isis_lookup_mt_items(m
, mtid
);
4376 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
4379 RB_INSERT(isis_mt_item_list
, m
, rv
);
4385 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
4388 struct isis_item_list key
= {.mtid
= mtid
};
4390 return RB_FIND(isis_mt_item_list
, m
, &key
);
4393 static void free_mt_items(enum isis_tlv_context context
,
4394 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
4396 struct isis_item_list
*n
, *nnext
;
4398 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
4399 free_items(context
, type
, n
);
4400 RB_REMOVE(isis_mt_item_list
, m
, n
);
4401 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
4405 static void format_mt_items(enum isis_tlv_context context
,
4406 enum isis_tlv_type type
,
4407 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
4408 struct json_object
*json
, int indent
)
4410 struct isis_item_list
*n
;
4412 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4413 format_items_(n
->mtid
, context
, type
, n
, buf
, json
, indent
);
4417 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4418 struct isis_mt_item_list
*m
, struct stream
*s
,
4419 struct isis_tlvs
**fragment_tlvs
,
4420 const struct pack_order_entry
*pe
,
4421 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4422 struct list
*new_fragment_arg
)
4424 struct isis_item_list
*n
;
4426 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4429 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
4430 pe
, new_fragment
, new_fragment_arg
);
4438 static void copy_mt_items(enum isis_tlv_context context
,
4439 enum isis_tlv_type type
,
4440 struct isis_mt_item_list
*src
,
4441 struct isis_mt_item_list
*dest
)
4443 struct isis_item_list
*n
;
4445 RB_INIT(isis_mt_item_list
, dest
);
4447 RB_FOREACH (n
, isis_mt_item_list
, src
) {
4448 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
4452 /* Functions related to tlvs in general */
4454 struct isis_tlvs
*isis_alloc_tlvs(void)
4456 struct isis_tlvs
*result
;
4458 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
4460 init_item_list(&result
->isis_auth
);
4461 init_item_list(&result
->area_addresses
);
4462 init_item_list(&result
->mt_router_info
);
4463 init_item_list(&result
->oldstyle_reach
);
4464 init_item_list(&result
->lan_neighbor
);
4465 init_item_list(&result
->lsp_entries
);
4466 init_item_list(&result
->extended_reach
);
4467 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
4468 init_item_list(&result
->oldstyle_ip_reach
);
4469 init_item_list(&result
->oldstyle_ip_reach_ext
);
4470 init_item_list(&result
->ipv4_address
);
4471 init_item_list(&result
->ipv6_address
);
4472 init_item_list(&result
->global_ipv6_address
);
4473 init_item_list(&result
->extended_ip_reach
);
4474 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
4475 init_item_list(&result
->ipv6_reach
);
4476 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
4481 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
4483 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4485 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
4488 rv
->purge_originator
=
4489 copy_tlv_purge_originator(tlvs
->purge_originator
);
4491 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4492 &tlvs
->area_addresses
, &rv
->area_addresses
);
4494 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4495 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
4497 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
4499 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4500 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
4502 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4503 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
4505 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4508 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4509 &tlvs
->extended_reach
, &rv
->extended_reach
);
4511 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4514 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4515 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
4517 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
4518 &rv
->protocols_supported
);
4520 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4521 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
4523 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
4526 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
4529 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4530 &tlvs
->global_ipv6_address
, &rv
->global_ipv6_address
);
4532 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
4534 rv
->te_router_id_ipv6
=
4535 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4537 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4538 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
4540 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4541 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
4543 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
4545 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4548 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4549 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
4551 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4553 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
4555 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4560 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, struct json_object
*json
, int indent
)
4562 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, json
,
4565 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
4568 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, json
, indent
);
4570 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4571 &tlvs
->area_addresses
, buf
, json
, indent
);
4573 if (tlvs
->mt_router_info_empty
) {
4575 json_object_string_add(json
, "mt-router-info", "none");
4577 sbuf_push(buf
, indent
, "MT Router Info: None\n");
4579 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4580 &tlvs
->mt_router_info
, buf
, json
, indent
);
4583 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4584 &tlvs
->oldstyle_reach
, buf
, json
, indent
);
4586 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4587 &tlvs
->lan_neighbor
, buf
, json
, indent
);
4589 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4592 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, json
, indent
);
4593 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, json
, indent
);
4594 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, buf
, json
,
4597 format_tlv_router_cap_json(tlvs
->router_cap
, json
);
4599 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
4601 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4602 &tlvs
->extended_reach
, buf
, json
, indent
);
4604 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4607 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4608 &tlvs
->oldstyle_ip_reach
, buf
, json
, indent
);
4610 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4611 &tlvs
->oldstyle_ip_reach_ext
, buf
, json
, indent
);
4613 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4614 &tlvs
->ipv4_address
, buf
, json
, indent
);
4616 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4617 &tlvs
->ipv6_address
, buf
, json
, indent
);
4619 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4620 &tlvs
->global_ipv6_address
, buf
, json
, indent
);
4622 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4623 &tlvs
->extended_ip_reach
, buf
, json
, indent
);
4625 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4626 &tlvs
->mt_ip_reach
, buf
, json
, indent
);
4628 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4631 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4632 &tlvs
->mt_ipv6_reach
, buf
, json
, indent
);
4634 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, json
, indent
);
4636 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, json
, indent
);
4639 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
, struct json_object
*json
)
4642 format_tlvs(tlvs
, NULL
, json
, 0);
4645 static struct sbuf buf
;
4647 if (!sbuf_buf(&buf
))
4648 sbuf_init(&buf
, NULL
, 0);
4651 format_tlvs(tlvs
, &buf
, NULL
, 0);
4652 return sbuf_buf(&buf
);
4656 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
4661 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4662 free_tlv_purge_originator(tlvs
->purge_originator
);
4663 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4664 &tlvs
->area_addresses
);
4665 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4666 &tlvs
->mt_router_info
);
4667 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4668 &tlvs
->oldstyle_reach
);
4669 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4670 &tlvs
->lan_neighbor
);
4671 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
4672 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4673 &tlvs
->extended_reach
);
4674 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
4675 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4676 &tlvs
->oldstyle_ip_reach
);
4677 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
4678 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4679 &tlvs
->oldstyle_ip_reach_ext
);
4680 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4681 &tlvs
->ipv4_address
);
4682 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4683 &tlvs
->ipv6_address
);
4684 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4685 &tlvs
->global_ipv6_address
);
4686 free_tlv_te_router_id(tlvs
->te_router_id
);
4687 free_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4688 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4689 &tlvs
->extended_ip_reach
);
4690 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4691 &tlvs
->mt_ip_reach
);
4692 free_tlv_dynamic_hostname(tlvs
->hostname
);
4693 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
4694 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4695 &tlvs
->mt_ipv6_reach
);
4696 free_tlv_threeway_adj(tlvs
->threeway_adj
);
4697 free_tlv_router_cap(tlvs
->router_cap
);
4698 free_tlv_spine_leaf(tlvs
->spine_leaf
);
4700 XFREE(MTYPE_ISIS_TLV
, tlvs
);
4703 static void add_padding(struct stream
*s
)
4705 while (STREAM_WRITEABLE(s
)) {
4706 if (STREAM_WRITEABLE(s
) == 1)
4708 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
4710 if (padding_len
> 255) {
4711 if (padding_len
== 256)
4717 stream_putc(s
, ISIS_TLV_PADDING
);
4718 stream_putc(s
, padding_len
);
4719 stream_put(s
, NULL
, padding_len
);
4723 #define LSP_REM_LIFETIME_OFF 10
4724 #define LSP_CHECKSUM_OFF 24
4725 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
4726 uint16_t *rem_lifetime
)
4728 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
4729 sizeof(*rem_lifetime
));
4730 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
4731 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
4732 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
4735 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
4736 uint16_t rem_lifetime
)
4738 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
4739 sizeof(rem_lifetime
));
4740 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
4743 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
4747 uint16_t checksum
, rem_lifetime
;
4750 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
4752 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
4753 #ifdef CRYPTO_OPENSSL
4754 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
4755 auth
->plength
, STREAM_DATA(s
),
4756 stream_get_endp(s
), NULL
, NULL
);
4758 memcpy(digest
, result
, 16);
4759 #elif CRYPTO_INTERNAL
4760 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
4761 auth
->plength
, digest
);
4763 memcpy(auth
->value
, digest
, 16);
4764 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
4767 restore_auth_md5(s
, checksum
, rem_lifetime
);
4770 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
4772 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4774 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
4775 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
4776 update_auth_hmac_md5(auth
, s
, is_lsp
);
4780 static int handle_pack_entry(const struct pack_order_entry
*pe
,
4781 struct isis_tlvs
*tlvs
, struct stream
*stream
,
4782 struct isis_tlvs
**fragment_tlvs
,
4783 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4784 struct list
*new_fragment_arg
)
4788 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4789 struct isis_item_list
*l
;
4790 l
= (struct isis_item_list
*)(((char *)tlvs
)
4791 + pe
->what_to_pack
);
4792 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
4793 pe
, new_fragment
, new_fragment_arg
);
4795 struct isis_mt_item_list
*l
;
4796 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
4797 + pe
->what_to_pack
);
4798 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
4799 fragment_tlvs
, pe
, new_fragment
,
4806 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4807 struct isis_tlvs
*fragment_tlvs
,
4808 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4809 struct list
*new_fragment_arg
)
4813 /* When fragmenting, don't add auth as it's already accounted for in the
4814 * size we are given. */
4815 if (!fragment_tlvs
) {
4816 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
4817 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
4823 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
4826 if (fragment_tlvs
) {
4827 fragment_tlvs
->purge_originator
=
4828 copy_tlv_purge_originator(tlvs
->purge_originator
);
4831 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
4834 if (fragment_tlvs
) {
4835 copy_tlv_protocols_supported(
4836 &tlvs
->protocols_supported
,
4837 &fragment_tlvs
->protocols_supported
);
4840 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4841 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
4844 if (fragment_tlvs
) {
4845 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4846 &tlvs
->area_addresses
,
4847 &fragment_tlvs
->area_addresses
);
4851 if (tlvs
->mt_router_info_empty
) {
4852 if (STREAM_WRITEABLE(stream
) < 2)
4854 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
4855 stream_putc(stream
, 0);
4857 fragment_tlvs
->mt_router_info_empty
= true;
4859 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4860 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
4864 if (fragment_tlvs
) {
4865 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4866 &tlvs
->mt_router_info
,
4867 &fragment_tlvs
->mt_router_info
);
4871 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
4875 fragment_tlvs
->hostname
=
4876 copy_tlv_dynamic_hostname(tlvs
->hostname
);
4878 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
4881 if (fragment_tlvs
) {
4882 fragment_tlvs
->router_cap
=
4883 copy_tlv_router_cap(tlvs
->router_cap
);
4886 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
4889 if (fragment_tlvs
) {
4890 fragment_tlvs
->te_router_id
=
4891 copy_tlv_te_router_id(tlvs
->te_router_id
);
4894 rv
= pack_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, stream
);
4897 if (fragment_tlvs
) {
4898 fragment_tlvs
->te_router_id_ipv6
=
4899 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4902 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
4905 if (fragment_tlvs
) {
4906 fragment_tlvs
->threeway_adj
=
4907 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4910 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
4913 if (fragment_tlvs
) {
4914 fragment_tlvs
->spine_leaf
=
4915 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4918 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
4920 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
4921 fragment_tlvs
? &fragment_tlvs
: NULL
,
4922 new_fragment
, new_fragment_arg
);
4931 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4932 size_t len_pointer
, bool pad
, bool is_lsp
)
4936 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
4941 add_padding(stream
);
4943 if (len_pointer
!= (size_t)-1) {
4944 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
4947 update_auth(tlvs
, stream
, is_lsp
);
4952 static struct isis_tlvs
*new_fragment(struct list
*l
)
4954 struct isis_tlvs
*rv
= isis_alloc_tlvs();
4956 listnode_add(l
, rv
);
4960 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
4962 struct stream
*dummy_stream
= stream_new(size
);
4963 struct list
*rv
= list_new();
4964 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
4966 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
4967 struct listnode
*node
;
4968 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
4969 isis_free_tlvs(fragment_tlvs
);
4973 stream_free(dummy_stream
);
4977 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
4978 uint8_t tlv_len
, struct stream
*s
,
4979 struct sbuf
*log
, int indent
)
4981 stream_forward_getp(s
, tlv_len
);
4982 sbuf_push(log
, indent
,
4983 "Skipping unknown TLV %hhu (%hhu bytes)\n",
4988 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
4989 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4990 int indent
, bool *unpacked_known_tlvs
)
4992 uint8_t tlv_type
, tlv_len
;
4993 const struct tlv_ops
*ops
;
4995 sbuf_push(log
, indent
, "Unpacking TLV...\n");
4997 if (avail_len
< 2) {
5000 "Available data %zu too short to contain a TLV header.\n",
5005 tlv_type
= stream_getc(stream
);
5006 tlv_len
= stream_getc(stream
);
5008 sbuf_push(log
, indent
+ 2,
5009 "Found TLV of type %hhu and len %hhu.\n",
5012 if (avail_len
< ((size_t)tlv_len
) + 2) {
5013 sbuf_push(log
, indent
+ 2,
5014 "Available data %zu too short for claimed TLV len %hhu.\n",
5015 avail_len
- 2, tlv_len
);
5019 ops
= tlv_table
[context
][tlv_type
];
5020 if (ops
&& ops
->unpack
) {
5021 if (unpacked_known_tlvs
)
5022 *unpacked_known_tlvs
= true;
5023 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
5027 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
5031 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
5032 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5033 int indent
, bool *unpacked_known_tlvs
)
5036 size_t tlv_start
, tlv_pos
;
5038 tlv_start
= stream_get_getp(stream
);
5041 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
5042 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
5044 while (tlv_pos
< avail_len
) {
5045 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
5046 indent
+ 2, unpacked_known_tlvs
);
5050 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
5056 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
5057 struct isis_tlvs
**dest
, const char **log
)
5059 static struct sbuf logbuf
;
5062 struct isis_tlvs
*result
;
5064 if (!sbuf_buf(&logbuf
))
5065 sbuf_init(&logbuf
, NULL
, 0);
5067 sbuf_reset(&logbuf
);
5068 if (avail_len
> STREAM_READABLE(stream
)) {
5069 sbuf_push(&logbuf
, indent
,
5070 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5071 avail_len
, STREAM_READABLE(stream
));
5075 result
= isis_alloc_tlvs();
5076 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
5079 *log
= sbuf_buf(&logbuf
);
5085 #define TLV_OPS(_name_, _desc_) \
5086 static const struct tlv_ops tlv_##_name_##_ops = { \
5087 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5090 #define ITEM_TLV_OPS(_name_, _desc_) \
5091 static const struct tlv_ops tlv_##_name_##_ops = { \
5093 .unpack = unpack_tlv_with_items, \
5095 .pack_item = pack_item_##_name_, \
5096 .free_item = free_item_##_name_, \
5097 .unpack_item = unpack_item_##_name_, \
5098 .format_item = format_item_##_name_, \
5099 .copy_item = copy_item_##_name_}
5101 #define SUBTLV_OPS(_name_, _desc_) \
5102 static const struct tlv_ops subtlv_##_name_##_ops = { \
5103 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5106 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5107 ITEM_TLV_OPS(_name_, _desc_)
5109 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
5110 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
5111 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
5112 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
5113 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
5114 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
5115 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
5116 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
5117 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
5118 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
5119 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
5120 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
5121 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
5122 TLV_OPS(te_router_id_ipv6
, "TLV 140 IPv6 TE Router ID");
5123 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
5124 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
5125 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
5126 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
5127 ITEM_TLV_OPS(global_ipv6_address
, "TLV 233 Global IPv6 Interface Address");
5128 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
5129 TLV_OPS(router_cap
, "TLV 242 Router Capability");
5131 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
5132 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
5134 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
5135 [ISIS_CONTEXT_LSP
] = {
5136 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
5137 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
5138 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
5139 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
5140 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
5141 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
5142 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
5143 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
5144 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
5145 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
5146 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
5147 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
5148 [ISIS_TLV_TE_ROUTER_ID_IPV6
] = &tlv_te_router_id_ipv6_ops
,
5149 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5150 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
5151 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
5152 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
5153 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
5154 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
5155 [ISIS_TLV_GLOBAL_IPV6_ADDRESS
] = &tlv_global_ipv6_address_ops
,
5156 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5157 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5158 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5159 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
5160 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
5162 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
5163 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
5164 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5166 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
5167 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5168 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
5172 /* Accessor functions */
5174 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
5176 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
5177 init_item_list(&tlvs
->isis_auth
);
5179 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
5182 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
5184 auth
->type
= passwd
->type
;
5186 auth
->plength
= passwd
->len
;
5187 memcpy(auth
->passwd
, passwd
->passwd
,
5188 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
5190 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
5191 auth
->length
= passwd
->len
;
5192 memcpy(auth
->value
, passwd
->passwd
,
5193 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
5196 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
5199 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
5200 struct list
*addresses
)
5202 struct listnode
*node
;
5203 struct area_addr
*area_addr
;
5205 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
5206 struct isis_area_address
*a
=
5207 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5209 a
->len
= area_addr
->addr_len
;
5210 memcpy(a
->addr
, area_addr
->area_addr
, 20);
5211 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
5215 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
5217 struct listnode
*node
;
5220 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
5221 struct isis_lan_neighbor
*n
=
5222 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
5224 memcpy(n
->mac
, snpa
, 6);
5225 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
5229 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
5230 struct nlpids
*nlpids
)
5232 tlvs
->protocols_supported
.count
= nlpids
->count
;
5233 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
5234 if (nlpids
->count
) {
5235 tlvs
->protocols_supported
.protocols
=
5236 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
5237 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
5240 tlvs
->protocols_supported
.protocols
= NULL
;
5244 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5245 bool overload
, bool attached
)
5247 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
5249 i
->overload
= overload
;
5250 i
->attached
= attached
;
5252 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
5255 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
5257 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5259 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
5263 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
5264 struct list
*addresses
)
5266 struct listnode
*node
;
5267 struct prefix_ipv4
*ip_addr
;
5268 unsigned int addr_count
= 0;
5270 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5271 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
5273 if (addr_count
>= 63)
5278 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
5279 struct list
*addresses
)
5281 struct listnode
*node
;
5282 struct prefix_ipv6
*ip_addr
;
5283 unsigned int addr_count
= 0;
5285 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5286 if (addr_count
>= 15)
5289 struct isis_ipv6_address
*a
=
5290 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5292 a
->addr
= ip_addr
->prefix
;
5293 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
5298 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs
*tlvs
,
5299 struct list
*addresses
)
5301 struct listnode
*node
;
5302 struct prefix_ipv6
*ip_addr
;
5303 unsigned int addr_count
= 0;
5305 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5306 if (addr_count
>= 15)
5309 struct isis_ipv6_address
*a
=
5310 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5312 a
->addr
= ip_addr
->prefix
;
5313 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)a
);
5318 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
5319 struct stream
*stream
,
5320 struct isis_auth
*auth
, bool is_lsp
);
5322 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
5323 struct stream
*stream
,
5324 struct isis_auth
*auth
, bool is_lsp
)
5326 return (auth
->length
== passwd
->len
5327 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
5330 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
5331 struct stream
*stream
,
5332 struct isis_auth
*auth
, bool is_lsp
)
5336 uint16_t rem_lifetime
;
5339 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
5341 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
5342 #ifdef CRYPTO_OPENSSL
5343 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
5344 passwd
->len
, STREAM_DATA(stream
),
5345 stream_get_endp(stream
), NULL
, NULL
);
5347 memcpy(digest
, result
, 16);
5348 #elif CRYPTO_INTERNAL
5349 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
5350 passwd
->len
, digest
);
5352 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
5354 bool rv
= !memcmp(digest
, auth
->value
, 16);
5357 restore_auth_md5(stream
, checksum
, rem_lifetime
);
5362 static const auth_validator_func auth_validators
[] = {
5363 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
5364 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
5367 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
5368 struct stream
*stream
, bool is_lsp
)
5370 /* If no auth is set, always pass authentication */
5372 return ISIS_AUTH_OK
;
5374 /* If we don't known how to validate the auth, return invalid */
5375 if (passwd
->type
>= array_size(auth_validators
)
5376 || !auth_validators
[passwd
->type
])
5377 return ISIS_AUTH_NO_VALIDATOR
;
5379 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
5380 struct isis_auth
*auth
;
5381 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
5382 if (auth
->type
== passwd
->type
)
5386 /* If matching auth TLV could not be found, return invalid */
5388 return ISIS_AUTH_TYPE_FAILURE
;
5391 /* Perform validation and return result */
5392 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
5393 return ISIS_AUTH_OK
;
5395 return ISIS_AUTH_FAILURE
;
5398 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
5399 struct list
*addresses
)
5401 struct isis_area_address
*addr_head
;
5403 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
5404 for (struct isis_area_address
*addr
= addr_head
; addr
;
5405 addr
= addr
->next
) {
5406 struct listnode
*node
;
5407 struct area_addr
*a
;
5409 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
5410 if (a
->addr_len
== addr
->len
5411 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
5419 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
5420 struct isis_adjacency
*adj
,
5423 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
5424 uint32_t oc
= adj
->area_address_count
;
5427 adj
->area_address_count
= tlvs
->area_addresses
.count
;
5428 adj
->area_addresses
= XREALLOC(
5429 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
5430 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
5432 for (; oc
< adj
->area_address_count
; oc
++) {
5433 adj
->area_addresses
[oc
].addr_len
= 0;
5434 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
5435 sizeof(adj
->area_addresses
[oc
].area_addr
));
5439 struct isis_area_address
*addr
= NULL
;
5440 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
5442 addr
= (struct isis_area_address
*)
5443 tlvs
->area_addresses
.head
;
5447 if (adj
->area_addresses
[i
].addr_len
== addr
->len
5448 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
5454 adj
->area_addresses
[i
].addr_len
= addr
->len
;
5455 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
5459 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
5460 struct isis_adjacency
*adj
,
5463 bool ipv4_supported
= false, ipv6_supported
= false;
5465 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
5466 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
5467 ipv4_supported
= true;
5468 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
5469 ipv6_supported
= true;
5472 struct nlpids reduced
= {};
5474 if (ipv4_supported
&& ipv6_supported
) {
5476 reduced
.nlpids
[0] = NLPID_IP
;
5477 reduced
.nlpids
[1] = NLPID_IPV6
;
5478 } else if (ipv4_supported
) {
5480 reduced
.nlpids
[0] = NLPID_IP
;
5481 } else if (ipv6_supported
) {
5483 reduced
.nlpids
[0] = NLPID_IPV6
;
5488 if (adj
->nlpids
.count
== reduced
.count
5489 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
5493 adj
->nlpids
.count
= reduced
.count
;
5494 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
5497 DEFINE_HOOK(isis_adj_ip_enabled_hook
,
5498 (struct isis_adjacency
* adj
, int family
, bool global
),
5499 (adj
, family
, global
));
5500 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
5501 (struct isis_adjacency
* adj
, int family
, bool global
),
5502 (adj
, family
, global
));
5504 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
5505 struct isis_adjacency
*adj
,
5508 bool ipv4_enabled
= false;
5510 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
5511 ipv4_enabled
= true;
5512 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
5513 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
, false);
5515 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
5516 uint32_t oc
= adj
->ipv4_address_count
;
5519 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
5520 adj
->ipv4_addresses
= XREALLOC(
5521 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
5522 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
5524 for (; oc
< adj
->ipv4_address_count
; oc
++) {
5525 memset(&adj
->ipv4_addresses
[oc
], 0,
5526 sizeof(adj
->ipv4_addresses
[oc
]));
5530 struct isis_ipv4_address
*addr
= NULL
;
5531 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
5533 addr
= (struct isis_ipv4_address
*)
5534 tlvs
->ipv4_address
.head
;
5538 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
5539 sizeof(addr
->addr
)))
5543 adj
->ipv4_addresses
[i
] = addr
->addr
;
5547 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
, false);
5550 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5551 struct isis_adjacency
*adj
,
5554 bool ipv6_enabled
= false;
5556 if (adj
->ll_ipv6_count
== 0 && tlvs
->ipv6_address
.count
> 0)
5557 ipv6_enabled
= true;
5558 else if (adj
->ll_ipv6_count
> 0 && tlvs
->ipv6_address
.count
== 0)
5559 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, false);
5561 if (adj
->ll_ipv6_count
!= tlvs
->ipv6_address
.count
) {
5562 uint32_t oc
= adj
->ll_ipv6_count
;
5565 adj
->ll_ipv6_count
= tlvs
->ipv6_address
.count
;
5566 adj
->ll_ipv6_addrs
= XREALLOC(
5567 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
,
5568 adj
->ll_ipv6_count
* sizeof(*adj
->ll_ipv6_addrs
));
5570 for (; oc
< adj
->ll_ipv6_count
; oc
++) {
5571 memset(&adj
->ll_ipv6_addrs
[oc
], 0,
5572 sizeof(adj
->ll_ipv6_addrs
[oc
]));
5576 struct isis_ipv6_address
*addr
= NULL
;
5577 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
5579 addr
= (struct isis_ipv6_address
*)
5580 tlvs
->ipv6_address
.head
;
5584 if (!memcmp(&adj
->ll_ipv6_addrs
[i
], &addr
->addr
,
5585 sizeof(addr
->addr
)))
5589 adj
->ll_ipv6_addrs
[i
] = addr
->addr
;
5593 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, false);
5597 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5598 struct isis_adjacency
*adj
,
5601 bool global_ipv6_enabled
= false;
5603 if (adj
->global_ipv6_count
== 0 && tlvs
->global_ipv6_address
.count
> 0)
5604 global_ipv6_enabled
= true;
5605 else if (adj
->global_ipv6_count
> 0
5606 && tlvs
->global_ipv6_address
.count
== 0)
5607 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, true);
5609 if (adj
->global_ipv6_count
!= tlvs
->global_ipv6_address
.count
) {
5610 uint32_t oc
= adj
->global_ipv6_count
;
5613 adj
->global_ipv6_count
= tlvs
->global_ipv6_address
.count
;
5614 adj
->global_ipv6_addrs
= XREALLOC(
5615 MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
,
5616 adj
->global_ipv6_count
5617 * sizeof(*adj
->global_ipv6_addrs
));
5619 for (; oc
< adj
->global_ipv6_count
; oc
++) {
5620 memset(&adj
->global_ipv6_addrs
[oc
], 0,
5621 sizeof(adj
->global_ipv6_addrs
[oc
]));
5625 struct isis_ipv6_address
*addr
= NULL
;
5626 for (unsigned int i
= 0; i
< tlvs
->global_ipv6_address
.count
; i
++) {
5628 addr
= (struct isis_ipv6_address
*)
5629 tlvs
->global_ipv6_address
.head
;
5633 if (!memcmp(&adj
->global_ipv6_addrs
[i
], &addr
->addr
,
5634 sizeof(addr
->addr
)))
5638 adj
->global_ipv6_addrs
[i
] = addr
->addr
;
5641 if (global_ipv6_enabled
)
5642 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, true);
5645 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
5650 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
5651 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
5652 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
5653 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5654 tlvs_global_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5657 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
5659 struct isis_lan_neighbor
*ne_head
;
5661 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
5662 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
5663 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
5670 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
5672 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
5674 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
5675 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
5676 entry
->checksum
= lsp
->hdr
.checksum
;
5677 entry
->seqno
= lsp
->hdr
.seqno
;
5680 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
5683 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
5684 uint8_t *stop_id
, uint16_t num_lsps
,
5685 struct lspdb_head
*head
,
5686 struct isis_lsp
**last_lsp
)
5688 struct isis_lsp searchfor
;
5689 struct isis_lsp
*first
, *lsp
;
5691 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
5692 first
= lspdb_find_gteq(head
, &searchfor
);
5696 frr_each_from (lspdb
, head
, lsp
, first
) {
5697 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
5698 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
5701 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
5706 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
5707 const char *hostname
)
5709 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
5711 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
5714 /* Set Router Capability TLV parameters */
5715 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
5716 const struct isis_router_cap
*cap
)
5718 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
5722 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
5723 *tlvs
->router_cap
= *cap
;
5726 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
5727 const struct in_addr
*id
)
5729 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
5732 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5733 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
5736 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs
*tlvs
,
5737 const struct in6_addr
*id
)
5739 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id_ipv6
);
5742 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5743 memcpy(tlvs
->te_router_id_ipv6
, id
, sizeof(*id
));
5746 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
5747 struct prefix_ipv4
*dest
, uint8_t metric
)
5749 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5752 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5753 apply_mask_ipv4(&r
->prefix
);
5754 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
5757 /* Add IS-IS SR Adjacency-SID subTLVs */
5758 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
5759 struct isis_adj_sid
*adj
)
5761 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5762 SET_SUBTLV(exts
, EXT_ADJ_SID
);
5765 /* Delete IS-IS SR Adjacency-SID subTLVs */
5766 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
5767 struct isis_adj_sid
*adj
)
5769 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5770 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
5771 if (exts
->adj_sid
.count
== 0)
5772 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
5775 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
5776 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5777 struct isis_lan_adj_sid
*lan
)
5779 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5780 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5783 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
5784 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5785 struct isis_lan_adj_sid
*lan
)
5787 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5788 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
5789 if (exts
->lan_sid
.count
== 0)
5790 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5793 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
5794 struct prefix_ipv4
*dest
, uint32_t metric
,
5795 bool external
, struct sr_prefix_cfg
*pcfg
)
5797 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5800 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5801 apply_mask_ipv4(&r
->prefix
);
5803 struct isis_prefix_sid
*psid
=
5804 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5806 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5807 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5808 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5810 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
5813 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5814 struct prefix_ipv6
*dest
, uint32_t metric
,
5815 bool external
, struct sr_prefix_cfg
*pcfg
)
5817 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5820 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5821 apply_mask_ipv6(&r
->prefix
);
5823 struct isis_prefix_sid
*psid
=
5824 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5826 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5827 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5828 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5831 struct isis_item_list
*l
;
5832 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
5834 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
5835 append_item(l
, (struct isis_item
*)r
);
5838 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5839 struct prefix_ipv6
*dest
,
5840 struct prefix_ipv6
*src
,
5843 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
5844 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
5847 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
5848 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
5849 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
5850 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
5853 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
5856 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5859 memcpy(r
->id
, id
, sizeof(r
->id
));
5860 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
5863 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5864 uint8_t *id
, uint32_t metric
,
5865 struct isis_ext_subtlvs
*exts
)
5867 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5869 memcpy(r
->id
, id
, sizeof(r
->id
));
5872 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
5874 struct isis_item_list
*l
;
5875 if ((mtid
== ISIS_MT_IPV4_UNICAST
) || (mtid
== ISIS_MT_DISABLE
))
5876 l
= &tlvs
->extended_reach
;
5878 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
5879 append_item(l
, (struct isis_item
*)r
);
5882 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
5883 enum isis_threeway_state state
,
5884 uint32_t local_circuit_id
,
5885 const uint8_t *neighbor_id
,
5886 uint32_t neighbor_circuit_id
)
5888 assert(!tlvs
->threeway_adj
);
5890 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
5891 tlvs
->threeway_adj
->state
= state
;
5892 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
5895 tlvs
->threeway_adj
->neighbor_set
= true;
5896 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
5897 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
5901 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
5902 bool has_tier
, bool is_leaf
, bool is_spine
,
5905 assert(!tlvs
->spine_leaf
);
5907 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
5910 tlvs
->spine_leaf
->tier
= tier
;
5913 tlvs
->spine_leaf
->has_tier
= has_tier
;
5914 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
5915 tlvs
->spine_leaf
->is_spine
= is_spine
;
5916 tlvs
->spine_leaf
->is_backup
= is_backup
;
5919 struct isis_mt_router_info
*
5920 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
5922 if (!tlvs
|| tlvs
->mt_router_info_empty
)
5925 struct isis_mt_router_info
*rv
;
5926 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
5928 if (rv
->mtid
== mtid
)
5935 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
5936 const uint8_t *generator
,
5937 const uint8_t *sender
)
5939 assert(!tlvs
->purge_originator
);
5941 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
5942 sizeof(*tlvs
->purge_originator
));
5943 memcpy(tlvs
->purge_originator
->generator
, generator
,
5944 sizeof(tlvs
->purge_originator
->generator
));
5946 tlvs
->purge_originator
->sender_set
= true;
5947 memcpy(tlvs
->purge_originator
->sender
, sender
,
5948 sizeof(tlvs
->purge_originator
->sender
));