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
25 #include <json-c/json_object.h>
28 #ifdef CRYPTO_INTERNAL
36 #include "isisd/isisd.h"
37 #include "isisd/isis_tlvs.h"
38 #include "isisd/isis_common.h"
39 #include "isisd/isis_mt.h"
40 #include "isisd/isis_misc.h"
41 #include "isisd/isis_adjacency.h"
42 #include "isisd/isis_circuit.h"
43 #include "isisd/isis_pdu.h"
44 #include "isisd/isis_lsp.h"
45 #include "isisd/isis_te.h"
46 #include "isisd/isis_sr.h"
48 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs");
49 DEFINE_MTYPE(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs");
50 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists");
52 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
53 uint8_t tlv_len
, struct stream
*s
,
54 struct sbuf
*log
, void *dest
, int indent
);
55 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
,
57 typedef void (*free_item_func
)(struct isis_item
*i
);
58 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
59 struct sbuf
*log
, void *dest
, int indent
);
60 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
61 struct sbuf
*buf
, struct json_object
*json
,
63 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
67 unpack_tlv_func unpack
;
69 pack_item_func pack_item
;
70 free_item_func free_item
;
71 unpack_item_func unpack_item
;
72 format_item_func format_item
;
73 copy_item_func copy_item
;
81 struct pack_order_entry
{
82 enum isis_tlv_context context
;
83 enum isis_tlv_type type
;
84 enum how_to_pack how_to_pack
;
87 #define PACK_ENTRY(t, h, w) \
89 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
91 .what_to_pack = offsetof(struct isis_tlvs, w), \
94 static const struct pack_order_entry pack_order
[] = {
95 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
96 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
97 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
98 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
99 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
100 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
101 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
102 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
103 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
104 PACK_ENTRY(GLOBAL_IPV6_ADDRESS
, ISIS_ITEMS
, global_ipv6_address
),
105 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
106 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
107 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
108 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)
111 /* This is a forward definition. The table is actually initialized
112 * in at the bottom. */
113 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
115 /* End of _ops forward definition. */
118 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
119 static void init_item_list(struct isis_item_list
*items
);
121 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
122 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
124 struct isis_ext_subtlvs
*ext
;
126 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
127 init_item_list(&ext
->adj_sid
);
128 init_item_list(&ext
->lan_sid
);
134 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
135 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
136 * that MT is disabled i.e. IS-IS is working with a Single Topology.
138 static struct isis_ext_subtlvs
*
139 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, uint16_t mtid
)
141 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
142 struct isis_adj_sid
*adj
;
143 struct isis_lan_adj_sid
*lan
;
145 /* Copy the Extended IS main part */
146 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
148 /* Disable IPv4 / IPv6 advertisement in function of MTID */
149 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
150 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR6
);
151 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR6
);
153 if (mtid
== ISIS_MT_IPV6_UNICAST
) {
154 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR
);
155 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR
);
158 /* Prepare (LAN)-Adjacency Segment Routing ID*/
159 init_item_list(&rv
->adj_sid
);
160 init_item_list(&rv
->lan_sid
);
162 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
163 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
165 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
166 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
168 if ((mtid
!= ISIS_MT_DISABLE
)
169 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
170 && (adj
->family
!= AF_INET
))
171 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
172 && (adj
->family
!= AF_INET6
))))
175 struct isis_adj_sid
*new;
177 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
178 new->family
= adj
->family
;
179 new->flags
= adj
->flags
;
180 new->weight
= adj
->weight
;
182 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
183 SET_SUBTLV(rv
, EXT_ADJ_SID
);
186 /* Same for LAN Adj SID */
187 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
189 if ((mtid
!= ISIS_MT_DISABLE
)
190 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
191 && (lan
->family
!= AF_INET
))
192 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
193 && (lan
->family
!= AF_INET6
))))
196 struct isis_lan_adj_sid
*new;
198 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
199 new->family
= lan
->family
;
200 new->flags
= lan
->flags
;
201 new->weight
= lan
->weight
;
202 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
204 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
205 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
211 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
212 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
213 struct sbuf
*buf
, struct json_object
*json
,
214 int indent
, uint16_t mtid
)
219 /* Standard metrics */
220 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
222 snprintfrr(aux_buf
, sizeof(aux_buf
), "0x%x",
224 json_object_string_add(json
, "adm-group", aux_buf
);
226 sbuf_push(buf
, indent
, "Administrative Group: 0x%x\n",
229 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
231 json_object_int_add(json
, "link-local-id",
233 json_object_int_add(json
, "link-remote-id",
236 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
238 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
242 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
244 inet_ntop(AF_INET
, &exts
->local_addr
, aux_buf
,
246 json_object_string_add(json
, "local-iface-ip", aux_buf
);
248 sbuf_push(buf
, indent
,
249 "Local Interface IP Address(es): %pI4\n",
252 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
254 inet_ntop(AF_INET
, &exts
->neigh_addr
, aux_buf
,
256 json_object_string_add(json
, "remote-iface-ip",
259 sbuf_push(buf
, indent
,
260 "Remote Interface IP Address(es): %pI4\n",
263 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
265 inet_ntop(AF_INET6
, &exts
->local_addr6
, aux_buf
,
267 json_object_string_add(json
, "local-iface-ipv6",
270 sbuf_push(buf
, indent
,
271 "Local Interface IPv6 Address(es): %pI6\n",
274 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
276 inet_ntop(AF_INET6
, &exts
->neigh_addr6
, aux_buf
,
278 json_object_string_add(json
, "remote-iface-ipv6",
281 sbuf_push(buf
, indent
,
282 "Remote Interface IPv6 Address(es): %pI6\n",
285 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
287 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
289 json_object_string_add(json
, "max-bandwith-bytes-sec",
292 sbuf_push(buf
, indent
,
293 "Maximum Bandwidth: %g (Bytes/sec)\n",
296 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
298 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
300 json_object_string_add(
301 json
, "max-res-bandwith-bytes-sec", aux_buf
);
305 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
308 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
310 struct json_object
*unrsv_json
;
311 unrsv_json
= json_object_new_object();
312 json_object_object_add(json
, "unrsv-bandwith-bytes-sec",
314 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 1) {
315 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d", j
);
316 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
318 json_object_string_add(unrsv_json
, cnt_buf
,
322 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
323 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
326 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
327 j
, exts
->unrsv_bw
[j
], j
+ 1,
328 exts
->unrsv_bw
[j
+ 1]);
332 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
334 json_object_int_add(json
, "te-metric", exts
->te_metric
);
336 sbuf_push(buf
, indent
,
337 "Traffic Engineering Metric: %u\n",
340 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
342 json_object_int_add(json
, "inter-as-te-remote-as",
345 sbuf_push(buf
, indent
,
346 "Inter-AS TE Remote AS number: %u\n",
349 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
351 inet_ntop(AF_INET6
, &exts
->remote_ip
, aux_buf
,
353 json_object_string_add(
354 json
, "inter-as-te-remote-asbr-ip", aux_buf
);
356 sbuf_push(buf
, indent
,
357 "Inter-AS TE Remote ASBR IP address: %pI4\n",
360 /* Extended metrics */
361 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
363 struct json_object
*avg_json
;
364 avg_json
= json_object_new_object();
365 json_object_object_add(json
, "avg-delay", avg_json
);
366 json_object_string_add(avg_json
, "delay",
367 IS_ANORMAL(exts
->delay
)
370 json_object_int_add(avg_json
, "micro-sec", exts
->delay
);
372 sbuf_push(buf
, indent
,
373 "%s Average Link Delay: %u (micro-sec)\n",
374 IS_ANORMAL(exts
->delay
) ? "Anomalous"
378 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
380 struct json_object
*avg_json
;
381 avg_json
= json_object_new_object();
382 json_object_object_add(json
, "max-min-delay", avg_json
);
383 json_object_string_add(avg_json
, "delay",
384 IS_ANORMAL(exts
->min_delay
)
387 snprintfrr(aux_buf
, sizeof(aux_buf
), "%u / %u",
388 exts
->min_delay
& TE_EXT_MASK
,
389 exts
->max_delay
& TE_EXT_MASK
);
390 json_object_string_add(avg_json
, "micro-sec", aux_buf
);
395 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
396 IS_ANORMAL(exts
->min_delay
) ? "Anomalous"
398 exts
->min_delay
& TE_EXT_MASK
,
399 exts
->max_delay
& TE_EXT_MASK
);
401 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
403 json_object_int_add(json
, "delay-variation-micro-sec",
404 exts
->delay_var
& TE_EXT_MASK
);
406 sbuf_push(buf
, indent
,
407 "Delay Variation: %u (micro-sec)\n",
408 exts
->delay_var
& TE_EXT_MASK
);
410 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
412 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
413 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
415 struct json_object
*link_json
;
416 link_json
= json_object_new_object();
417 json_object_object_add(json
, "link-packet-loss",
419 json_object_string_add(link_json
, "loss",
420 IS_ANORMAL(exts
->pkt_loss
)
423 json_object_string_add(link_json
, "percentaje",
426 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
427 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous"
429 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
432 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
434 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
436 json_object_string_add(json
,
437 "unidir-residual-band-bytes-sec",
442 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
445 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
447 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
449 json_object_string_add(
450 json
, "unidir-available-band-bytes-sec",
455 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
458 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
460 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
462 json_object_string_add(json
,
463 "unidir-utilized-band-bytes-sec",
468 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
471 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
472 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
473 struct isis_adj_sid
*adj
;
476 struct json_object
*arr_adj_json
, *flags_json
;
477 arr_adj_json
= json_object_new_array();
478 json_object_object_add(json
, "adj-sid", arr_adj_json
);
479 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
480 adj
; adj
= adj
->next
) {
481 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
483 flags_json
= json_object_new_object();
484 json_object_int_add(flags_json
, "sid",
486 json_object_int_add(flags_json
, "weight",
488 json_object_string_add(
489 flags_json
, "flag-f",
490 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
493 json_object_string_add(
494 flags_json
, "flag-b",
495 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
498 json_object_string_add(
499 flags_json
, "flag-v",
500 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
503 json_object_string_add(
504 flags_json
, "flag-l",
505 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
508 json_object_string_add(
509 flags_json
, "flag-s",
510 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
513 json_object_string_add(
514 flags_json
, "flag-p",
515 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
518 json_object_array_add(arr_adj_json
, flags_json
);
521 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
522 adj
; adj
= adj
->next
) {
525 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
526 adj
->sid
, adj
->weight
,
527 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
530 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
533 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
536 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
539 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
542 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
547 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
548 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
549 struct isis_lan_adj_sid
*lan
;
551 struct json_object
*arr_adj_json
, *flags_json
;
552 arr_adj_json
= json_object_new_array();
553 json_object_object_add(json
, "lan-adj-sid",
555 for (lan
= (struct isis_lan_adj_sid
*)
557 lan
; lan
= lan
->next
) {
558 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
559 (lan
->family
!= AF_INET
)) ||
560 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
561 (lan
->family
!= AF_INET6
)))
563 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
565 flags_json
= json_object_new_object();
566 json_object_int_add(flags_json
, "sid",
568 json_object_int_add(flags_json
, "weight",
570 json_object_string_add(
571 flags_json
, "flag-f",
572 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
575 json_object_string_add(
576 flags_json
, "flag-b",
577 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
580 json_object_string_add(
581 flags_json
, "flag-v",
582 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
585 json_object_string_add(
586 flags_json
, "flag-l",
587 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
590 json_object_string_add(
591 flags_json
, "flag-s",
592 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
595 json_object_string_add(
596 flags_json
, "flag-p",
597 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
600 json_object_array_add(arr_adj_json
, flags_json
);
604 for (lan
= (struct isis_lan_adj_sid
*)
606 lan
; lan
= lan
->next
) {
607 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
608 (lan
->family
!= AF_INET
)) ||
609 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
610 (lan
->family
!= AF_INET6
)))
614 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
615 " Neighbor-ID: %s\n",
616 lan
->sid
, lan
->weight
,
617 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
620 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
623 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
626 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
629 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
632 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
635 isis_format_id(lan
->neighbor_id
, 6));
640 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
642 struct isis_item
*item
, *next_item
;
644 /* First, free Adj SID and LAN Adj SID list if needed */
645 for (item
= exts
->adj_sid
.head
; item
; item
= next_item
) {
646 next_item
= item
->next
;
647 XFREE(MTYPE_ISIS_SUBTLV
, item
);
649 for (item
= exts
->lan_sid
.head
; item
; item
= next_item
) {
650 next_item
= item
->next
;
651 XFREE(MTYPE_ISIS_SUBTLV
, item
);
653 XFREE(MTYPE_ISIS_SUBTLV
, exts
);
656 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
657 struct stream
*s
, size_t *min_len
)
661 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
662 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
666 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
667 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
668 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
669 stream_putl(s
, exts
->adm_group
);
671 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
672 stream_putc(s
, ISIS_SUBTLV_LLRI
);
673 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
674 stream_putl(s
, exts
->local_llri
);
675 stream_putl(s
, exts
->remote_llri
);
677 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
678 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
679 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
680 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
682 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
683 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
684 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
685 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
687 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
688 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
689 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
690 stream_put(s
, &exts
->local_addr6
, 16);
692 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
693 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
694 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
695 stream_put(s
, &exts
->neigh_addr6
, 16);
697 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
698 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
699 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
700 stream_putf(s
, exts
->max_bw
);
702 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
703 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
704 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
705 stream_putf(s
, exts
->max_rsv_bw
);
707 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
708 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
709 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
710 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
711 stream_putf(s
, exts
->unrsv_bw
[j
]);
713 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
714 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
715 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
716 stream_put3(s
, exts
->te_metric
);
718 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
719 stream_putc(s
, ISIS_SUBTLV_RAS
);
720 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
721 stream_putl(s
, exts
->remote_as
);
723 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
724 stream_putc(s
, ISIS_SUBTLV_RIP
);
725 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
726 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
728 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
729 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
730 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
731 stream_putl(s
, exts
->delay
);
733 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
734 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
735 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
736 stream_putl(s
, exts
->min_delay
);
737 stream_putl(s
, exts
->max_delay
);
739 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
740 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
741 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
742 stream_putl(s
, exts
->delay_var
);
744 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
745 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
746 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
747 stream_putl(s
, exts
->pkt_loss
);
749 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
750 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
751 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
752 stream_putf(s
, exts
->res_bw
);
754 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
755 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
756 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
757 stream_putf(s
, exts
->ava_bw
);
759 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
760 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
761 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
762 stream_putf(s
, exts
->use_bw
);
764 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
765 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
766 struct isis_adj_sid
*adj
;
768 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
770 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
771 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
772 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
774 stream_putc(s
, size
);
775 stream_putc(s
, adj
->flags
);
776 stream_putc(s
, adj
->weight
);
777 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
778 stream_put3(s
, adj
->sid
);
780 stream_putl(s
, adj
->sid
);
784 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
785 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
786 struct isis_lan_adj_sid
*lan
;
788 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
790 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
791 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
792 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
794 stream_putc(s
, size
);
795 stream_putc(s
, lan
->flags
);
796 stream_putc(s
, lan
->weight
);
797 stream_put(s
, lan
->neighbor_id
, 6);
798 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
799 stream_put3(s
, lan
->sid
);
801 stream_putl(s
, lan
->sid
);
808 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
809 struct sbuf
*log
, void *dest
, int indent
)
815 struct isis_extended_reach
*rv
= dest
;
816 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
821 * Parse subTLVs until reach subTLV length
822 * Check that it remains at least 2 bytes: subTLV Type & Length
824 while (len
> sum
+ 2) {
825 /* Read SubTLV Type and Length */
826 subtlv_type
= stream_getc(s
);
827 subtlv_len
= stream_getc(s
);
828 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
831 "TLV %hhu: Available data %u is less than TLV size %u !\n",
832 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
837 switch (subtlv_type
) {
838 /* Standard Metric as defined in RFC5305 */
839 case ISIS_SUBTLV_ADMIN_GRP
:
840 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
841 sbuf_push(log
, indent
,
842 "TLV size does not match expected size for Administrative Group!\n");
843 stream_forward_getp(s
, subtlv_len
);
845 exts
->adm_group
= stream_getl(s
);
846 SET_SUBTLV(exts
, EXT_ADM_GRP
);
849 case ISIS_SUBTLV_LLRI
:
850 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
851 sbuf_push(log
, indent
,
852 "TLV size does not match expected size for Link ID!\n");
853 stream_forward_getp(s
, subtlv_len
);
855 exts
->local_llri
= stream_getl(s
);
856 exts
->remote_llri
= stream_getl(s
);
857 SET_SUBTLV(exts
, EXT_LLRI
);
860 case ISIS_SUBTLV_LOCAL_IPADDR
:
861 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
862 sbuf_push(log
, indent
,
863 "TLV size does not match expected size for Local IP address!\n");
864 stream_forward_getp(s
, subtlv_len
);
866 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
867 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
870 case ISIS_SUBTLV_RMT_IPADDR
:
871 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
872 sbuf_push(log
, indent
,
873 "TLV size does not match expected size for Remote IP address!\n");
874 stream_forward_getp(s
, subtlv_len
);
876 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
877 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
880 case ISIS_SUBTLV_LOCAL_IPADDR6
:
881 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
882 sbuf_push(log
, indent
,
883 "TLV size does not match expected size for Local IPv6 address!\n");
884 stream_forward_getp(s
, subtlv_len
);
886 stream_get(&exts
->local_addr6
, s
, 16);
887 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
890 case ISIS_SUBTLV_RMT_IPADDR6
:
891 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
892 sbuf_push(log
, indent
,
893 "TLV size does not match expected size for Remote IPv6 address!\n");
894 stream_forward_getp(s
, subtlv_len
);
896 stream_get(&exts
->neigh_addr6
, s
, 16);
897 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
900 case ISIS_SUBTLV_MAX_BW
:
901 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
902 sbuf_push(log
, indent
,
903 "TLV size does not match expected size for Maximum Bandwidth!\n");
904 stream_forward_getp(s
, subtlv_len
);
906 exts
->max_bw
= stream_getf(s
);
907 SET_SUBTLV(exts
, EXT_MAX_BW
);
910 case ISIS_SUBTLV_MAX_RSV_BW
:
911 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
912 sbuf_push(log
, indent
,
913 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
914 stream_forward_getp(s
, subtlv_len
);
916 exts
->max_rsv_bw
= stream_getf(s
);
917 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
920 case ISIS_SUBTLV_UNRSV_BW
:
921 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
922 sbuf_push(log
, indent
,
923 "TLV size does not match expected size for Unreserved Bandwidth!\n");
924 stream_forward_getp(s
, subtlv_len
);
926 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
927 exts
->unrsv_bw
[i
] = stream_getf(s
);
928 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
931 case ISIS_SUBTLV_TE_METRIC
:
932 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
933 sbuf_push(log
, indent
,
934 "TLV size does not match expected size for Traffic Engineering Metric!\n");
935 stream_forward_getp(s
, subtlv_len
);
937 exts
->te_metric
= stream_get3(s
);
938 SET_SUBTLV(exts
, EXT_TE_METRIC
);
941 case ISIS_SUBTLV_RAS
:
942 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
943 sbuf_push(log
, indent
,
944 "TLV size does not match expected size for Remote AS number!\n");
945 stream_forward_getp(s
, subtlv_len
);
947 exts
->remote_as
= stream_getl(s
);
948 SET_SUBTLV(exts
, EXT_RMT_AS
);
951 case ISIS_SUBTLV_RIP
:
952 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
953 sbuf_push(log
, indent
,
954 "TLV size does not match expected size for Remote ASBR IP Address!\n");
955 stream_forward_getp(s
, subtlv_len
);
957 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
958 SET_SUBTLV(exts
, EXT_RMT_IP
);
961 /* Extended Metrics as defined in RFC 7810 */
962 case ISIS_SUBTLV_AV_DELAY
:
963 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
964 sbuf_push(log
, indent
,
965 "TLV size does not match expected size for Average Link Delay!\n");
966 stream_forward_getp(s
, subtlv_len
);
968 exts
->delay
= stream_getl(s
);
969 SET_SUBTLV(exts
, EXT_DELAY
);
972 case ISIS_SUBTLV_MM_DELAY
:
973 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
974 sbuf_push(log
, indent
,
975 "TLV size does not match expected size for Min/Max Link Delay!\n");
976 stream_forward_getp(s
, subtlv_len
);
978 exts
->min_delay
= stream_getl(s
);
979 exts
->max_delay
= stream_getl(s
);
980 SET_SUBTLV(exts
, EXT_MM_DELAY
);
983 case ISIS_SUBTLV_DELAY_VAR
:
984 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
985 sbuf_push(log
, indent
,
986 "TLV size does not match expected size for Delay Variation!\n");
987 stream_forward_getp(s
, subtlv_len
);
989 exts
->delay_var
= stream_getl(s
);
990 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
993 case ISIS_SUBTLV_PKT_LOSS
:
994 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
995 sbuf_push(log
, indent
,
996 "TLV size does not match expected size for Link Packet Loss!\n");
997 stream_forward_getp(s
, subtlv_len
);
999 exts
->pkt_loss
= stream_getl(s
);
1000 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
1003 case ISIS_SUBTLV_RES_BW
:
1004 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1005 sbuf_push(log
, indent
,
1006 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
1007 stream_forward_getp(s
, subtlv_len
);
1009 exts
->res_bw
= stream_getf(s
);
1010 SET_SUBTLV(exts
, EXT_RES_BW
);
1013 case ISIS_SUBTLV_AVA_BW
:
1014 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1015 sbuf_push(log
, indent
,
1016 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
1017 stream_forward_getp(s
, subtlv_len
);
1019 exts
->ava_bw
= stream_getf(s
);
1020 SET_SUBTLV(exts
, EXT_AVA_BW
);
1023 case ISIS_SUBTLV_USE_BW
:
1024 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1025 sbuf_push(log
, indent
,
1026 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
1027 stream_forward_getp(s
, subtlv_len
);
1029 exts
->use_bw
= stream_getf(s
);
1030 SET_SUBTLV(exts
, EXT_USE_BW
);
1033 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1034 case ISIS_SUBTLV_ADJ_SID
:
1035 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
1036 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
1037 sbuf_push(log
, indent
,
1038 "TLV size does not match expected size for Adjacency SID!\n");
1039 stream_forward_getp(s
, subtlv_len
);
1041 struct isis_adj_sid
*adj
;
1043 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1044 sizeof(struct isis_adj_sid
));
1045 adj
->flags
= stream_getc(s
);
1046 adj
->weight
= stream_getc(s
);
1047 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1048 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
1051 "TLV size does not match expected size for Adjacency SID!\n");
1052 stream_forward_getp(s
, subtlv_len
- 2);
1056 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1058 != ISIS_SUBTLV_ADJ_SID_SIZE
1062 "TLV size does not match expected size for Adjacency SID!\n");
1063 stream_forward_getp(s
, subtlv_len
- 2);
1067 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1068 adj
->sid
= stream_get3(s
);
1069 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
1071 adj
->sid
= stream_getl(s
);
1073 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1074 adj
->family
= AF_INET
;
1075 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1076 adj
->family
= AF_INET6
;
1077 append_item(&exts
->adj_sid
,
1078 (struct isis_item
*)adj
);
1079 SET_SUBTLV(exts
, EXT_ADJ_SID
);
1082 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1083 case ISIS_SUBTLV_LAN_ADJ_SID
:
1084 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1085 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
1086 sbuf_push(log
, indent
,
1087 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1088 stream_forward_getp(s
, subtlv_len
);
1090 struct isis_lan_adj_sid
*lan
;
1092 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1093 sizeof(struct isis_lan_adj_sid
));
1094 lan
->flags
= stream_getc(s
);
1095 lan
->weight
= stream_getc(s
);
1096 stream_get(&(lan
->neighbor_id
), s
,
1099 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1101 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
1104 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1105 stream_forward_getp(
1111 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1113 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1117 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1118 stream_forward_getp(
1124 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1125 lan
->sid
= stream_get3(s
);
1126 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
1128 lan
->sid
= stream_getl(s
);
1130 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1131 lan
->family
= AF_INET
;
1132 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1133 lan
->family
= AF_INET6
;
1134 append_item(&exts
->lan_sid
,
1135 (struct isis_item
*)lan
);
1136 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
1140 /* Skip unknown TLV */
1141 stream_forward_getp(s
, subtlv_len
);
1144 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
1150 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1151 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
1153 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1154 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1156 rv
->flags
= sid
->flags
;
1157 rv
->algorithm
= sid
->algorithm
;
1158 rv
->value
= sid
->value
;
1159 return (struct isis_item
*)rv
;
1162 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
1163 struct sbuf
*buf
, struct json_object
*json
,
1166 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1169 struct json_object
*sr_json
;
1170 sr_json
= json_object_new_object();
1171 json_object_object_add(json
, "sr", sr_json
);
1172 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1173 json_object_int_add(sr_json
, "label", sid
->value
);
1175 json_object_int_add(sr_json
, "index", sid
->value
);
1177 json_object_int_add(sr_json
, "alg", sid
->algorithm
);
1178 json_object_string_add(
1179 sr_json
, "readvertised",
1180 ((sid
->flags
& ISIS_PREFIX_SID_READVERTISED
) ? "yes"
1182 json_object_string_add(
1184 ((sid
->flags
& ISIS_PREFIX_SID_NODE
) ? "yes" : ""));
1185 json_object_string_add(sr_json
, "php",
1186 ((sid
->flags
& ISIS_PREFIX_SID_NO_PHP
)
1189 json_object_string_add(
1190 sr_json
, "explicit-null",
1191 ((sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
) ? "yes"
1193 json_object_string_add(
1195 ((sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? "yes" : ""));
1196 json_object_string_add(
1198 ((sid
->flags
& ISIS_PREFIX_SID_LOCAL
) ? "yes" : ""));
1201 sbuf_push(buf
, indent
, "SR Prefix-SID ");
1202 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1203 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
1205 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
1207 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
1208 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
1209 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
1212 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
1213 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP"
1215 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
1218 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
1219 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
1223 static void free_item_prefix_sid(struct isis_item
*i
)
1225 XFREE(MTYPE_ISIS_SUBTLV
, i
);
1228 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
1231 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1233 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
1235 if (STREAM_WRITEABLE(s
) < size
) {
1240 stream_putc(s
, sid
->flags
);
1241 stream_putc(s
, sid
->algorithm
);
1243 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1244 stream_put3(s
, sid
->value
);
1246 stream_putl(s
, sid
->value
);
1252 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1253 struct sbuf
*log
, void *dest
, int indent
)
1255 struct isis_subtlvs
*subtlvs
= dest
;
1256 struct isis_prefix_sid sid
= {
1259 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
1262 sbuf_push(log
, indent
,
1263 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1268 sid
.flags
= stream_getc(s
);
1269 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1270 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
1271 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
1275 sid
.algorithm
= stream_getc(s
);
1277 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1278 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1279 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
1280 if (len
!= expected_size
) {
1281 sbuf_push(log
, indent
,
1282 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1283 expected_size
, len
);
1287 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
1288 sid
.value
= stream_get3(s
);
1289 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
1290 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
1295 sid
.value
= stream_getl(s
);
1298 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, NULL
, indent
+ 2);
1299 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
1303 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1305 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
1310 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1311 rv
->family
= p
->family
;
1312 rv
->prefixlen
= p
->prefixlen
;
1313 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
1317 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1319 struct json_object
*json
,
1325 char prefixbuf
[PREFIX2STR_BUFFER
];
1327 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
));
1328 json_object_string_add(json
, "ipv6-src-prefix", prefixbuf
);
1330 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1331 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1335 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1341 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1344 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1345 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1346 stream_putc(s
, p
->prefixlen
);
1347 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1351 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1352 uint8_t tlv_type
, uint8_t tlv_len
,
1353 struct stream
*s
, struct sbuf
*log
,
1354 void *dest
, int indent
)
1356 struct isis_subtlvs
*subtlvs
= dest
;
1357 struct prefix_ipv6 p
= {
1361 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1364 sbuf_push(log
, indent
,
1365 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1370 p
.prefixlen
= stream_getc(s
);
1371 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1372 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1377 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1380 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1381 1 + PSIZE(p
.prefixlen
), tlv_len
);
1385 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1387 if (subtlvs
->source_prefix
) {
1390 "WARNING: source prefix Sub-TLV present multiple times.\n");
1391 /* Ignore all but first occurrence of the source prefix Sub-TLV
1396 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1397 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1401 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1402 enum isis_tlv_type type
,
1403 struct isis_item
*item
);
1404 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1405 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1406 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1407 enum isis_tlv_type type
, struct isis_item_list
*items
,
1408 struct sbuf
*buf
, struct json_object
*json
,
1410 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1411 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1412 struct isis_item_list
*items
);
1413 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1414 enum isis_tlv_type type
, struct isis_item_list
*items
,
1415 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1416 const struct pack_order_entry
*pe
,
1417 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1418 struct list
*new_fragment_arg
);
1419 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1421 /* Functions related to subtlvs */
1423 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1425 struct isis_subtlvs
*result
;
1427 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1428 result
->context
= context
;
1430 init_item_list(&result
->prefix_sids
);
1435 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1440 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1442 rv
->context
= subtlvs
->context
;
1444 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1445 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1448 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1452 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1453 struct json_object
*json
, int indent
)
1455 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1456 &subtlvs
->prefix_sids
, buf
, json
, indent
);
1458 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, json
, indent
);
1461 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1466 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1467 &subtlvs
->prefix_sids
);
1469 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1471 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1474 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1477 size_t subtlv_len_pos
= stream_get_endp(s
);
1479 if (STREAM_WRITEABLE(s
) < 1)
1482 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1484 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1485 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1489 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1493 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1494 if (subtlv_len
> 255)
1497 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1501 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1502 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1503 int indent
, bool *unpacked_known_tlvs
);
1505 /* Functions related to TLVs 1 Area Addresses */
1507 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1509 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1510 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1512 rv
->len
= addr
->len
;
1513 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1514 return (struct isis_item
*)rv
;
1517 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1518 struct sbuf
*buf
, struct json_object
*json
,
1521 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1524 json_object_string_add(json
, "area-addr",
1525 isonet_print(addr
->addr
, addr
->len
));
1527 sbuf_push(buf
, indent
, "Area Address: %s\n",
1528 isonet_print(addr
->addr
, addr
->len
));
1532 static void free_item_area_address(struct isis_item
*i
)
1534 XFREE(MTYPE_ISIS_TLV
, i
);
1537 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
1540 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1542 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
1543 *min_len
= (unsigned)1 + addr
->len
;
1546 stream_putc(s
, addr
->len
);
1547 stream_put(s
, addr
->addr
, addr
->len
);
1551 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1552 struct stream
*s
, struct sbuf
*log
,
1553 void *dest
, int indent
)
1555 struct isis_tlvs
*tlvs
= dest
;
1556 struct isis_area_address
*rv
= NULL
;
1558 sbuf_push(log
, indent
, "Unpack area address...\n");
1562 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1567 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1568 rv
->len
= stream_getc(s
);
1570 if (len
< 1 + rv
->len
) {
1571 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1576 if (rv
->len
< 1 || rv
->len
> 20) {
1577 sbuf_push(log
, indent
,
1578 "Implausible area address length %hhu\n",
1583 stream_get(rv
->addr
, s
, rv
->len
);
1585 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1586 log
, NULL
, indent
+ 2);
1587 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1590 XFREE(MTYPE_ISIS_TLV
, rv
);
1594 /* Functions related to TLV 2 (Old-Style) IS Reach */
1595 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1597 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1598 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1600 memcpy(rv
->id
, r
->id
, 7);
1601 rv
->metric
= r
->metric
;
1602 return (struct isis_item
*)rv
;
1605 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1607 struct json_object
*json
, int indent
)
1609 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1612 struct json_object
*old_json
;
1613 old_json
= json_object_new_object();
1614 json_object_object_add(json
, "old-reach-style", old_json
);
1615 json_object_string_add(old_json
, "is-reach",
1616 isis_format_id(r
->id
, 7));
1617 json_object_int_add(old_json
, "metric", r
->metric
);
1619 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
1620 isis_format_id(r
->id
, 7), r
->metric
);
1623 static void free_item_oldstyle_reach(struct isis_item
*i
)
1625 XFREE(MTYPE_ISIS_TLV
, i
);
1628 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
1631 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1633 if (STREAM_WRITEABLE(s
) < 11) {
1638 stream_putc(s
, r
->metric
);
1639 stream_putc(s
, 0x80); /* delay metric - unsupported */
1640 stream_putc(s
, 0x80); /* expense metric - unsupported */
1641 stream_putc(s
, 0x80); /* error metric - unsupported */
1642 stream_put(s
, r
->id
, 7);
1647 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1648 struct stream
*s
, struct sbuf
*log
,
1649 void *dest
, int indent
)
1651 struct isis_tlvs
*tlvs
= dest
;
1653 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1657 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1662 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1663 rv
->metric
= stream_getc(s
);
1664 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1665 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1668 stream_forward_getp(s
, 3); /* Skip other metrics */
1669 stream_get(rv
->id
, s
, 7);
1671 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1673 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1677 /* Functions related to TLV 6 LAN Neighbors */
1678 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1680 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1681 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1683 memcpy(rv
->mac
, n
->mac
, 6);
1684 return (struct isis_item
*)rv
;
1687 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1688 struct sbuf
*buf
, struct json_object
*json
,
1691 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1694 json_object_string_add(json
, "lan-neighbor",
1695 isis_format_id(n
->mac
, 6));
1697 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n",
1698 isis_format_id(n
->mac
, 6));
1701 static void free_item_lan_neighbor(struct isis_item
*i
)
1703 XFREE(MTYPE_ISIS_TLV
, i
);
1706 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
1709 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1711 if (STREAM_WRITEABLE(s
) < 6) {
1716 stream_put(s
, n
->mac
, 6);
1721 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1722 struct stream
*s
, struct sbuf
*log
,
1723 void *dest
, int indent
)
1725 struct isis_tlvs
*tlvs
= dest
;
1727 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1731 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1736 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1737 stream_get(rv
->mac
, s
, 6);
1739 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1740 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1744 /* Functions related to TLV 9 LSP Entry */
1745 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1747 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1748 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1750 rv
->rem_lifetime
= e
->rem_lifetime
;
1751 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1752 rv
->seqno
= e
->seqno
;
1753 rv
->checksum
= e
->checksum
;
1755 return (struct isis_item
*)rv
;
1758 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1759 struct sbuf
*buf
, struct json_object
*json
,
1762 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1766 struct json_object
*lsp_json
;
1767 lsp_json
= json_object_new_object();
1768 json_object_object_add(json
, "lsp-entry", lsp_json
);
1769 json_object_string_add(lsp_json
, "id", isis_format_id(e
->id
, 8));
1770 snprintfrr(buf
,sizeof(buf
),"0x%08x",e
->seqno
);
1771 json_object_string_add(lsp_json
, "seq", buf
);
1772 snprintfrr(buf
,sizeof(buf
),"0x%04hx",e
->checksum
);
1773 json_object_string_add(lsp_json
, "chksum", buf
);
1774 json_object_int_add(lsp_json
, "lifetime", e
->checksum
);
1776 sbuf_push(buf
, indent
,
1777 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1778 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1782 static void free_item_lsp_entry(struct isis_item
*i
)
1784 XFREE(MTYPE_ISIS_TLV
, i
);
1787 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
1790 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1792 if (STREAM_WRITEABLE(s
) < 16) {
1797 stream_putw(s
, e
->rem_lifetime
);
1798 stream_put(s
, e
->id
, 8);
1799 stream_putl(s
, e
->seqno
);
1800 stream_putw(s
, e
->checksum
);
1805 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1806 struct sbuf
*log
, void *dest
, int indent
)
1808 struct isis_tlvs
*tlvs
= dest
;
1810 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1814 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1819 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1820 rv
->rem_lifetime
= stream_getw(s
);
1821 stream_get(rv
->id
, s
, 8);
1822 rv
->seqno
= stream_getl(s
);
1823 rv
->checksum
= stream_getw(s
);
1825 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1826 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1830 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1832 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1834 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1835 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1837 memcpy(rv
->id
, r
->id
, 7);
1838 rv
->metric
= r
->metric
;
1841 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1843 return (struct isis_item
*)rv
;
1846 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1848 struct json_object
*json
, int indent
)
1850 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1853 struct json_object
*reach_json
;
1854 reach_json
= json_object_new_object();
1855 json_object_object_add(json
, "ext-reach", reach_json
);
1856 json_object_string_add(
1857 reach_json
, "mt-id",
1858 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
1859 json_object_string_add(reach_json
, "id",
1860 isis_format_id(r
->id
, 7));
1861 json_object_int_add(reach_json
, "metric", r
->metric
);
1862 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1863 json_object_string_add(reach_json
, "mt-name",
1864 isis_mtid2str(mtid
));
1867 format_item_ext_subtlvs(r
->subtlvs
, NULL
, json
,
1870 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1871 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1872 isis_format_id(r
->id
, 7), r
->metric
);
1873 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1874 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1875 sbuf_push(buf
, 0, "\n");
1878 format_item_ext_subtlvs(r
->subtlvs
, buf
, NULL
,
1883 static void free_item_extended_reach(struct isis_item
*i
)
1885 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1886 if (item
->subtlvs
!= NULL
)
1887 free_item_ext_subtlvs(item
->subtlvs
);
1888 XFREE(MTYPE_ISIS_TLV
, item
);
1891 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
1894 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1898 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
1899 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
1903 stream_put(s
, r
->id
, sizeof(r
->id
));
1904 stream_put3(s
, r
->metric
);
1905 len_pos
= stream_get_endp(s
);
1906 /* Real length will be adjust after adding subTLVs */
1909 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
1911 len
= stream_get_endp(s
) - len_pos
- 1;
1912 stream_putc_at(s
, len_pos
, len
);
1916 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1917 struct stream
*s
, struct sbuf
*log
,
1918 void *dest
, int indent
)
1920 struct isis_tlvs
*tlvs
= dest
;
1921 struct isis_extended_reach
*rv
= NULL
;
1923 struct isis_item_list
*items
;
1925 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1926 items
= &tlvs
->extended_reach
;
1928 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1931 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1932 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1935 sbuf_push(log
, indent
,
1936 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
1941 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1942 stream_get(rv
->id
, s
, 7);
1943 rv
->metric
= stream_get3(s
);
1944 subtlv_len
= stream_getc(s
);
1946 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1947 sbuf_push(log
, indent
,
1948 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
1949 subtlv_len
, len
- 11);
1953 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
1957 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1963 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1965 append_item(items
, (struct isis_item
*)rv
);
1969 free_item_extended_reach((struct isis_item
*)rv
);
1974 /* Functions related to TLV 128 (Old-Style) IP Reach */
1975 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1977 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1978 struct isis_oldstyle_ip_reach
*rv
=
1979 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1981 rv
->metric
= r
->metric
;
1982 rv
->prefix
= r
->prefix
;
1983 return (struct isis_item
*)rv
;
1986 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1988 struct json_object
*json
, int indent
)
1990 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1991 char prefixbuf
[PREFIX2STR_BUFFER
];
1994 struct json_object
*old_json
;
1995 old_json
= json_object_new_object();
1996 json_object_object_add(json
, "old-ip-reach-style", old_json
);
1997 json_object_string_add(old_json
, "prefix",
1998 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
1999 json_object_int_add(old_json
, "metric", r
->metric
);
2001 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
2002 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2006 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
2008 XFREE(MTYPE_ISIS_TLV
, i
);
2011 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
2014 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2016 if (STREAM_WRITEABLE(s
) < 12) {
2021 stream_putc(s
, r
->metric
);
2022 stream_putc(s
, 0x80); /* delay metric - unsupported */
2023 stream_putc(s
, 0x80); /* expense metric - unsupported */
2024 stream_putc(s
, 0x80); /* error metric - unsupported */
2025 stream_put(s
, &r
->prefix
.prefix
, 4);
2027 struct in_addr mask
;
2028 masklen2ip(r
->prefix
.prefixlen
, &mask
);
2029 stream_put(s
, &mask
, sizeof(mask
));
2034 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
2035 struct stream
*s
, struct sbuf
*log
,
2036 void *dest
, int indent
)
2038 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
2042 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2047 struct isis_oldstyle_ip_reach
*rv
=
2048 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2049 rv
->metric
= stream_getc(s
);
2050 if ((rv
->metric
& 0x7f) != rv
->metric
) {
2051 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2054 stream_forward_getp(s
, 3); /* Skip other metrics */
2055 rv
->prefix
.family
= AF_INET
;
2056 stream_get(&rv
->prefix
.prefix
, s
, 4);
2058 struct in_addr mask
;
2059 stream_get(&mask
, s
, 4);
2060 rv
->prefix
.prefixlen
= ip_masklen(mask
);
2062 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2064 append_item(dest
, (struct isis_item
*)rv
);
2069 /* Functions related to TLV 129 protocols supported */
2071 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
2072 struct isis_protocols_supported
*dest
)
2074 if (!src
->protocols
|| !src
->count
)
2076 dest
->count
= src
->count
;
2077 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
2078 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
2081 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2083 struct json_object
*json
, int indent
)
2085 if (!p
|| !p
->count
|| !p
->protocols
)
2089 struct json_object
*protocol_json
;
2092 protocol_json
= json_object_new_object();
2093 json_object_object_add(json
, "protocols-supported",
2095 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2096 snprintfrr(buf
, sizeof(buf
), "%d", i
);
2097 json_object_string_add(protocol_json
, buf
,
2098 nlpid2str(p
->protocols
[i
]));
2101 sbuf_push(buf
, indent
, "Protocols Supported: ");
2102 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2103 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
2104 (i
+ 1 < p
->count
) ? ", " : "");
2106 sbuf_push(buf
, 0, "\n");
2110 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
2112 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
2115 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2118 if (!p
|| !p
->count
|| !p
->protocols
)
2121 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
2124 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
2125 stream_putc(s
, p
->count
);
2126 stream_put(s
, p
->protocols
, p
->count
);
2130 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
2131 uint8_t tlv_type
, uint8_t tlv_len
,
2132 struct stream
*s
, struct sbuf
*log
,
2133 void *dest
, int indent
)
2135 struct isis_tlvs
*tlvs
= dest
;
2137 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
2139 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
2142 if (tlvs
->protocols_supported
.protocols
) {
2145 "WARNING: protocols supported TLV present multiple times.\n");
2146 stream_forward_getp(s
, tlv_len
);
2150 tlvs
->protocols_supported
.count
= tlv_len
;
2151 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
2152 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
2154 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
, NULL
,
2159 /* Functions related to TLV 132 IPv4 Interface addresses */
2160 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
2162 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2163 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2166 return (struct isis_item
*)rv
;
2169 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
2170 struct sbuf
*buf
, struct json_object
*json
,
2173 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2174 char addrbuf
[INET_ADDRSTRLEN
];
2176 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2178 json_object_string_add(json
, "ipv4", addrbuf
);
2180 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
2184 static void free_item_ipv4_address(struct isis_item
*i
)
2186 XFREE(MTYPE_ISIS_TLV
, i
);
2189 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
2192 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2194 if (STREAM_WRITEABLE(s
) < 4) {
2199 stream_put(s
, &a
->addr
, 4);
2204 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
2205 struct stream
*s
, struct sbuf
*log
,
2206 void *dest
, int indent
)
2208 struct isis_tlvs
*tlvs
= dest
;
2210 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
2214 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2219 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2220 stream_get(&rv
->addr
, s
, 4);
2222 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2223 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
2228 /* Functions related to TLV 232 IPv6 Interface addresses */
2229 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
2231 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2232 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2235 return (struct isis_item
*)rv
;
2238 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2239 struct sbuf
*buf
, struct json_object
*json
,
2242 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2243 char addrbuf
[INET6_ADDRSTRLEN
];
2245 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2247 json_object_string_add(json
, "ipv6", addrbuf
);
2249 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
2252 static void free_item_ipv6_address(struct isis_item
*i
)
2254 XFREE(MTYPE_ISIS_TLV
, i
);
2257 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2260 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2262 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2263 *min_len
= IPV6_MAX_BYTELEN
;
2267 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2272 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
2273 struct stream
*s
, struct sbuf
*log
,
2274 void *dest
, int indent
)
2276 struct isis_tlvs
*tlvs
= dest
;
2278 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
2282 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2287 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2288 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2290 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2291 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
2296 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2297 static struct isis_item
*copy_item_global_ipv6_address(struct isis_item
*i
)
2299 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2300 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2303 return (struct isis_item
*)rv
;
2306 static void format_item_global_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2308 struct json_object
*json
,
2311 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2312 char addrbuf
[INET6_ADDRSTRLEN
];
2314 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2316 json_object_string_add(json
, "global-ipv6", addrbuf
);
2318 sbuf_push(buf
, indent
, "Global IPv6 Interface Address: %s\n",
2322 static void free_item_global_ipv6_address(struct isis_item
*i
)
2324 XFREE(MTYPE_ISIS_TLV
, i
);
2327 static int pack_item_global_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2330 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2332 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2333 *min_len
= IPV6_MAX_BYTELEN
;
2337 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2342 static int unpack_item_global_ipv6_address(uint16_t mtid
, uint8_t len
,
2343 struct stream
*s
, struct sbuf
*log
,
2344 void *dest
, int indent
)
2346 struct isis_tlvs
*tlvs
= dest
;
2348 sbuf_push(log
, indent
, "Unpack Global IPv6 Interface address...\n");
2349 if (len
< IPV6_MAX_BYTELEN
) {
2352 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2357 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2358 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2360 format_item_global_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2362 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)rv
);
2366 /* Functions related to TLV 229 MT Router information */
2367 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
2369 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2370 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2372 rv
->overload
= info
->overload
;
2373 rv
->attached
= info
->attached
;
2374 rv
->mtid
= info
->mtid
;
2375 return (struct isis_item
*)rv
;
2378 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
2380 struct json_object
*json
, int indent
)
2382 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2385 struct json_object
*mt_json
;
2386 mt_json
= json_object_new_object();
2387 json_object_object_add(json
, "mt", mt_json
);
2388 json_object_int_add(mt_json
, "mtid", info
->mtid
);
2389 json_object_string_add(mt_json
, "overload", info
->overload
?"true":"false");
2390 json_object_string_add(mt_json
, "attached", info
->attached
?"true":"false");
2392 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
2393 isis_mtid2str(info
->mtid
),
2394 info
->overload
? " Overload" : "",
2395 info
->attached
? " Attached" : "");
2398 static void free_item_mt_router_info(struct isis_item
*i
)
2400 XFREE(MTYPE_ISIS_TLV
, i
);
2403 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
2406 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2408 if (STREAM_WRITEABLE(s
) < 2) {
2413 uint16_t entry
= info
->mtid
;
2416 entry
|= ISIS_MT_OL_MASK
;
2418 entry
|= ISIS_MT_AT_MASK
;
2420 stream_putw(s
, entry
);
2425 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
2426 struct stream
*s
, struct sbuf
*log
,
2427 void *dest
, int indent
)
2429 struct isis_tlvs
*tlvs
= dest
;
2431 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
2435 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2440 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2442 uint16_t entry
= stream_getw(s
);
2443 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
2444 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
2445 rv
->mtid
= entry
& ISIS_MT_MASK
;
2447 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2449 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
2453 /* Functions related to TLV 134 TE Router ID */
2455 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
2460 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2461 memcpy(rv
, id
, sizeof(*rv
));
2465 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
2466 struct json_object
*json
, int indent
)
2471 char addrbuf
[INET_ADDRSTRLEN
];
2472 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
2474 json_object_string_add(json
, "te-router-id", addrbuf
);
2476 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
2479 static void free_tlv_te_router_id(struct in_addr
*id
)
2481 XFREE(MTYPE_ISIS_TLV
, id
);
2484 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
2489 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2492 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
2494 stream_put(s
, id
, 4);
2498 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
2499 uint8_t tlv_type
, uint8_t tlv_len
,
2500 struct stream
*s
, struct sbuf
*log
,
2501 void *dest
, int indent
)
2503 struct isis_tlvs
*tlvs
= dest
;
2505 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
2507 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2511 if (tlvs
->te_router_id
) {
2512 sbuf_push(log
, indent
,
2513 "WARNING: TE Router ID present multiple times.\n");
2514 stream_forward_getp(s
, tlv_len
);
2518 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
2519 stream_get(tlvs
->te_router_id
, s
, 4);
2520 format_tlv_te_router_id(tlvs
->te_router_id
, log
, NULL
, indent
+ 2);
2525 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
2527 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
2529 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2530 struct isis_extended_ip_reach
*rv
=
2531 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2533 rv
->metric
= r
->metric
;
2535 rv
->prefix
= r
->prefix
;
2536 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2538 return (struct isis_item
*)rv
;
2541 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2543 struct json_object
*json
, int indent
)
2545 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2546 char prefixbuf
[PREFIX2STR_BUFFER
];
2549 struct json_object
*ext_json
;
2550 ext_json
= json_object_new_object();
2551 json_object_object_add(json
, "ext-ip-reach", ext_json
);
2552 json_object_string_add(
2554 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
2555 json_object_string_add(
2557 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2558 json_object_int_add(json
, "ip-reach-metric", r
->metric
);
2559 json_object_string_add(json
, "down", r
->down
? "yes" : "");
2560 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2561 json_object_string_add(json
, "mt-name",
2562 isis_mtid2str(mtid
));
2564 struct json_object
*subtlv_json
;
2565 subtlv_json
= json_object_new_object();
2566 json_object_object_add(json
, "subtlvs", subtlv_json
);
2567 format_subtlvs(r
->subtlvs
, NULL
, subtlv_json
, 0);
2570 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
2571 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2572 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2573 r
->metric
, r
->down
? " Down" : "");
2574 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2575 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2576 sbuf_push(buf
, 0, "\n");
2579 sbuf_push(buf
, indent
, " Subtlvs:\n");
2580 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
2585 static void free_item_extended_ip_reach(struct isis_item
*i
)
2587 struct isis_extended_ip_reach
*item
=
2588 (struct isis_extended_ip_reach
*)i
;
2589 isis_free_subtlvs(item
->subtlvs
);
2590 XFREE(MTYPE_ISIS_TLV
, item
);
2593 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
2596 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2599 if (STREAM_WRITEABLE(s
) < 5) {
2603 stream_putl(s
, r
->metric
);
2605 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
2606 control
|= r
->prefix
.prefixlen
;
2607 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
2609 stream_putc(s
, control
);
2611 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2612 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2615 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2618 return pack_subtlvs(r
->subtlvs
, s
);
2622 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2623 struct stream
*s
, struct sbuf
*log
,
2624 void *dest
, int indent
)
2626 struct isis_tlvs
*tlvs
= dest
;
2627 struct isis_extended_ip_reach
*rv
= NULL
;
2629 uint8_t control
, subtlv_len
;
2630 struct isis_item_list
*items
;
2632 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2633 items
= &tlvs
->extended_ip_reach
;
2635 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2638 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2639 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2642 if (len
< consume
) {
2643 sbuf_push(log
, indent
,
2644 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2649 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2651 rv
->metric
= stream_getl(s
);
2652 control
= stream_getc(s
);
2653 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2654 rv
->prefix
.family
= AF_INET
;
2655 rv
->prefix
.prefixlen
= control
& 0x3f;
2656 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
2657 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2658 rv
->prefix
.prefixlen
);
2662 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2663 if (len
< consume
) {
2664 sbuf_push(log
, indent
,
2665 "Expected %u bytes of prefix, but only %u bytes available.\n",
2666 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2669 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2670 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2671 apply_mask_ipv4(&rv
->prefix
);
2672 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2673 sbuf_push(log
, indent
+ 2,
2674 "WARNING: Prefix had hostbits set.\n");
2675 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2678 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2680 if (len
< consume
) {
2681 sbuf_push(log
, indent
,
2682 "Expected 1 byte of subtlv len, but no more data present.\n");
2685 subtlv_len
= stream_getc(s
);
2688 sbuf_push(log
, indent
+ 2,
2689 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2691 consume
+= subtlv_len
;
2692 if (len
< consume
) {
2693 sbuf_push(log
, indent
,
2694 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2696 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2700 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2701 bool unpacked_known_tlvs
= false;
2703 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2704 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2707 if (!unpacked_known_tlvs
) {
2708 isis_free_subtlvs(rv
->subtlvs
);
2713 append_item(items
, (struct isis_item
*)rv
);
2717 free_item_extended_ip_reach((struct isis_item
*)rv
);
2721 /* Functions related to TLV 137 Dynamic Hostname */
2723 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2728 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2731 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2732 struct json_object
*json
, int indent
)
2738 json_object_string_add(json
, "hostname", hostname
);
2740 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2743 static void free_tlv_dynamic_hostname(char *hostname
)
2745 XFREE(MTYPE_ISIS_TLV
, hostname
);
2748 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2753 uint8_t name_len
= strlen(hostname
);
2755 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2758 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2759 stream_putc(s
, name_len
);
2760 stream_put(s
, hostname
, name_len
);
2764 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2765 uint8_t tlv_type
, uint8_t tlv_len
,
2766 struct stream
*s
, struct sbuf
*log
,
2767 void *dest
, int indent
)
2769 struct isis_tlvs
*tlvs
= dest
;
2771 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2773 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2777 if (tlvs
->hostname
) {
2778 sbuf_push(log
, indent
,
2779 "WARNING: Hostname present multiple times.\n");
2780 stream_forward_getp(s
, tlv_len
);
2784 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2785 stream_get(tlvs
->hostname
, s
, tlv_len
);
2786 tlvs
->hostname
[tlv_len
] = '\0';
2789 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2790 if ((unsigned char)tlvs
->hostname
[i
] > 127
2791 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2793 tlvs
->hostname
[i
] = '?';
2799 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2805 /* Functions related to TLV 140 IPv6 TE Router ID */
2807 static struct in6_addr
*copy_tlv_te_router_id_ipv6(const struct in6_addr
*id
)
2812 struct in6_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2813 memcpy(rv
, id
, sizeof(*rv
));
2817 static void format_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2819 struct json_object
*json
, int indent
)
2824 char addrbuf
[INET6_ADDRSTRLEN
];
2825 inet_ntop(AF_INET6
, id
, addrbuf
, sizeof(addrbuf
));
2827 json_object_string_add(json
, "ipv6-te-router-id", addrbuf
);
2829 sbuf_push(buf
, indent
, "IPv6 TE Router ID: %s\n", addrbuf
);
2832 static void free_tlv_te_router_id_ipv6(struct in6_addr
*id
)
2834 XFREE(MTYPE_ISIS_TLV
, id
);
2837 static int pack_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2843 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2846 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID_IPV6
);
2847 stream_putc(s
, IPV6_MAX_BYTELEN
);
2848 stream_put(s
, id
, IPV6_MAX_BYTELEN
);
2852 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context
,
2853 uint8_t tlv_type
, uint8_t tlv_len
,
2854 struct stream
*s
, struct sbuf
*log
,
2855 void *dest
, int indent
)
2857 struct isis_tlvs
*tlvs
= dest
;
2859 sbuf_push(log
, indent
, "Unpacking IPv6 TE Router ID TLV...\n");
2860 if (tlv_len
!= IPV6_MAX_BYTELEN
) {
2861 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2865 if (tlvs
->te_router_id_ipv6
) {
2868 "WARNING: IPv6 TE Router ID present multiple times.\n");
2869 stream_forward_getp(s
, tlv_len
);
2873 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, IPV6_MAX_BYTELEN
);
2874 stream_get(tlvs
->te_router_id_ipv6
, s
, IPV6_MAX_BYTELEN
);
2875 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, log
, NULL
, indent
+ 2);
2880 /* Functions related to TLV 150 Spine-Leaf-Extension */
2882 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2883 const struct isis_spine_leaf
*spine_leaf
)
2888 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2889 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2894 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2895 struct sbuf
*buf
, struct json_object
*json
,
2904 struct json_object
*spine_json
;
2905 spine_json
= json_object_new_object();
2906 json_object_object_add(json
, "spine-leaf-extension",
2908 if (spine_leaf
->has_tier
) {
2909 snprintfrr(aux_buf
, sizeof(aux_buf
), "%hhu",
2911 json_object_string_add(
2913 (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
)
2917 json_object_string_add(spine_json
, "flag-leaf",
2918 spine_leaf
->is_leaf
? "yes" : "");
2919 json_object_string_add(spine_json
, "flag-spine",
2920 spine_leaf
->is_spine
? "yes" : "");
2921 json_object_string_add(spine_json
, "flag-backup",
2922 spine_leaf
->is_backup
? "yes" : "");
2924 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2925 if (spine_leaf
->has_tier
) {
2926 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2927 sbuf_push(buf
, indent
, " Tier: undefined\n");
2929 sbuf_push(buf
, indent
, " Tier: %hhu\n",
2934 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2935 spine_leaf
->is_leaf
? " LEAF" : "",
2936 spine_leaf
->is_spine
? " SPINE" : "",
2937 spine_leaf
->is_backup
? " BACKUP" : "");
2941 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2943 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2946 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2947 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2948 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2949 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2951 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2957 uint8_t tlv_len
= 2;
2959 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2962 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2963 stream_putc(s
, tlv_len
);
2965 uint16_t spine_leaf_flags
= 0;
2967 if (spine_leaf
->has_tier
) {
2968 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2969 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2972 if (spine_leaf
->is_leaf
)
2973 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2975 if (spine_leaf
->is_spine
)
2976 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
2978 if (spine_leaf
->is_backup
)
2979 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
2981 stream_putw(s
, spine_leaf_flags
);
2986 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
2987 uint8_t tlv_type
, uint8_t tlv_len
,
2988 struct stream
*s
, struct sbuf
*log
,
2989 void *dest
, int indent
)
2991 struct isis_tlvs
*tlvs
= dest
;
2993 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
2995 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2996 stream_forward_getp(s
, tlv_len
);
3000 if (tlvs
->spine_leaf
) {
3001 sbuf_push(log
, indent
,
3002 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3003 stream_forward_getp(s
, tlv_len
);
3007 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3009 uint16_t spine_leaf_flags
= stream_getw(s
);
3011 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
3012 tlvs
->spine_leaf
->has_tier
= true;
3013 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
3016 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
3017 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
3018 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
3020 stream_forward_getp(s
, tlv_len
- 2);
3024 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3026 const char *isis_threeway_state_name(enum isis_threeway_state state
)
3029 case ISIS_THREEWAY_DOWN
:
3031 case ISIS_THREEWAY_INITIALIZING
:
3032 return "Initializing";
3033 case ISIS_THREEWAY_UP
:
3040 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
3041 const struct isis_threeway_adj
*threeway_adj
)
3046 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3047 memcpy(rv
, threeway_adj
, sizeof(*rv
));
3053 format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3054 struct sbuf
*buf
, struct json_object
*json
, int indent
)
3060 struct json_object
*three_json
;
3061 three_json
= json_object_new_object();
3062 json_object_object_add(json
, "p2p-three-way-adj", three_json
);
3063 json_object_string_add(
3064 three_json
, "state-name",
3065 isis_threeway_state_name(threeway_adj
->state
));
3066 json_object_int_add(three_json
, "state", threeway_adj
->state
);
3067 json_object_int_add(three_json
, "ext-local-circuit-id",
3068 threeway_adj
->local_circuit_id
);
3069 if (!threeway_adj
->neighbor_set
)
3071 json_object_string_add(
3072 three_json
, "neigh-system-id",
3073 isis_format_id(threeway_adj
->neighbor_id
, 6));
3074 json_object_int_add(three_json
, "neigh-ext-circuit-id",
3075 threeway_adj
->neighbor_circuit_id
);
3077 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
3078 sbuf_push(buf
, indent
, " State: %s (%d)\n",
3079 isis_threeway_state_name(threeway_adj
->state
),
3080 threeway_adj
->state
);
3081 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
3082 threeway_adj
->local_circuit_id
);
3083 if (!threeway_adj
->neighbor_set
)
3086 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
3087 isis_format_id(threeway_adj
->neighbor_id
, 6));
3088 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
3089 threeway_adj
->neighbor_circuit_id
);
3093 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
3095 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
3098 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3104 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
3106 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3109 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
3110 stream_putc(s
, tlv_len
);
3111 stream_putc(s
, threeway_adj
->state
);
3112 stream_putl(s
, threeway_adj
->local_circuit_id
);
3114 if (threeway_adj
->neighbor_set
) {
3115 stream_put(s
, threeway_adj
->neighbor_id
, 6);
3116 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
3122 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
3123 uint8_t tlv_type
, uint8_t tlv_len
,
3124 struct stream
*s
, struct sbuf
*log
,
3125 void *dest
, int indent
)
3127 struct isis_tlvs
*tlvs
= dest
;
3129 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
3130 if (tlv_len
!= 5 && tlv_len
!= 15) {
3131 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3132 stream_forward_getp(s
, tlv_len
);
3136 if (tlvs
->threeway_adj
) {
3137 sbuf_push(log
, indent
,
3138 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3139 stream_forward_getp(s
, tlv_len
);
3143 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3145 tlvs
->threeway_adj
->state
= stream_getc(s
);
3146 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
3148 if (tlv_len
== 15) {
3149 tlvs
->threeway_adj
->neighbor_set
= true;
3150 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
3151 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
3157 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3158 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
3160 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3161 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3163 rv
->metric
= r
->metric
;
3165 rv
->external
= r
->external
;
3166 rv
->prefix
= r
->prefix
;
3167 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3169 return (struct isis_item
*)rv
;
3172 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
3173 struct sbuf
*buf
, struct json_object
*json
,
3176 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3177 char prefixbuf
[PREFIX2STR_BUFFER
];
3180 struct json_object
*reach_json
;
3181 reach_json
= json_object_new_object();
3182 json_object_object_add(json
, "ipv6-reach", reach_json
);
3183 json_object_string_add(reach_json
, "mt-id",
3184 (mtid
== ISIS_MT_IPV4_UNICAST
) ? ""
3186 json_object_string_add(
3187 reach_json
, "prefix",
3188 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3189 json_object_int_add(reach_json
, "metric", r
->metric
);
3190 json_object_string_add(reach_json
, "down",
3191 r
->down
? "yes" : "");
3192 json_object_string_add(reach_json
, "external",
3193 r
->external
? "yes" : "");
3194 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3195 json_object_string_add(reach_json
, "mt-name",
3196 isis_mtid2str(mtid
));
3198 struct json_object
*subtlvs_json
;
3199 subtlvs_json
= json_object_new_object();
3200 json_object_object_add(json
, "subtlvs", subtlvs_json
);
3201 format_subtlvs(r
->subtlvs
, NULL
, subtlvs_json
, 0);
3204 sbuf_push(buf
, indent
,
3205 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3206 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
3207 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3208 r
->metric
, r
->down
? " Down" : "",
3209 r
->external
? " External" : "");
3210 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3211 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3212 sbuf_push(buf
, 0, "\n");
3215 sbuf_push(buf
, indent
, " Subtlvs:\n");
3216 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3221 static void free_item_ipv6_reach(struct isis_item
*i
)
3223 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
3225 isis_free_subtlvs(item
->subtlvs
);
3226 XFREE(MTYPE_ISIS_TLV
, item
);
3229 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
3232 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3235 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3236 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3239 stream_putl(s
, r
->metric
);
3241 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
3242 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
3243 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
3245 stream_putc(s
, control
);
3246 stream_putc(s
, r
->prefix
.prefixlen
);
3248 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
3251 return pack_subtlvs(r
->subtlvs
, s
);
3256 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3257 struct sbuf
*log
, void *dest
, int indent
)
3259 struct isis_tlvs
*tlvs
= dest
;
3260 struct isis_ipv6_reach
*rv
= NULL
;
3262 uint8_t control
, subtlv_len
;
3263 struct isis_item_list
*items
;
3265 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3266 items
= &tlvs
->ipv6_reach
;
3268 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3271 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
3272 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
3274 if (len
< consume
) {
3275 sbuf_push(log
, indent
,
3276 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3281 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3283 rv
->metric
= stream_getl(s
);
3284 control
= stream_getc(s
);
3285 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
3286 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
3288 rv
->prefix
.family
= AF_INET6
;
3289 rv
->prefix
.prefixlen
= stream_getc(s
);
3290 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
3291 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
3292 rv
->prefix
.prefixlen
);
3296 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3297 if (len
< consume
) {
3298 sbuf_push(log
, indent
,
3299 "Expected %u bytes of prefix, but only %u bytes available.\n",
3300 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
3303 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3304 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
3306 apply_mask_ipv6(&rv
->prefix
);
3307 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
3308 sbuf_push(log
, indent
+ 2,
3309 "WARNING: Prefix had hostbits set.\n");
3310 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3312 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
3314 if (len
< consume
) {
3315 sbuf_push(log
, indent
,
3316 "Expected 1 byte of subtlv len, but no more data persent.\n");
3319 subtlv_len
= stream_getc(s
);
3322 sbuf_push(log
, indent
+ 2,
3323 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3325 consume
+= subtlv_len
;
3326 if (len
< consume
) {
3327 sbuf_push(log
, indent
,
3328 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3330 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3334 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3335 bool unpacked_known_tlvs
= false;
3337 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
3338 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3341 if (!unpacked_known_tlvs
) {
3342 isis_free_subtlvs(rv
->subtlvs
);
3347 append_item(items
, (struct isis_item
*)rv
);
3351 free_item_ipv6_reach((struct isis_item
*)rv
);
3355 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3356 static struct isis_router_cap
*copy_tlv_router_cap(
3357 const struct isis_router_cap
*router_cap
)
3359 struct isis_router_cap
*rv
;
3364 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3366 memcpy(rv
, router_cap
, sizeof(*rv
));
3371 static void format_tlv_router_cap_json(const struct isis_router_cap
*router_cap
,
3372 struct json_object
*json
)
3374 char addrbuf
[INET_ADDRSTRLEN
];
3379 /* Router ID and Flags */
3380 struct json_object
*cap_json
;
3381 cap_json
= json_object_new_object();
3382 json_object_object_add(json
, "router-capability", cap_json
);
3383 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3384 json_object_string_add(cap_json
, "id", addrbuf
);
3385 json_object_string_add(
3387 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? "1" : "0");
3388 json_object_string_add(
3390 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? "1" : "0");
3392 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3393 if (router_cap
->srgb
.range_size
!= 0) {
3394 struct json_object
*gb_json
;
3395 gb_json
= json_object_new_object();
3396 json_object_object_add(json
, "segment-routing-gb", gb_json
);
3397 json_object_string_add(gb_json
, "ipv4",
3398 IS_SR_IPV4(&router_cap
->srgb
) ? "1"
3400 json_object_string_add(gb_json
, "ipv6",
3401 IS_SR_IPV6(&router_cap
->srgb
) ? "1"
3403 json_object_int_add(gb_json
, "global-block-base",
3404 router_cap
->srgb
.lower_bound
);
3405 json_object_int_add(gb_json
, "global-block-range",
3406 router_cap
->srgb
.range_size
);
3409 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3410 if (router_cap
->srlb
.range_size
!= 0) {
3411 struct json_object
*lb_json
;
3412 lb_json
= json_object_new_object();
3413 json_object_object_add(json
, "segment-routing-lb", lb_json
);
3414 json_object_int_add(lb_json
, "global-block-base",
3415 router_cap
->srlb
.lower_bound
);
3416 json_object_int_add(lb_json
, "global-block-range",
3417 router_cap
->srlb
.range_size
);
3420 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3421 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3423 struct json_object
*alg_json
;
3424 alg_json
= json_object_new_object();
3425 json_object_object_add(json
, "segment-routing-algorithm",
3427 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3428 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
) {
3429 snprintfrr(buf
, sizeof(buf
), "%d", i
);
3430 json_object_string_add(alg_json
, buf
,
3431 router_cap
->algo
[i
] == 0
3437 /* Segment Routing Node MSD as per RFC8491 section #2 */
3438 if (router_cap
->msd
!= 0)
3439 json_object_int_add(json
, "msd", router_cap
->msd
);
3442 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3443 struct sbuf
*buf
, int indent
)
3445 char addrbuf
[INET_ADDRSTRLEN
];
3450 /* Router ID and Flags */
3451 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3452 sbuf_push(buf
, indent
, "Router Capability:");
3453 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
3454 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
3455 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
3457 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3458 if (router_cap
->srgb
.range_size
!= 0)
3461 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
3462 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
3463 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
3464 router_cap
->srgb
.lower_bound
,
3465 router_cap
->srgb
.range_size
);
3467 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3468 if (router_cap
->srlb
.range_size
!= 0)
3469 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
3470 router_cap
->srlb
.lower_bound
,
3471 router_cap
->srlb
.range_size
);
3473 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3474 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3475 sbuf_push(buf
, indent
, " SR Algorithm:\n");
3476 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3477 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
3478 sbuf_push(buf
, indent
, " %u: %s\n", i
,
3479 router_cap
->algo
[i
] == 0
3484 /* Segment Routing Node MSD as per RFC8491 section #2 */
3485 if (router_cap
->msd
!= 0)
3486 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
3490 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
3492 XFREE(MTYPE_ISIS_TLV
, router_cap
);
3495 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3498 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
3505 /* Compute Maximum TLV size */
3506 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
3507 + ISIS_SUBTLV_HDR_SIZE
3508 + ISIS_SUBTLV_ALGORITHM_SIZE
3509 + ISIS_SUBTLV_NODE_MSD_SIZE
;
3511 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
3514 /* Add Router Capability TLV 242 with Router ID and Flags */
3515 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
3516 /* Real length will be adjusted later */
3517 len_pos
= stream_get_endp(s
);
3518 stream_putc(s
, tlv_len
);
3519 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
3520 stream_putc(s
, router_cap
->flags
);
3522 /* Add SRGB if set as per RFC8667 section #3.1 */
3523 if ((router_cap
->srgb
.range_size
!= 0)
3524 && (router_cap
->srgb
.lower_bound
!= 0)) {
3525 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
3526 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3527 stream_putc(s
, router_cap
->srgb
.flags
);
3528 stream_put3(s
, router_cap
->srgb
.range_size
);
3529 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3530 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3531 stream_put3(s
, router_cap
->srgb
.lower_bound
);
3533 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
3534 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
3535 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
3538 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
3539 stream_putc(s
, nb_algo
);
3540 for (int i
= 0; i
< nb_algo
; i
++)
3541 stream_putc(s
, router_cap
->algo
[i
]);
3544 /* Local Block if defined as per RFC8667 section #3.3 */
3545 if ((router_cap
->srlb
.range_size
!= 0)
3546 && (router_cap
->srlb
.lower_bound
!= 0)) {
3547 stream_putc(s
, ISIS_SUBTLV_SRLB
);
3548 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3549 /* No Flags are defined for SRLB */
3551 stream_put3(s
, router_cap
->srlb
.range_size
);
3552 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3553 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3554 stream_put3(s
, router_cap
->srlb
.lower_bound
);
3557 /* And finish with MSD if set as per RFC8491 section #2 */
3558 if (router_cap
->msd
!= 0) {
3559 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
3560 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
3561 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
3562 stream_putc(s
, router_cap
->msd
);
3566 /* Adjust TLV length which depends on subTLVs presence */
3567 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
3568 stream_putc_at(s
, len_pos
, tlv_len
);
3573 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
3574 uint8_t tlv_type
, uint8_t tlv_len
,
3575 struct stream
*s
, struct sbuf
*log
,
3576 void *dest
, int indent
)
3578 struct isis_tlvs
*tlvs
= dest
;
3579 struct isis_router_cap
*rcap
;
3585 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
3586 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
3587 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3588 stream_forward_getp(s
, tlv_len
);
3592 if (tlvs
->router_cap
) {
3593 sbuf_push(log
, indent
,
3594 "WARNING: Router Capability TLV present multiple times.\n");
3595 stream_forward_getp(s
, tlv_len
);
3599 /* Allocate router cap structure and initialize SR Algorithms */
3600 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
3601 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3602 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
3604 /* Get Router ID and Flags */
3605 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
3606 rcap
->flags
= stream_getc(s
);
3608 /* Parse remaining part of the TLV if present */
3609 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
3610 while (subtlv_len
> 2) {
3613 type
= stream_getc(s
);
3614 length
= stream_getc(s
);
3616 if (length
> STREAM_READABLE(s
) || length
> subtlv_len
- 2) {
3619 "WARNING: Router Capability subTLV length too large compared to expected size\n");
3620 stream_forward_getp(s
, STREAM_READABLE(s
));
3626 case ISIS_SUBTLV_SID_LABEL_RANGE
:
3627 /* Check that SRGB is correctly formated */
3628 if (length
< SUBTLV_RANGE_LABEL_SIZE
3629 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3630 stream_forward_getp(s
, length
);
3633 /* Only one SRGB is supported. Skip subsequent one */
3634 if (rcap
->srgb
.range_size
!= 0) {
3635 stream_forward_getp(s
, length
);
3638 rcap
->srgb
.flags
= stream_getc(s
);
3639 rcap
->srgb
.range_size
= stream_get3(s
);
3640 /* Skip Type and get Length of SID Label */
3642 size
= stream_getc(s
);
3644 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3645 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3646 stream_forward_getp(s
, length
- 6);
3650 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3651 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3652 stream_forward_getp(s
, length
- 6);
3656 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3657 rcap
->srgb
.lower_bound
= stream_get3(s
);
3658 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3659 rcap
->srgb
.lower_bound
= stream_getl(s
);
3661 stream_forward_getp(s
, length
- 6);
3665 /* SRGB sanity checks. */
3666 if (rcap
->srgb
.range_size
== 0
3667 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3668 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
3669 > MPLS_LABEL_UNRESERVED_MAX
)) {
3670 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
3671 rcap
->srgb
.lower_bound
= 0;
3672 rcap
->srgb
.range_size
= 0;
3674 /* Only one range is supported. Skip subsequent one */
3675 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3677 stream_forward_getp(s
, size
);
3680 case ISIS_SUBTLV_ALGORITHM
:
3683 /* Only 2 algorithms are supported: SPF & Strict SPF */
3684 stream_get(&rcap
->algo
, s
,
3685 length
> SR_ALGORITHM_COUNT
3686 ? SR_ALGORITHM_COUNT
3688 if (length
> SR_ALGORITHM_COUNT
)
3689 stream_forward_getp(
3690 s
, length
- SR_ALGORITHM_COUNT
);
3692 case ISIS_SUBTLV_SRLB
:
3693 /* Check that SRLB is correctly formated */
3694 if (length
< SUBTLV_RANGE_LABEL_SIZE
3695 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3696 stream_forward_getp(s
, length
);
3699 /* RFC 8667 section #3.3: Only one SRLB is authorized */
3700 if (rcap
->srlb
.range_size
!= 0) {
3701 stream_forward_getp(s
, length
);
3704 /* Ignore Flags which are not defined */
3706 rcap
->srlb
.range_size
= stream_get3(s
);
3707 /* Skip Type and get Length of SID Label */
3709 size
= stream_getc(s
);
3711 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3712 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3713 stream_forward_getp(s
, length
- 6);
3717 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3718 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3719 stream_forward_getp(s
, length
- 6);
3723 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3724 rcap
->srlb
.lower_bound
= stream_get3(s
);
3725 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3726 rcap
->srlb
.lower_bound
= stream_getl(s
);
3728 stream_forward_getp(s
, length
- 6);
3732 /* SRLB sanity checks. */
3733 if (rcap
->srlb
.range_size
== 0
3734 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3735 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
3736 > MPLS_LABEL_UNRESERVED_MAX
)) {
3737 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
3738 rcap
->srlb
.lower_bound
= 0;
3739 rcap
->srlb
.range_size
= 0;
3741 /* Only one range is supported. Skip subsequent one */
3742 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3744 stream_forward_getp(s
, size
);
3747 case ISIS_SUBTLV_NODE_MSD
:
3748 /* Check that MSD is correctly formated */
3749 if (length
< MSD_TLV_SIZE
) {
3750 stream_forward_getp(s
, length
);
3753 msd_type
= stream_getc(s
);
3754 rcap
->msd
= stream_getc(s
);
3755 /* Only BMI-MSD type has been defined in RFC 8491 */
3756 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
3758 /* Only one MSD is standardized. Skip others */
3759 if (length
> MSD_TLV_SIZE
)
3760 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
3763 stream_forward_getp(s
, length
);
3766 subtlv_len
= subtlv_len
- length
- 2;
3768 tlvs
->router_cap
= rcap
;
3772 /* Functions related to TLV 10 Authentication */
3773 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
3775 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3776 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3778 rv
->type
= auth
->type
;
3779 rv
->length
= auth
->length
;
3780 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
3781 return (struct isis_item
*)rv
;
3784 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
3785 struct sbuf
*buf
, struct json_object
*json
,
3788 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3792 json_object_string_add(json
, "test-auth", "ok");
3794 sbuf_push(buf
, indent
, "Authentication:\n");
3795 switch (auth
->type
) {
3796 case ISIS_PASSWD_TYPE_CLEARTXT
:
3797 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
3799 json_object_string_add(json
, "auth-pass", obuf
);
3801 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
3803 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3804 for (unsigned int j
= 0; j
< 16; j
++) {
3805 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
, "%02hhx",
3809 json_object_string_add(json
, "auth-hmac-md5", obuf
);
3811 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
3815 json_object_int_add(json
, "auth-unknown", auth
->type
);
3817 sbuf_push(buf
, indent
, " Unknown (%hhu)\n",
3823 static void free_item_auth(struct isis_item
*i
)
3825 XFREE(MTYPE_ISIS_TLV
, i
);
3828 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
3831 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3833 if (STREAM_WRITEABLE(s
) < 1) {
3837 stream_putc(s
, auth
->type
);
3839 switch (auth
->type
) {
3840 case ISIS_PASSWD_TYPE_CLEARTXT
:
3841 if (STREAM_WRITEABLE(s
) < auth
->length
) {
3842 *min_len
= 1 + auth
->length
;
3845 stream_put(s
, auth
->passwd
, auth
->length
);
3847 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3848 if (STREAM_WRITEABLE(s
) < 16) {
3852 auth
->offset
= stream_get_endp(s
);
3853 stream_put(s
, NULL
, 16);
3862 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3863 struct sbuf
*log
, void *dest
, int indent
)
3865 struct isis_tlvs
*tlvs
= dest
;
3867 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
3871 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
3876 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3878 rv
->type
= stream_getc(s
);
3879 rv
->length
= len
- 1;
3881 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
3884 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
3886 XFREE(MTYPE_ISIS_TLV
, rv
);
3890 rv
->offset
= stream_get_getp(s
);
3891 stream_get(rv
->value
, s
, rv
->length
);
3892 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3893 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
3897 /* Functions related to TLV 13 Purge Originator */
3899 static struct isis_purge_originator
*copy_tlv_purge_originator(
3900 struct isis_purge_originator
*poi
)
3905 struct isis_purge_originator
*rv
;
3907 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3908 rv
->sender_set
= poi
->sender_set
;
3909 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3910 if (poi
->sender_set
)
3911 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
3915 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
3917 struct json_object
*json
, int indent
)
3923 struct json_object
*purge_json
;
3924 purge_json
= json_object_new_object();
3925 json_object_object_add(json
, "purge_originator", purge_json
);
3927 json_object_string_add(
3929 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3930 if (poi
->sender_set
) {
3931 json_object_string_add(
3932 purge_json
, "rec-from",
3933 isis_format_id(poi
->sender
,
3934 sizeof(poi
->sender
)));
3937 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
3939 buf
, indent
, " Generator: %s\n",
3940 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3941 if (poi
->sender_set
) {
3942 sbuf_push(buf
, indent
, " Received-From: %s\n",
3943 isis_format_id(poi
->sender
,
3944 sizeof(poi
->sender
)));
3949 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
3951 XFREE(MTYPE_ISIS_TLV
, poi
);
3954 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
3960 uint8_t data_len
= 1 + sizeof(poi
->generator
);
3962 if (poi
->sender_set
)
3963 data_len
+= sizeof(poi
->sender
);
3965 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
3968 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
3969 stream_putc(s
, data_len
);
3970 stream_putc(s
, poi
->sender_set
? 2 : 1);
3971 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
3972 if (poi
->sender_set
)
3973 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
3977 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
3978 uint8_t tlv_type
, uint8_t tlv_len
,
3979 struct stream
*s
, struct sbuf
*log
,
3980 void *dest
, int indent
)
3982 struct isis_tlvs
*tlvs
= dest
;
3983 struct isis_purge_originator poi
= {};
3985 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
3987 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
3991 uint8_t number_of_ids
= stream_getc(s
);
3993 if (number_of_ids
== 1) {
3994 poi
.sender_set
= false;
3995 } else if (number_of_ids
== 2) {
3996 poi
.sender_set
= true;
3998 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
4002 if (tlv_len
!= 1 + 6 * number_of_ids
) {
4003 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
4007 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
4009 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
4011 if (tlvs
->purge_originator
) {
4012 sbuf_push(log
, indent
,
4013 "WARNING: Purge originator present multiple times, ignoring.\n");
4017 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
4022 /* Functions relating to item TLVs */
4024 static void init_item_list(struct isis_item_list
*items
)
4027 items
->tail
= &items
->head
;
4031 static struct isis_item
*copy_item(enum isis_tlv_context context
,
4032 enum isis_tlv_type type
,
4033 struct isis_item
*item
)
4035 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4037 if (ops
&& ops
->copy_item
)
4038 return ops
->copy_item(item
);
4040 assert(!"Unknown item tlv type!");
4044 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4045 struct isis_item_list
*src
, struct isis_item_list
*dest
)
4047 struct isis_item
*item
;
4049 init_item_list(dest
);
4051 for (item
= src
->head
; item
; item
= item
->next
) {
4052 append_item(dest
, copy_item(context
, type
, item
));
4056 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
4057 enum isis_tlv_type type
, struct isis_item
*i
,
4058 struct sbuf
*buf
, struct json_object
*json
, int indent
)
4060 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4062 if (ops
&& ops
->format_item
) {
4063 ops
->format_item(mtid
, i
, buf
, json
, indent
);
4067 assert(!"Unknown item tlv type!");
4070 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
4071 enum isis_tlv_type type
, struct isis_item_list
*items
,
4072 struct sbuf
*buf
, struct json_object
*json
,
4075 struct isis_item
*i
;
4077 for (i
= items
->head
; i
; i
= i
->next
)
4078 format_item(mtid
, context
, type
, i
, buf
, json
, indent
);
4081 static void free_item(enum isis_tlv_context tlv_context
,
4082 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
4084 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
4086 if (ops
&& ops
->free_item
) {
4087 ops
->free_item(item
);
4091 assert(!"Unknown item tlv type!");
4094 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4095 struct isis_item_list
*items
)
4097 struct isis_item
*item
, *next_item
;
4099 for (item
= items
->head
; item
; item
= next_item
) {
4100 next_item
= item
->next
;
4101 free_item(context
, type
, item
);
4105 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
4106 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
4107 struct isis_tlvs
**fragment_tlvs
,
4108 const struct pack_order_entry
*pe
, uint16_t mtid
)
4110 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4112 if (ops
&& ops
->pack_item
) {
4113 return ops
->pack_item(i
, s
, min_len
);
4116 assert(!"Unknown item tlv type!");
4120 static void add_item_to_fragment(struct isis_item
*i
,
4121 const struct pack_order_entry
*pe
,
4122 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
4124 struct isis_item_list
*l
;
4126 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4127 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4129 struct isis_mt_item_list
*m
;
4130 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4131 l
= isis_get_mt_items(m
, mtid
);
4134 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
4137 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
4138 enum isis_tlv_type type
, struct isis_item_list
*items
,
4139 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
4140 const struct pack_order_entry
*pe
,
4141 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4142 struct list
*new_fragment_arg
)
4144 size_t len_pos
, last_len
, len
;
4145 struct isis_item
*item
= NULL
;
4153 if (STREAM_WRITEABLE(s
) < 2)
4156 stream_putc(s
, type
);
4157 len_pos
= stream_get_endp(s
);
4158 stream_putc(s
, 0); /* Put 0 as length for now */
4160 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
4161 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
4162 if (STREAM_WRITEABLE(s
) < 2)
4164 stream_putw(s
, mtid
);
4167 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
4168 if (STREAM_WRITEABLE(s
) < 1)
4170 stream_putc(s
, 0); /* Virtual flag is set to 0 */
4174 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
4175 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
4180 len
= stream_get_endp(s
) - len_pos
- 1;
4182 /* Multiple auths don't go into one TLV, so always break */
4183 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
4188 /* Multiple prefix-sids don't go into one TLV, so always break */
4189 if (type
== ISIS_SUBTLV_PREFIX_SID
4190 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
4191 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
4197 if (!last_len
) /* strange, not a single item fit */
4199 /* drop last tlv, otherwise, its too long */
4200 stream_set_endp(s
, len_pos
+ 1 + last_len
);
4206 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
4211 stream_putc_at(s
, len_pos
, len
);
4220 if (STREAM_WRITEABLE(s
) < min_len
)
4222 *fragment_tlvs
= new_fragment(new_fragment_arg
);
4225 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
4227 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
4230 dest
->tail
= &(*dest
->tail
)->next
;
4234 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
4236 struct isis_item
*item
, *prev
= NULL
, *next
;
4239 if ((dest
== NULL
) || (del
== NULL
))
4243 * TODO: delete is tricky because "dest" is a singly linked list.
4244 * We need to switch a doubly linked list.
4246 for (item
= dest
->head
; item
; item
= next
) {
4247 if (item
->next
== del
) {
4254 prev
->next
= del
->next
;
4255 if (dest
->head
== del
)
4256 dest
->head
= del
->next
;
4257 if ((struct isis_item
*)dest
->tail
== del
) {
4260 dest
->tail
= &(*dest
->tail
)->next
;
4262 dest
->tail
= &dest
->head
;
4267 static struct isis_item
*last_item(struct isis_item_list
*list
)
4269 return container_of(list
->tail
, struct isis_item
, next
);
4272 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
4273 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
4274 struct sbuf
*log
, void *dest
, int indent
)
4276 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
4278 if (ops
&& ops
->unpack_item
)
4279 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
4281 assert(!"Unknown item tlv type!");
4282 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
4286 static int unpack_tlv_with_items(enum isis_tlv_context context
,
4287 uint8_t tlv_type
, uint8_t tlv_len
,
4288 struct stream
*s
, struct sbuf
*log
, void *dest
,
4296 tlv_start
= stream_get_getp(s
);
4299 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
4301 sbuf_push(log
, indent
,
4302 "TLV is too short to contain MTID\n");
4305 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
4307 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
4308 isis_mtid2str(mtid
));
4310 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
4311 mtid
= ISIS_MT_IPV4_UNICAST
;
4314 if (context
== ISIS_CONTEXT_LSP
4315 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
4316 if (tlv_len
- tlv_pos
< 1) {
4317 sbuf_push(log
, indent
,
4318 "TLV is too short for old style reach\n");
4321 stream_forward_getp(s
, 1);
4325 if (context
== ISIS_CONTEXT_LSP
4326 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
4327 struct isis_tlvs
*tlvs
= dest
;
4328 dest
= &tlvs
->oldstyle_ip_reach
;
4329 } else if (context
== ISIS_CONTEXT_LSP
4330 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
4331 struct isis_tlvs
*tlvs
= dest
;
4332 dest
= &tlvs
->oldstyle_ip_reach_ext
;
4335 if (context
== ISIS_CONTEXT_LSP
4336 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
4337 struct isis_tlvs
*tlvs
= dest
;
4338 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
4341 while (tlv_pos
< (size_t)tlv_len
) {
4342 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
4343 log
, dest
, indent
+ 2);
4347 tlv_pos
= stream_get_getp(s
) - tlv_start
;
4353 /* Functions to manipulate mt_item_lists */
4355 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
4356 const struct isis_item_list
*b
)
4358 if (a
->mtid
< b
->mtid
)
4360 if (a
->mtid
> b
->mtid
)
4365 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4366 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4368 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
4371 struct isis_item_list
*rv
;
4373 rv
= isis_lookup_mt_items(m
, mtid
);
4375 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
4378 RB_INSERT(isis_mt_item_list
, m
, rv
);
4384 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
4387 struct isis_item_list key
= {.mtid
= mtid
};
4389 return RB_FIND(isis_mt_item_list
, m
, &key
);
4392 static void free_mt_items(enum isis_tlv_context context
,
4393 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
4395 struct isis_item_list
*n
, *nnext
;
4397 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
4398 free_items(context
, type
, n
);
4399 RB_REMOVE(isis_mt_item_list
, m
, n
);
4400 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
4404 static void format_mt_items(enum isis_tlv_context context
,
4405 enum isis_tlv_type type
,
4406 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
4407 struct json_object
*json
, int indent
)
4409 struct isis_item_list
*n
;
4411 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4412 format_items_(n
->mtid
, context
, type
, n
, buf
, json
, indent
);
4416 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4417 struct isis_mt_item_list
*m
, struct stream
*s
,
4418 struct isis_tlvs
**fragment_tlvs
,
4419 const struct pack_order_entry
*pe
,
4420 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4421 struct list
*new_fragment_arg
)
4423 struct isis_item_list
*n
;
4425 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4428 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
4429 pe
, new_fragment
, new_fragment_arg
);
4437 static void copy_mt_items(enum isis_tlv_context context
,
4438 enum isis_tlv_type type
,
4439 struct isis_mt_item_list
*src
,
4440 struct isis_mt_item_list
*dest
)
4442 struct isis_item_list
*n
;
4444 RB_INIT(isis_mt_item_list
, dest
);
4446 RB_FOREACH (n
, isis_mt_item_list
, src
) {
4447 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
4451 /* Functions related to tlvs in general */
4453 struct isis_tlvs
*isis_alloc_tlvs(void)
4455 struct isis_tlvs
*result
;
4457 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
4459 init_item_list(&result
->isis_auth
);
4460 init_item_list(&result
->area_addresses
);
4461 init_item_list(&result
->mt_router_info
);
4462 init_item_list(&result
->oldstyle_reach
);
4463 init_item_list(&result
->lan_neighbor
);
4464 init_item_list(&result
->lsp_entries
);
4465 init_item_list(&result
->extended_reach
);
4466 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
4467 init_item_list(&result
->oldstyle_ip_reach
);
4468 init_item_list(&result
->oldstyle_ip_reach_ext
);
4469 init_item_list(&result
->ipv4_address
);
4470 init_item_list(&result
->ipv6_address
);
4471 init_item_list(&result
->global_ipv6_address
);
4472 init_item_list(&result
->extended_ip_reach
);
4473 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
4474 init_item_list(&result
->ipv6_reach
);
4475 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
4480 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
4482 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4484 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
4487 rv
->purge_originator
=
4488 copy_tlv_purge_originator(tlvs
->purge_originator
);
4490 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4491 &tlvs
->area_addresses
, &rv
->area_addresses
);
4493 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4494 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
4496 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
4498 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4499 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
4501 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4502 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
4504 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4507 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4508 &tlvs
->extended_reach
, &rv
->extended_reach
);
4510 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4513 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4514 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
4516 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
4517 &rv
->protocols_supported
);
4519 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4520 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
4522 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
4525 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
4528 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4529 &tlvs
->global_ipv6_address
, &rv
->global_ipv6_address
);
4531 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
4533 rv
->te_router_id_ipv6
=
4534 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4536 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4537 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
4539 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4540 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
4542 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
4544 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4547 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4548 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
4550 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4552 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
4554 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4559 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, struct json_object
*json
, int indent
)
4561 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, json
,
4564 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
4567 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, json
, indent
);
4569 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4570 &tlvs
->area_addresses
, buf
, json
, indent
);
4572 if (tlvs
->mt_router_info_empty
) {
4574 json_object_string_add(json
, "mt-router-info", "none");
4576 sbuf_push(buf
, indent
, "MT Router Info: None\n");
4578 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4579 &tlvs
->mt_router_info
, buf
, json
, indent
);
4582 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4583 &tlvs
->oldstyle_reach
, buf
, json
, indent
);
4585 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4586 &tlvs
->lan_neighbor
, buf
, json
, indent
);
4588 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4591 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, json
, indent
);
4592 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, json
, indent
);
4593 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, buf
, json
,
4596 format_tlv_router_cap_json(tlvs
->router_cap
, json
);
4598 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
4600 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4601 &tlvs
->extended_reach
, buf
, json
, indent
);
4603 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4606 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4607 &tlvs
->oldstyle_ip_reach
, buf
, json
, indent
);
4609 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4610 &tlvs
->oldstyle_ip_reach_ext
, buf
, json
, indent
);
4612 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4613 &tlvs
->ipv4_address
, buf
, json
, indent
);
4615 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4616 &tlvs
->ipv6_address
, buf
, json
, indent
);
4618 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4619 &tlvs
->global_ipv6_address
, buf
, json
, indent
);
4621 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4622 &tlvs
->extended_ip_reach
, buf
, json
, indent
);
4624 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4625 &tlvs
->mt_ip_reach
, buf
, json
, indent
);
4627 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4630 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4631 &tlvs
->mt_ipv6_reach
, buf
, json
, indent
);
4633 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, json
, indent
);
4635 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, json
, indent
);
4638 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
, struct json_object
*json
)
4641 format_tlvs(tlvs
, NULL
, json
, 0);
4644 static struct sbuf buf
;
4646 if (!sbuf_buf(&buf
))
4647 sbuf_init(&buf
, NULL
, 0);
4650 format_tlvs(tlvs
, &buf
, NULL
, 0);
4651 return sbuf_buf(&buf
);
4655 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
4660 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4661 free_tlv_purge_originator(tlvs
->purge_originator
);
4662 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4663 &tlvs
->area_addresses
);
4664 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4665 &tlvs
->mt_router_info
);
4666 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4667 &tlvs
->oldstyle_reach
);
4668 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4669 &tlvs
->lan_neighbor
);
4670 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
4671 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4672 &tlvs
->extended_reach
);
4673 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
4674 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4675 &tlvs
->oldstyle_ip_reach
);
4676 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
4677 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4678 &tlvs
->oldstyle_ip_reach_ext
);
4679 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4680 &tlvs
->ipv4_address
);
4681 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4682 &tlvs
->ipv6_address
);
4683 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4684 &tlvs
->global_ipv6_address
);
4685 free_tlv_te_router_id(tlvs
->te_router_id
);
4686 free_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4687 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4688 &tlvs
->extended_ip_reach
);
4689 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4690 &tlvs
->mt_ip_reach
);
4691 free_tlv_dynamic_hostname(tlvs
->hostname
);
4692 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
4693 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4694 &tlvs
->mt_ipv6_reach
);
4695 free_tlv_threeway_adj(tlvs
->threeway_adj
);
4696 free_tlv_router_cap(tlvs
->router_cap
);
4697 free_tlv_spine_leaf(tlvs
->spine_leaf
);
4699 XFREE(MTYPE_ISIS_TLV
, tlvs
);
4702 static void add_padding(struct stream
*s
)
4704 while (STREAM_WRITEABLE(s
)) {
4705 if (STREAM_WRITEABLE(s
) == 1)
4707 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
4709 if (padding_len
> 255) {
4710 if (padding_len
== 256)
4716 stream_putc(s
, ISIS_TLV_PADDING
);
4717 stream_putc(s
, padding_len
);
4718 stream_put(s
, NULL
, padding_len
);
4722 #define LSP_REM_LIFETIME_OFF 10
4723 #define LSP_CHECKSUM_OFF 24
4724 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
4725 uint16_t *rem_lifetime
)
4727 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
4728 sizeof(*rem_lifetime
));
4729 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
4730 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
4731 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
4734 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
4735 uint16_t rem_lifetime
)
4737 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
4738 sizeof(rem_lifetime
));
4739 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
4742 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
4746 uint16_t checksum
, rem_lifetime
;
4749 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
4751 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
4752 #ifdef CRYPTO_OPENSSL
4753 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
4754 auth
->plength
, STREAM_DATA(s
),
4755 stream_get_endp(s
), NULL
, NULL
);
4757 memcpy(digest
, result
, 16);
4758 #elif CRYPTO_INTERNAL
4759 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
4760 auth
->plength
, digest
);
4762 memcpy(auth
->value
, digest
, 16);
4763 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
4766 restore_auth_md5(s
, checksum
, rem_lifetime
);
4769 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
4771 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4773 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
4774 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
4775 update_auth_hmac_md5(auth
, s
, is_lsp
);
4779 static int handle_pack_entry(const struct pack_order_entry
*pe
,
4780 struct isis_tlvs
*tlvs
, struct stream
*stream
,
4781 struct isis_tlvs
**fragment_tlvs
,
4782 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4783 struct list
*new_fragment_arg
)
4787 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4788 struct isis_item_list
*l
;
4789 l
= (struct isis_item_list
*)(((char *)tlvs
)
4790 + pe
->what_to_pack
);
4791 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
4792 pe
, new_fragment
, new_fragment_arg
);
4794 struct isis_mt_item_list
*l
;
4795 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
4796 + pe
->what_to_pack
);
4797 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
4798 fragment_tlvs
, pe
, new_fragment
,
4805 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4806 struct isis_tlvs
*fragment_tlvs
,
4807 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4808 struct list
*new_fragment_arg
)
4812 /* When fragmenting, don't add auth as it's already accounted for in the
4813 * size we are given. */
4814 if (!fragment_tlvs
) {
4815 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
4816 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
4822 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
4825 if (fragment_tlvs
) {
4826 fragment_tlvs
->purge_originator
=
4827 copy_tlv_purge_originator(tlvs
->purge_originator
);
4830 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
4833 if (fragment_tlvs
) {
4834 copy_tlv_protocols_supported(
4835 &tlvs
->protocols_supported
,
4836 &fragment_tlvs
->protocols_supported
);
4839 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4840 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
4843 if (fragment_tlvs
) {
4844 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4845 &tlvs
->area_addresses
,
4846 &fragment_tlvs
->area_addresses
);
4850 if (tlvs
->mt_router_info_empty
) {
4851 if (STREAM_WRITEABLE(stream
) < 2)
4853 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
4854 stream_putc(stream
, 0);
4856 fragment_tlvs
->mt_router_info_empty
= true;
4858 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4859 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
4863 if (fragment_tlvs
) {
4864 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4865 &tlvs
->mt_router_info
,
4866 &fragment_tlvs
->mt_router_info
);
4870 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
4874 fragment_tlvs
->hostname
=
4875 copy_tlv_dynamic_hostname(tlvs
->hostname
);
4877 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
4880 if (fragment_tlvs
) {
4881 fragment_tlvs
->router_cap
=
4882 copy_tlv_router_cap(tlvs
->router_cap
);
4885 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
4888 if (fragment_tlvs
) {
4889 fragment_tlvs
->te_router_id
=
4890 copy_tlv_te_router_id(tlvs
->te_router_id
);
4893 rv
= pack_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, stream
);
4896 if (fragment_tlvs
) {
4897 fragment_tlvs
->te_router_id_ipv6
=
4898 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4901 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
4904 if (fragment_tlvs
) {
4905 fragment_tlvs
->threeway_adj
=
4906 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4909 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
4912 if (fragment_tlvs
) {
4913 fragment_tlvs
->spine_leaf
=
4914 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4917 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
4919 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
4920 fragment_tlvs
? &fragment_tlvs
: NULL
,
4921 new_fragment
, new_fragment_arg
);
4930 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4931 size_t len_pointer
, bool pad
, bool is_lsp
)
4935 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
4940 add_padding(stream
);
4942 if (len_pointer
!= (size_t)-1) {
4943 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
4946 update_auth(tlvs
, stream
, is_lsp
);
4951 static struct isis_tlvs
*new_fragment(struct list
*l
)
4953 struct isis_tlvs
*rv
= isis_alloc_tlvs();
4955 listnode_add(l
, rv
);
4959 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
4961 struct stream
*dummy_stream
= stream_new(size
);
4962 struct list
*rv
= list_new();
4963 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
4965 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
4966 struct listnode
*node
;
4967 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
4968 isis_free_tlvs(fragment_tlvs
);
4972 stream_free(dummy_stream
);
4976 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
4977 uint8_t tlv_len
, struct stream
*s
,
4978 struct sbuf
*log
, int indent
)
4980 stream_forward_getp(s
, tlv_len
);
4981 sbuf_push(log
, indent
,
4982 "Skipping unknown TLV %hhu (%hhu bytes)\n",
4987 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
4988 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4989 int indent
, bool *unpacked_known_tlvs
)
4991 uint8_t tlv_type
, tlv_len
;
4992 const struct tlv_ops
*ops
;
4994 sbuf_push(log
, indent
, "Unpacking TLV...\n");
4996 if (avail_len
< 2) {
4999 "Available data %zu too short to contain a TLV header.\n",
5004 tlv_type
= stream_getc(stream
);
5005 tlv_len
= stream_getc(stream
);
5007 sbuf_push(log
, indent
+ 2,
5008 "Found TLV of type %hhu and len %hhu.\n",
5011 if (avail_len
< ((size_t)tlv_len
) + 2) {
5012 sbuf_push(log
, indent
+ 2,
5013 "Available data %zu too short for claimed TLV len %hhu.\n",
5014 avail_len
- 2, tlv_len
);
5018 ops
= tlv_table
[context
][tlv_type
];
5019 if (ops
&& ops
->unpack
) {
5020 if (unpacked_known_tlvs
)
5021 *unpacked_known_tlvs
= true;
5022 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
5026 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
5030 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
5031 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5032 int indent
, bool *unpacked_known_tlvs
)
5035 size_t tlv_start
, tlv_pos
;
5037 tlv_start
= stream_get_getp(stream
);
5040 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
5041 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
5043 while (tlv_pos
< avail_len
) {
5044 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
5045 indent
+ 2, unpacked_known_tlvs
);
5049 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
5055 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
5056 struct isis_tlvs
**dest
, const char **log
)
5058 static struct sbuf logbuf
;
5061 struct isis_tlvs
*result
;
5063 if (!sbuf_buf(&logbuf
))
5064 sbuf_init(&logbuf
, NULL
, 0);
5066 sbuf_reset(&logbuf
);
5067 if (avail_len
> STREAM_READABLE(stream
)) {
5068 sbuf_push(&logbuf
, indent
,
5069 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5070 avail_len
, STREAM_READABLE(stream
));
5074 result
= isis_alloc_tlvs();
5075 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
5078 *log
= sbuf_buf(&logbuf
);
5084 #define TLV_OPS(_name_, _desc_) \
5085 static const struct tlv_ops tlv_##_name_##_ops = { \
5086 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5089 #define ITEM_TLV_OPS(_name_, _desc_) \
5090 static const struct tlv_ops tlv_##_name_##_ops = { \
5092 .unpack = unpack_tlv_with_items, \
5094 .pack_item = pack_item_##_name_, \
5095 .free_item = free_item_##_name_, \
5096 .unpack_item = unpack_item_##_name_, \
5097 .format_item = format_item_##_name_, \
5098 .copy_item = copy_item_##_name_}
5100 #define SUBTLV_OPS(_name_, _desc_) \
5101 static const struct tlv_ops subtlv_##_name_##_ops = { \
5102 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5105 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5106 ITEM_TLV_OPS(_name_, _desc_)
5108 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
5109 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
5110 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
5111 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
5112 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
5113 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
5114 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
5115 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
5116 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
5117 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
5118 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
5119 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
5120 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
5121 TLV_OPS(te_router_id_ipv6
, "TLV 140 IPv6 TE Router ID");
5122 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
5123 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
5124 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
5125 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
5126 ITEM_TLV_OPS(global_ipv6_address
, "TLV 233 Global IPv6 Interface Address");
5127 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
5128 TLV_OPS(router_cap
, "TLV 242 Router Capability");
5130 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
5131 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
5133 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
5134 [ISIS_CONTEXT_LSP
] = {
5135 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
5136 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
5137 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
5138 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
5139 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
5140 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
5141 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
5142 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
5143 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
5144 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
5145 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
5146 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
5147 [ISIS_TLV_TE_ROUTER_ID_IPV6
] = &tlv_te_router_id_ipv6_ops
,
5148 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5149 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
5150 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
5151 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
5152 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
5153 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
5154 [ISIS_TLV_GLOBAL_IPV6_ADDRESS
] = &tlv_global_ipv6_address_ops
,
5155 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5156 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5157 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5158 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
5159 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
5161 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
5162 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
5163 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5165 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
5166 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5167 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
5171 /* Accessor functions */
5173 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
5175 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
5176 init_item_list(&tlvs
->isis_auth
);
5178 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
5181 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
5183 auth
->type
= passwd
->type
;
5185 auth
->plength
= passwd
->len
;
5186 memcpy(auth
->passwd
, passwd
->passwd
,
5187 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
5189 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
5190 auth
->length
= passwd
->len
;
5191 memcpy(auth
->value
, passwd
->passwd
,
5192 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
5195 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
5198 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
5199 struct list
*addresses
)
5201 struct listnode
*node
;
5202 struct area_addr
*area_addr
;
5204 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
5205 struct isis_area_address
*a
=
5206 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5208 a
->len
= area_addr
->addr_len
;
5209 memcpy(a
->addr
, area_addr
->area_addr
, 20);
5210 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
5214 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
5216 struct listnode
*node
;
5219 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
5220 struct isis_lan_neighbor
*n
=
5221 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
5223 memcpy(n
->mac
, snpa
, 6);
5224 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
5228 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
5229 struct nlpids
*nlpids
)
5231 tlvs
->protocols_supported
.count
= nlpids
->count
;
5232 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
5233 if (nlpids
->count
) {
5234 tlvs
->protocols_supported
.protocols
=
5235 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
5236 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
5239 tlvs
->protocols_supported
.protocols
= NULL
;
5243 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5244 bool overload
, bool attached
)
5246 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
5248 i
->overload
= overload
;
5249 i
->attached
= attached
;
5251 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
5254 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
5256 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5258 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
5262 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
5263 struct list
*addresses
)
5265 struct listnode
*node
;
5266 struct prefix_ipv4
*ip_addr
;
5267 unsigned int addr_count
= 0;
5269 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5270 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
5272 if (addr_count
>= 63)
5277 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
5278 struct list
*addresses
)
5280 struct listnode
*node
;
5281 struct prefix_ipv6
*ip_addr
;
5282 unsigned int addr_count
= 0;
5284 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5285 if (addr_count
>= 15)
5288 struct isis_ipv6_address
*a
=
5289 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5291 a
->addr
= ip_addr
->prefix
;
5292 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
5297 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs
*tlvs
,
5298 struct list
*addresses
)
5300 struct listnode
*node
;
5301 struct prefix_ipv6
*ip_addr
;
5302 unsigned int addr_count
= 0;
5304 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5305 if (addr_count
>= 15)
5308 struct isis_ipv6_address
*a
=
5309 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5311 a
->addr
= ip_addr
->prefix
;
5312 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)a
);
5317 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
5318 struct stream
*stream
,
5319 struct isis_auth
*auth
, bool is_lsp
);
5321 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
5322 struct stream
*stream
,
5323 struct isis_auth
*auth
, bool is_lsp
)
5325 return (auth
->length
== passwd
->len
5326 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
5329 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
5330 struct stream
*stream
,
5331 struct isis_auth
*auth
, bool is_lsp
)
5335 uint16_t rem_lifetime
;
5338 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
5340 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
5341 #ifdef CRYPTO_OPENSSL
5342 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
5343 passwd
->len
, STREAM_DATA(stream
),
5344 stream_get_endp(stream
), NULL
, NULL
);
5346 memcpy(digest
, result
, 16);
5347 #elif CRYPTO_INTERNAL
5348 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
5349 passwd
->len
, digest
);
5351 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
5353 bool rv
= !memcmp(digest
, auth
->value
, 16);
5356 restore_auth_md5(stream
, checksum
, rem_lifetime
);
5361 static const auth_validator_func auth_validators
[] = {
5362 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
5363 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
5366 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
5367 struct stream
*stream
, bool is_lsp
)
5369 /* If no auth is set, always pass authentication */
5371 return ISIS_AUTH_OK
;
5373 /* If we don't known how to validate the auth, return invalid */
5374 if (passwd
->type
>= array_size(auth_validators
)
5375 || !auth_validators
[passwd
->type
])
5376 return ISIS_AUTH_NO_VALIDATOR
;
5378 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
5379 struct isis_auth
*auth
;
5380 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
5381 if (auth
->type
== passwd
->type
)
5385 /* If matching auth TLV could not be found, return invalid */
5387 return ISIS_AUTH_TYPE_FAILURE
;
5390 /* Perform validation and return result */
5391 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
5392 return ISIS_AUTH_OK
;
5394 return ISIS_AUTH_FAILURE
;
5397 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
5398 struct list
*addresses
)
5400 struct isis_area_address
*addr_head
;
5402 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
5403 for (struct isis_area_address
*addr
= addr_head
; addr
;
5404 addr
= addr
->next
) {
5405 struct listnode
*node
;
5406 struct area_addr
*a
;
5408 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
5409 if (a
->addr_len
== addr
->len
5410 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
5418 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
5419 struct isis_adjacency
*adj
,
5422 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
5423 uint32_t oc
= adj
->area_address_count
;
5426 adj
->area_address_count
= tlvs
->area_addresses
.count
;
5427 adj
->area_addresses
= XREALLOC(
5428 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
5429 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
5431 for (; oc
< adj
->area_address_count
; oc
++) {
5432 adj
->area_addresses
[oc
].addr_len
= 0;
5433 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
5434 sizeof(adj
->area_addresses
[oc
].area_addr
));
5438 struct isis_area_address
*addr
= NULL
;
5439 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
5441 addr
= (struct isis_area_address
*)
5442 tlvs
->area_addresses
.head
;
5446 if (adj
->area_addresses
[i
].addr_len
== addr
->len
5447 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
5453 adj
->area_addresses
[i
].addr_len
= addr
->len
;
5454 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
5458 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
5459 struct isis_adjacency
*adj
,
5462 bool ipv4_supported
= false, ipv6_supported
= false;
5464 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
5465 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
5466 ipv4_supported
= true;
5467 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
5468 ipv6_supported
= true;
5471 struct nlpids reduced
= {};
5473 if (ipv4_supported
&& ipv6_supported
) {
5475 reduced
.nlpids
[0] = NLPID_IP
;
5476 reduced
.nlpids
[1] = NLPID_IPV6
;
5477 } else if (ipv4_supported
) {
5479 reduced
.nlpids
[0] = NLPID_IP
;
5480 } else if (ipv6_supported
) {
5482 reduced
.nlpids
[0] = NLPID_IPV6
;
5487 if (adj
->nlpids
.count
== reduced
.count
5488 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
5492 adj
->nlpids
.count
= reduced
.count
;
5493 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
5496 DEFINE_HOOK(isis_adj_ip_enabled_hook
,
5497 (struct isis_adjacency
* adj
, int family
, bool global
),
5498 (adj
, family
, global
));
5499 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
5500 (struct isis_adjacency
* adj
, int family
, bool global
),
5501 (adj
, family
, global
));
5503 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
5504 struct isis_adjacency
*adj
,
5507 bool ipv4_enabled
= false;
5509 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
5510 ipv4_enabled
= true;
5511 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
5512 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
, false);
5514 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
5515 uint32_t oc
= adj
->ipv4_address_count
;
5518 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
5519 adj
->ipv4_addresses
= XREALLOC(
5520 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
5521 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
5523 for (; oc
< adj
->ipv4_address_count
; oc
++) {
5524 memset(&adj
->ipv4_addresses
[oc
], 0,
5525 sizeof(adj
->ipv4_addresses
[oc
]));
5529 struct isis_ipv4_address
*addr
= NULL
;
5530 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
5532 addr
= (struct isis_ipv4_address
*)
5533 tlvs
->ipv4_address
.head
;
5537 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
5538 sizeof(addr
->addr
)))
5542 adj
->ipv4_addresses
[i
] = addr
->addr
;
5546 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
, false);
5549 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5550 struct isis_adjacency
*adj
,
5553 bool ipv6_enabled
= false;
5555 if (adj
->ll_ipv6_count
== 0 && tlvs
->ipv6_address
.count
> 0)
5556 ipv6_enabled
= true;
5557 else if (adj
->ll_ipv6_count
> 0 && tlvs
->ipv6_address
.count
== 0)
5558 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, false);
5560 if (adj
->ll_ipv6_count
!= tlvs
->ipv6_address
.count
) {
5561 uint32_t oc
= adj
->ll_ipv6_count
;
5564 adj
->ll_ipv6_count
= tlvs
->ipv6_address
.count
;
5565 adj
->ll_ipv6_addrs
= XREALLOC(
5566 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
,
5567 adj
->ll_ipv6_count
* sizeof(*adj
->ll_ipv6_addrs
));
5569 for (; oc
< adj
->ll_ipv6_count
; oc
++) {
5570 memset(&adj
->ll_ipv6_addrs
[oc
], 0,
5571 sizeof(adj
->ll_ipv6_addrs
[oc
]));
5575 struct isis_ipv6_address
*addr
= NULL
;
5576 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
5578 addr
= (struct isis_ipv6_address
*)
5579 tlvs
->ipv6_address
.head
;
5583 if (!memcmp(&adj
->ll_ipv6_addrs
[i
], &addr
->addr
,
5584 sizeof(addr
->addr
)))
5588 adj
->ll_ipv6_addrs
[i
] = addr
->addr
;
5592 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, false);
5596 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5597 struct isis_adjacency
*adj
,
5600 bool global_ipv6_enabled
= false;
5602 if (adj
->global_ipv6_count
== 0 && tlvs
->global_ipv6_address
.count
> 0)
5603 global_ipv6_enabled
= true;
5604 else if (adj
->global_ipv6_count
> 0
5605 && tlvs
->global_ipv6_address
.count
== 0)
5606 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, true);
5608 if (adj
->global_ipv6_count
!= tlvs
->global_ipv6_address
.count
) {
5609 uint32_t oc
= adj
->global_ipv6_count
;
5612 adj
->global_ipv6_count
= tlvs
->global_ipv6_address
.count
;
5613 adj
->global_ipv6_addrs
= XREALLOC(
5614 MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
,
5615 adj
->global_ipv6_count
5616 * sizeof(*adj
->global_ipv6_addrs
));
5618 for (; oc
< adj
->global_ipv6_count
; oc
++) {
5619 memset(&adj
->global_ipv6_addrs
[oc
], 0,
5620 sizeof(adj
->global_ipv6_addrs
[oc
]));
5624 struct isis_ipv6_address
*addr
= NULL
;
5625 for (unsigned int i
= 0; i
< tlvs
->global_ipv6_address
.count
; i
++) {
5627 addr
= (struct isis_ipv6_address
*)
5628 tlvs
->global_ipv6_address
.head
;
5632 if (!memcmp(&adj
->global_ipv6_addrs
[i
], &addr
->addr
,
5633 sizeof(addr
->addr
)))
5637 adj
->global_ipv6_addrs
[i
] = addr
->addr
;
5640 if (global_ipv6_enabled
)
5641 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, true);
5644 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
5649 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
5650 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
5651 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
5652 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5653 tlvs_global_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5656 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
5658 struct isis_lan_neighbor
*ne_head
;
5660 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
5661 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
5662 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
5669 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
5671 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
5673 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
5674 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
5675 entry
->checksum
= lsp
->hdr
.checksum
;
5676 entry
->seqno
= lsp
->hdr
.seqno
;
5679 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
5682 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
5683 uint8_t *stop_id
, uint16_t num_lsps
,
5684 struct lspdb_head
*head
,
5685 struct isis_lsp
**last_lsp
)
5687 struct isis_lsp searchfor
;
5688 struct isis_lsp
*first
, *lsp
;
5690 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
5691 first
= lspdb_find_gteq(head
, &searchfor
);
5695 frr_each_from (lspdb
, head
, lsp
, first
) {
5696 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
5697 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
5700 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
5705 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
5706 const char *hostname
)
5708 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
5710 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
5713 /* Set Router Capability TLV parameters */
5714 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
5715 const struct isis_router_cap
*cap
)
5717 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
5721 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
5722 *tlvs
->router_cap
= *cap
;
5725 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
5726 const struct in_addr
*id
)
5728 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
5731 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5732 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
5735 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs
*tlvs
,
5736 const struct in6_addr
*id
)
5738 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id_ipv6
);
5741 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5742 memcpy(tlvs
->te_router_id_ipv6
, id
, sizeof(*id
));
5745 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
5746 struct prefix_ipv4
*dest
, uint8_t metric
)
5748 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5751 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5752 apply_mask_ipv4(&r
->prefix
);
5753 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
5756 /* Add IS-IS SR Adjacency-SID subTLVs */
5757 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
5758 struct isis_adj_sid
*adj
)
5760 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5761 SET_SUBTLV(exts
, EXT_ADJ_SID
);
5764 /* Delete IS-IS SR Adjacency-SID subTLVs */
5765 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
5766 struct isis_adj_sid
*adj
)
5768 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5769 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
5770 if (exts
->adj_sid
.count
== 0)
5771 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
5774 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
5775 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5776 struct isis_lan_adj_sid
*lan
)
5778 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5779 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5782 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
5783 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5784 struct isis_lan_adj_sid
*lan
)
5786 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5787 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
5788 if (exts
->lan_sid
.count
== 0)
5789 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5792 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
5793 struct prefix_ipv4
*dest
, uint32_t metric
,
5794 bool external
, struct sr_prefix_cfg
*pcfg
)
5796 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5799 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5800 apply_mask_ipv4(&r
->prefix
);
5802 struct isis_prefix_sid
*psid
=
5803 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5805 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5806 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5807 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5809 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
5812 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5813 struct prefix_ipv6
*dest
, uint32_t metric
,
5814 bool external
, struct sr_prefix_cfg
*pcfg
)
5816 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5819 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5820 apply_mask_ipv6(&r
->prefix
);
5822 struct isis_prefix_sid
*psid
=
5823 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5825 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5826 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5827 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5830 struct isis_item_list
*l
;
5831 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
5833 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
5834 append_item(l
, (struct isis_item
*)r
);
5837 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5838 struct prefix_ipv6
*dest
,
5839 struct prefix_ipv6
*src
,
5842 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
5843 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
5846 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
5847 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
5848 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
5849 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
5852 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
5855 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5858 memcpy(r
->id
, id
, sizeof(r
->id
));
5859 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
5862 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5863 uint8_t *id
, uint32_t metric
,
5864 struct isis_ext_subtlvs
*exts
)
5866 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5868 memcpy(r
->id
, id
, sizeof(r
->id
));
5871 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
5873 struct isis_item_list
*l
;
5874 if ((mtid
== ISIS_MT_IPV4_UNICAST
) || (mtid
== ISIS_MT_DISABLE
))
5875 l
= &tlvs
->extended_reach
;
5877 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
5878 append_item(l
, (struct isis_item
*)r
);
5881 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
5882 enum isis_threeway_state state
,
5883 uint32_t local_circuit_id
,
5884 const uint8_t *neighbor_id
,
5885 uint32_t neighbor_circuit_id
)
5887 assert(!tlvs
->threeway_adj
);
5889 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
5890 tlvs
->threeway_adj
->state
= state
;
5891 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
5894 tlvs
->threeway_adj
->neighbor_set
= true;
5895 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
5896 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
5900 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
5901 bool has_tier
, bool is_leaf
, bool is_spine
,
5904 assert(!tlvs
->spine_leaf
);
5906 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
5909 tlvs
->spine_leaf
->tier
= tier
;
5912 tlvs
->spine_leaf
->has_tier
= has_tier
;
5913 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
5914 tlvs
->spine_leaf
->is_spine
= is_spine
;
5915 tlvs
->spine_leaf
->is_backup
= is_backup
;
5918 struct isis_mt_router_info
*
5919 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
5921 if (!tlvs
|| tlvs
->mt_router_info_empty
)
5924 struct isis_mt_router_info
*rv
;
5925 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
5927 if (rv
->mtid
== mtid
)
5934 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
5935 const uint8_t *generator
,
5936 const uint8_t *sender
)
5938 assert(!tlvs
->purge_originator
);
5940 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
5941 sizeof(*tlvs
->purge_originator
));
5942 memcpy(tlvs
->purge_originator
->generator
, generator
,
5943 sizeof(tlvs
->purge_originator
->generator
));
5945 tlvs
->purge_originator
->sender_set
= true;
5946 memcpy(tlvs
->purge_originator
->sender
, sender
,
5947 sizeof(tlvs
->purge_originator
->sender
));