2 * IS-IS TLV Serializer/Deserializer
4 * Copyright (C) 2015,2017 Christian Franke
6 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
8 * This file is part of FRR.
10 * FRR is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FRR; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #include <json-c/json_object.h>
29 #ifdef CRYPTO_INTERNAL
37 #include "isisd/isisd.h"
38 #include "isisd/isis_tlvs.h"
39 #include "isisd/isis_common.h"
40 #include "isisd/isis_mt.h"
41 #include "isisd/isis_misc.h"
42 #include "isisd/isis_adjacency.h"
43 #include "isisd/isis_circuit.h"
44 #include "isisd/isis_pdu.h"
45 #include "isisd/isis_lsp.h"
46 #include "isisd/isis_te.h"
47 #include "isisd/isis_sr.h"
49 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs");
50 DEFINE_MTYPE(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs");
51 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists");
53 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
54 uint8_t tlv_len
, struct stream
*s
,
55 struct sbuf
*log
, void *dest
, int indent
);
56 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
,
58 typedef void (*free_item_func
)(struct isis_item
*i
);
59 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
60 struct sbuf
*log
, void *dest
, int indent
);
61 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
62 struct sbuf
*buf
, struct json_object
*json
,
64 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
68 unpack_tlv_func unpack
;
70 pack_item_func pack_item
;
71 free_item_func free_item
;
72 unpack_item_func unpack_item
;
73 format_item_func format_item
;
74 copy_item_func copy_item
;
82 struct pack_order_entry
{
83 enum isis_tlv_context context
;
84 enum isis_tlv_type type
;
85 enum how_to_pack how_to_pack
;
88 #define PACK_ENTRY(t, h, w) \
90 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
92 .what_to_pack = offsetof(struct isis_tlvs, w), \
95 static const struct pack_order_entry pack_order
[] = {
96 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
97 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
98 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
99 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
100 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
101 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
102 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
103 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
104 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
105 PACK_ENTRY(GLOBAL_IPV6_ADDRESS
, ISIS_ITEMS
, global_ipv6_address
),
106 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
107 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
108 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
109 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)
112 /* This is a forward definition. The table is actually initialized
113 * in at the bottom. */
114 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
116 /* End of _ops forward definition. */
119 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
120 static void init_item_list(struct isis_item_list
*items
);
122 /* For tests/isisd, TLV text requires ipv4-unicast instead of standard */
123 static const char *isis_mtid2str_fake(uint16_t mtid
)
125 if (mtid
== ISIS_MT_STANDARD
)
126 return "ipv4-unicast";
127 return isis_mtid2str(mtid
);
130 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
131 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
133 struct isis_ext_subtlvs
*ext
;
135 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
136 init_item_list(&ext
->adj_sid
);
137 init_item_list(&ext
->lan_sid
);
143 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
144 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
145 * that MT is disabled i.e. IS-IS is working with a Single Topology.
147 static struct isis_ext_subtlvs
*
148 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, uint16_t mtid
)
150 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
151 struct isis_adj_sid
*adj
;
152 struct isis_lan_adj_sid
*lan
;
154 /* Copy the Extended IS main part */
155 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
157 /* Disable IPv4 / IPv6 advertisement in function of MTID */
158 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
159 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR6
);
160 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR6
);
162 if (mtid
== ISIS_MT_IPV6_UNICAST
) {
163 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR
);
164 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR
);
167 /* Prepare (LAN)-Adjacency Segment Routing ID*/
168 init_item_list(&rv
->adj_sid
);
169 init_item_list(&rv
->lan_sid
);
171 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
172 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
174 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
175 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
177 if ((mtid
!= ISIS_MT_DISABLE
)
178 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
179 && (adj
->family
!= AF_INET
))
180 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
181 && (adj
->family
!= AF_INET6
))))
184 struct isis_adj_sid
*new;
186 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
187 new->family
= adj
->family
;
188 new->flags
= adj
->flags
;
189 new->weight
= adj
->weight
;
191 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
192 SET_SUBTLV(rv
, EXT_ADJ_SID
);
195 /* Same for LAN Adj SID */
196 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
198 if ((mtid
!= ISIS_MT_DISABLE
)
199 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
200 && (lan
->family
!= AF_INET
))
201 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
202 && (lan
->family
!= AF_INET6
))))
205 struct isis_lan_adj_sid
*new;
207 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
208 new->family
= lan
->family
;
209 new->flags
= lan
->flags
;
210 new->weight
= lan
->weight
;
211 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
213 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
214 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
220 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
221 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
222 struct sbuf
*buf
, struct json_object
*json
,
223 int indent
, uint16_t mtid
)
228 /* Standard metrics */
229 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
231 snprintfrr(aux_buf
, sizeof(aux_buf
), "0x%x",
233 json_object_string_add(json
, "adm-group", aux_buf
);
235 sbuf_push(buf
, indent
, "Administrative Group: 0x%x\n",
238 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
240 json_object_int_add(json
, "link-local-id",
242 json_object_int_add(json
, "link-remote-id",
245 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
247 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
251 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
253 inet_ntop(AF_INET
, &exts
->local_addr
, aux_buf
,
255 json_object_string_add(json
, "local-iface-ip", aux_buf
);
257 sbuf_push(buf
, indent
,
258 "Local Interface IP Address(es): %pI4\n",
261 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
263 inet_ntop(AF_INET
, &exts
->neigh_addr
, aux_buf
,
265 json_object_string_add(json
, "remote-iface-ip",
268 sbuf_push(buf
, indent
,
269 "Remote Interface IP Address(es): %pI4\n",
272 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
274 inet_ntop(AF_INET6
, &exts
->local_addr6
, aux_buf
,
276 json_object_string_add(json
, "local-iface-ipv6",
279 sbuf_push(buf
, indent
,
280 "Local Interface IPv6 Address(es): %pI6\n",
283 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
285 inet_ntop(AF_INET6
, &exts
->neigh_addr6
, aux_buf
,
287 json_object_string_add(json
, "remote-iface-ipv6",
290 sbuf_push(buf
, indent
,
291 "Remote Interface IPv6 Address(es): %pI6\n",
294 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
296 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
298 json_object_string_add(json
, "max-bandwith-bytes-sec",
301 sbuf_push(buf
, indent
,
302 "Maximum Bandwidth: %g (Bytes/sec)\n",
305 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
307 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
309 json_object_string_add(
310 json
, "max-res-bandwith-bytes-sec", aux_buf
);
314 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
317 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
319 struct json_object
*unrsv_json
;
320 unrsv_json
= json_object_new_object();
321 json_object_object_add(json
, "unrsv-bandwith-bytes-sec",
323 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 1) {
324 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d", j
);
325 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
327 json_object_string_add(unrsv_json
, cnt_buf
,
331 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
332 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
335 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
336 j
, exts
->unrsv_bw
[j
], j
+ 1,
337 exts
->unrsv_bw
[j
+ 1]);
341 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
343 json_object_int_add(json
, "te-metric", exts
->te_metric
);
345 sbuf_push(buf
, indent
,
346 "Traffic Engineering Metric: %u\n",
349 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
351 json_object_int_add(json
, "inter-as-te-remote-as",
354 sbuf_push(buf
, indent
,
355 "Inter-AS TE Remote AS number: %u\n",
358 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
360 inet_ntop(AF_INET6
, &exts
->remote_ip
, aux_buf
,
362 json_object_string_add(
363 json
, "inter-as-te-remote-asbr-ip", aux_buf
);
365 sbuf_push(buf
, indent
,
366 "Inter-AS TE Remote ASBR IP address: %pI4\n",
369 /* Extended metrics */
370 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
372 struct json_object
*avg_json
;
373 avg_json
= json_object_new_object();
374 json_object_object_add(json
, "avg-delay", avg_json
);
375 json_object_string_add(avg_json
, "delay",
376 IS_ANORMAL(exts
->delay
)
379 json_object_int_add(avg_json
, "micro-sec", exts
->delay
);
381 sbuf_push(buf
, indent
,
382 "%s Average Link Delay: %u (micro-sec)\n",
383 IS_ANORMAL(exts
->delay
) ? "Anomalous"
387 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
389 struct json_object
*avg_json
;
390 avg_json
= json_object_new_object();
391 json_object_object_add(json
, "max-min-delay", avg_json
);
392 json_object_string_add(avg_json
, "delay",
393 IS_ANORMAL(exts
->min_delay
)
396 snprintfrr(aux_buf
, sizeof(aux_buf
), "%u / %u",
397 exts
->min_delay
& TE_EXT_MASK
,
398 exts
->max_delay
& TE_EXT_MASK
);
399 json_object_string_add(avg_json
, "micro-sec", aux_buf
);
404 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
405 IS_ANORMAL(exts
->min_delay
) ? "Anomalous"
407 exts
->min_delay
& TE_EXT_MASK
,
408 exts
->max_delay
& TE_EXT_MASK
);
410 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
412 json_object_int_add(json
, "delay-variation-micro-sec",
413 exts
->delay_var
& TE_EXT_MASK
);
415 sbuf_push(buf
, indent
,
416 "Delay Variation: %u (micro-sec)\n",
417 exts
->delay_var
& TE_EXT_MASK
);
419 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
421 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
422 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
424 struct json_object
*link_json
;
425 link_json
= json_object_new_object();
426 json_object_object_add(json
, "link-packet-loss",
428 json_object_string_add(link_json
, "loss",
429 IS_ANORMAL(exts
->pkt_loss
)
432 json_object_string_add(link_json
, "percentaje",
435 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
436 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous"
438 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
441 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
443 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
445 json_object_string_add(json
,
446 "unidir-residual-band-bytes-sec",
451 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
454 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
456 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
458 json_object_string_add(
459 json
, "unidir-available-band-bytes-sec",
464 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
467 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
469 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
471 json_object_string_add(json
,
472 "unidir-utilized-band-bytes-sec",
477 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
480 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
481 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
482 struct isis_adj_sid
*adj
;
485 struct json_object
*arr_adj_json
, *flags_json
;
486 arr_adj_json
= json_object_new_array();
487 json_object_object_add(json
, "adj-sid", arr_adj_json
);
488 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
489 adj
; adj
= adj
->next
) {
490 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
492 flags_json
= json_object_new_object();
493 json_object_int_add(flags_json
, "sid",
495 json_object_int_add(flags_json
, "weight",
497 json_object_string_add(
498 flags_json
, "flag-f",
499 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
502 json_object_string_add(
503 flags_json
, "flag-b",
504 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
507 json_object_string_add(
508 flags_json
, "flag-v",
509 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
512 json_object_string_add(
513 flags_json
, "flag-l",
514 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
517 json_object_string_add(
518 flags_json
, "flag-s",
519 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
522 json_object_string_add(
523 flags_json
, "flag-p",
524 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
527 json_object_array_add(arr_adj_json
, flags_json
);
530 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
531 adj
; adj
= adj
->next
) {
534 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
535 adj
->sid
, adj
->weight
,
536 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
539 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
542 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
545 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
548 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
551 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
556 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
557 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
558 struct isis_lan_adj_sid
*lan
;
560 struct json_object
*arr_adj_json
, *flags_json
;
561 arr_adj_json
= json_object_new_array();
562 json_object_object_add(json
, "lan-adj-sid",
564 for (lan
= (struct isis_lan_adj_sid
*)
566 lan
; lan
= lan
->next
) {
567 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
568 (lan
->family
!= AF_INET
)) ||
569 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
570 (lan
->family
!= AF_INET6
)))
572 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
574 flags_json
= json_object_new_object();
575 json_object_int_add(flags_json
, "sid",
577 json_object_int_add(flags_json
, "weight",
579 json_object_string_add(
580 flags_json
, "flag-f",
581 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
584 json_object_string_add(
585 flags_json
, "flag-b",
586 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
589 json_object_string_add(
590 flags_json
, "flag-v",
591 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
594 json_object_string_add(
595 flags_json
, "flag-l",
596 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
599 json_object_string_add(
600 flags_json
, "flag-s",
601 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
604 json_object_string_add(
605 flags_json
, "flag-p",
606 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
609 json_object_array_add(arr_adj_json
, flags_json
);
613 for (lan
= (struct isis_lan_adj_sid
*)
615 lan
; lan
= lan
->next
) {
616 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
617 (lan
->family
!= AF_INET
)) ||
618 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
619 (lan
->family
!= AF_INET6
)))
623 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
624 " Neighbor-ID: %s\n",
625 lan
->sid
, lan
->weight
,
626 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
629 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
632 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
635 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
638 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
641 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
644 isis_format_id(lan
->neighbor_id
, 6));
649 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
651 struct isis_item
*item
, *next_item
;
653 /* First, free Adj SID and LAN Adj SID list if needed */
654 for (item
= exts
->adj_sid
.head
; item
; item
= next_item
) {
655 next_item
= item
->next
;
656 XFREE(MTYPE_ISIS_SUBTLV
, item
);
658 for (item
= exts
->lan_sid
.head
; item
; item
= next_item
) {
659 next_item
= item
->next
;
660 XFREE(MTYPE_ISIS_SUBTLV
, item
);
662 XFREE(MTYPE_ISIS_SUBTLV
, exts
);
665 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
666 struct stream
*s
, size_t *min_len
)
670 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
671 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
675 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
676 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
677 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
678 stream_putl(s
, exts
->adm_group
);
680 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
681 stream_putc(s
, ISIS_SUBTLV_LLRI
);
682 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
683 stream_putl(s
, exts
->local_llri
);
684 stream_putl(s
, exts
->remote_llri
);
686 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
687 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
688 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
689 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
691 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
692 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
693 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
694 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
696 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
697 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
698 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
699 stream_put(s
, &exts
->local_addr6
, 16);
701 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
702 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
703 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
704 stream_put(s
, &exts
->neigh_addr6
, 16);
706 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
707 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
708 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
709 stream_putf(s
, exts
->max_bw
);
711 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
712 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
713 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
714 stream_putf(s
, exts
->max_rsv_bw
);
716 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
717 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
718 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
719 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
720 stream_putf(s
, exts
->unrsv_bw
[j
]);
722 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
723 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
724 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
725 stream_put3(s
, exts
->te_metric
);
727 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
728 stream_putc(s
, ISIS_SUBTLV_RAS
);
729 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
730 stream_putl(s
, exts
->remote_as
);
732 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
733 stream_putc(s
, ISIS_SUBTLV_RIP
);
734 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
735 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
737 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
738 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
739 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
740 stream_putl(s
, exts
->delay
);
742 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
743 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
744 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
745 stream_putl(s
, exts
->min_delay
);
746 stream_putl(s
, exts
->max_delay
);
748 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
749 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
750 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
751 stream_putl(s
, exts
->delay_var
);
753 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
754 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
755 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
756 stream_putl(s
, exts
->pkt_loss
);
758 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
759 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
760 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
761 stream_putf(s
, exts
->res_bw
);
763 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
764 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
765 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
766 stream_putf(s
, exts
->ava_bw
);
768 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
769 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
770 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
771 stream_putf(s
, exts
->use_bw
);
773 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
774 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
775 struct isis_adj_sid
*adj
;
777 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
779 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
780 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
781 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
783 stream_putc(s
, size
);
784 stream_putc(s
, adj
->flags
);
785 stream_putc(s
, adj
->weight
);
786 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
787 stream_put3(s
, adj
->sid
);
789 stream_putl(s
, adj
->sid
);
793 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
794 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
795 struct isis_lan_adj_sid
*lan
;
797 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
799 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
800 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
801 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
803 stream_putc(s
, size
);
804 stream_putc(s
, lan
->flags
);
805 stream_putc(s
, lan
->weight
);
806 stream_put(s
, lan
->neighbor_id
, 6);
807 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
808 stream_put3(s
, lan
->sid
);
810 stream_putl(s
, lan
->sid
);
817 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
818 struct sbuf
*log
, void *dest
, int indent
)
824 struct isis_extended_reach
*rv
= dest
;
825 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
830 * Parse subTLVs until reach subTLV length
831 * Check that it remains at least 2 bytes: subTLV Type & Length
833 while (len
> sum
+ 2) {
834 /* Read SubTLV Type and Length */
835 subtlv_type
= stream_getc(s
);
836 subtlv_len
= stream_getc(s
);
837 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
840 "TLV %hhu: Available data %u is less than TLV size %u !\n",
841 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
846 switch (subtlv_type
) {
847 /* Standard Metric as defined in RFC5305 */
848 case ISIS_SUBTLV_ADMIN_GRP
:
849 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
850 sbuf_push(log
, indent
,
851 "TLV size does not match expected size for Administrative Group!\n");
852 stream_forward_getp(s
, subtlv_len
);
854 exts
->adm_group
= stream_getl(s
);
855 SET_SUBTLV(exts
, EXT_ADM_GRP
);
858 case ISIS_SUBTLV_LLRI
:
859 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
860 sbuf_push(log
, indent
,
861 "TLV size does not match expected size for Link ID!\n");
862 stream_forward_getp(s
, subtlv_len
);
864 exts
->local_llri
= stream_getl(s
);
865 exts
->remote_llri
= stream_getl(s
);
866 SET_SUBTLV(exts
, EXT_LLRI
);
869 case ISIS_SUBTLV_LOCAL_IPADDR
:
870 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
871 sbuf_push(log
, indent
,
872 "TLV size does not match expected size for Local IP address!\n");
873 stream_forward_getp(s
, subtlv_len
);
875 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
876 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
879 case ISIS_SUBTLV_RMT_IPADDR
:
880 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
881 sbuf_push(log
, indent
,
882 "TLV size does not match expected size for Remote IP address!\n");
883 stream_forward_getp(s
, subtlv_len
);
885 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
886 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
889 case ISIS_SUBTLV_LOCAL_IPADDR6
:
890 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
891 sbuf_push(log
, indent
,
892 "TLV size does not match expected size for Local IPv6 address!\n");
893 stream_forward_getp(s
, subtlv_len
);
895 stream_get(&exts
->local_addr6
, s
, 16);
896 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
899 case ISIS_SUBTLV_RMT_IPADDR6
:
900 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
901 sbuf_push(log
, indent
,
902 "TLV size does not match expected size for Remote IPv6 address!\n");
903 stream_forward_getp(s
, subtlv_len
);
905 stream_get(&exts
->neigh_addr6
, s
, 16);
906 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
909 case ISIS_SUBTLV_MAX_BW
:
910 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
911 sbuf_push(log
, indent
,
912 "TLV size does not match expected size for Maximum Bandwidth!\n");
913 stream_forward_getp(s
, subtlv_len
);
915 exts
->max_bw
= stream_getf(s
);
916 SET_SUBTLV(exts
, EXT_MAX_BW
);
919 case ISIS_SUBTLV_MAX_RSV_BW
:
920 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
921 sbuf_push(log
, indent
,
922 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
923 stream_forward_getp(s
, subtlv_len
);
925 exts
->max_rsv_bw
= stream_getf(s
);
926 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
929 case ISIS_SUBTLV_UNRSV_BW
:
930 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
931 sbuf_push(log
, indent
,
932 "TLV size does not match expected size for Unreserved Bandwidth!\n");
933 stream_forward_getp(s
, subtlv_len
);
935 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
936 exts
->unrsv_bw
[i
] = stream_getf(s
);
937 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
940 case ISIS_SUBTLV_TE_METRIC
:
941 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
942 sbuf_push(log
, indent
,
943 "TLV size does not match expected size for Traffic Engineering Metric!\n");
944 stream_forward_getp(s
, subtlv_len
);
946 exts
->te_metric
= stream_get3(s
);
947 SET_SUBTLV(exts
, EXT_TE_METRIC
);
950 case ISIS_SUBTLV_RAS
:
951 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
952 sbuf_push(log
, indent
,
953 "TLV size does not match expected size for Remote AS number!\n");
954 stream_forward_getp(s
, subtlv_len
);
956 exts
->remote_as
= stream_getl(s
);
957 SET_SUBTLV(exts
, EXT_RMT_AS
);
960 case ISIS_SUBTLV_RIP
:
961 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
962 sbuf_push(log
, indent
,
963 "TLV size does not match expected size for Remote ASBR IP Address!\n");
964 stream_forward_getp(s
, subtlv_len
);
966 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
967 SET_SUBTLV(exts
, EXT_RMT_IP
);
970 /* Extended Metrics as defined in RFC 7810 */
971 case ISIS_SUBTLV_AV_DELAY
:
972 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
973 sbuf_push(log
, indent
,
974 "TLV size does not match expected size for Average Link Delay!\n");
975 stream_forward_getp(s
, subtlv_len
);
977 exts
->delay
= stream_getl(s
);
978 SET_SUBTLV(exts
, EXT_DELAY
);
981 case ISIS_SUBTLV_MM_DELAY
:
982 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
983 sbuf_push(log
, indent
,
984 "TLV size does not match expected size for Min/Max Link Delay!\n");
985 stream_forward_getp(s
, subtlv_len
);
987 exts
->min_delay
= stream_getl(s
);
988 exts
->max_delay
= stream_getl(s
);
989 SET_SUBTLV(exts
, EXT_MM_DELAY
);
992 case ISIS_SUBTLV_DELAY_VAR
:
993 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
994 sbuf_push(log
, indent
,
995 "TLV size does not match expected size for Delay Variation!\n");
996 stream_forward_getp(s
, subtlv_len
);
998 exts
->delay_var
= stream_getl(s
);
999 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
1002 case ISIS_SUBTLV_PKT_LOSS
:
1003 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1004 sbuf_push(log
, indent
,
1005 "TLV size does not match expected size for Link Packet Loss!\n");
1006 stream_forward_getp(s
, subtlv_len
);
1008 exts
->pkt_loss
= stream_getl(s
);
1009 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
1012 case ISIS_SUBTLV_RES_BW
:
1013 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1014 sbuf_push(log
, indent
,
1015 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
1016 stream_forward_getp(s
, subtlv_len
);
1018 exts
->res_bw
= stream_getf(s
);
1019 SET_SUBTLV(exts
, EXT_RES_BW
);
1022 case ISIS_SUBTLV_AVA_BW
:
1023 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1024 sbuf_push(log
, indent
,
1025 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
1026 stream_forward_getp(s
, subtlv_len
);
1028 exts
->ava_bw
= stream_getf(s
);
1029 SET_SUBTLV(exts
, EXT_AVA_BW
);
1032 case ISIS_SUBTLV_USE_BW
:
1033 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1034 sbuf_push(log
, indent
,
1035 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
1036 stream_forward_getp(s
, subtlv_len
);
1038 exts
->use_bw
= stream_getf(s
);
1039 SET_SUBTLV(exts
, EXT_USE_BW
);
1042 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1043 case ISIS_SUBTLV_ADJ_SID
:
1044 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
1045 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
1046 sbuf_push(log
, indent
,
1047 "TLV size does not match expected size for Adjacency SID!\n");
1048 stream_forward_getp(s
, subtlv_len
);
1050 struct isis_adj_sid
*adj
;
1052 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1053 sizeof(struct isis_adj_sid
));
1054 adj
->flags
= stream_getc(s
);
1055 adj
->weight
= stream_getc(s
);
1056 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1057 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
1060 "TLV size does not match expected size for Adjacency SID!\n");
1061 stream_forward_getp(s
, subtlv_len
- 2);
1065 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1067 != ISIS_SUBTLV_ADJ_SID_SIZE
1071 "TLV size does not match expected size for Adjacency SID!\n");
1072 stream_forward_getp(s
, subtlv_len
- 2);
1076 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1077 adj
->sid
= stream_get3(s
);
1078 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
1080 adj
->sid
= stream_getl(s
);
1082 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1083 adj
->family
= AF_INET
;
1084 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1085 adj
->family
= AF_INET6
;
1086 append_item(&exts
->adj_sid
,
1087 (struct isis_item
*)adj
);
1088 SET_SUBTLV(exts
, EXT_ADJ_SID
);
1091 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1092 case ISIS_SUBTLV_LAN_ADJ_SID
:
1093 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1094 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
1095 sbuf_push(log
, indent
,
1096 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1097 stream_forward_getp(s
, subtlv_len
);
1099 struct isis_lan_adj_sid
*lan
;
1101 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1102 sizeof(struct isis_lan_adj_sid
));
1103 lan
->flags
= stream_getc(s
);
1104 lan
->weight
= stream_getc(s
);
1105 stream_get(&(lan
->neighbor_id
), s
,
1108 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1110 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
1113 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1114 stream_forward_getp(
1120 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1122 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1126 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1127 stream_forward_getp(
1133 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1134 lan
->sid
= stream_get3(s
);
1135 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
1137 lan
->sid
= stream_getl(s
);
1139 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1140 lan
->family
= AF_INET
;
1141 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1142 lan
->family
= AF_INET6
;
1143 append_item(&exts
->lan_sid
,
1144 (struct isis_item
*)lan
);
1145 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
1149 /* Skip unknown TLV */
1150 stream_forward_getp(s
, subtlv_len
);
1153 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
1159 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1160 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
1162 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1163 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1165 rv
->flags
= sid
->flags
;
1166 rv
->algorithm
= sid
->algorithm
;
1167 rv
->value
= sid
->value
;
1168 return (struct isis_item
*)rv
;
1171 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
1172 struct sbuf
*buf
, struct json_object
*json
,
1175 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1178 struct json_object
*sr_json
;
1179 sr_json
= json_object_new_object();
1180 json_object_object_add(json
, "sr", sr_json
);
1181 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1182 json_object_int_add(sr_json
, "label", sid
->value
);
1184 json_object_int_add(sr_json
, "index", sid
->value
);
1186 json_object_int_add(sr_json
, "alg", sid
->algorithm
);
1187 json_object_string_add(
1188 sr_json
, "readvertised",
1189 ((sid
->flags
& ISIS_PREFIX_SID_READVERTISED
) ? "yes"
1191 json_object_string_add(
1193 ((sid
->flags
& ISIS_PREFIX_SID_NODE
) ? "yes" : ""));
1194 json_object_string_add(sr_json
, "php",
1195 ((sid
->flags
& ISIS_PREFIX_SID_NO_PHP
)
1198 json_object_string_add(
1199 sr_json
, "explicit-null",
1200 ((sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
) ? "yes"
1202 json_object_string_add(
1204 ((sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? "yes" : ""));
1205 json_object_string_add(
1207 ((sid
->flags
& ISIS_PREFIX_SID_LOCAL
) ? "yes" : ""));
1210 sbuf_push(buf
, indent
, "SR Prefix-SID ");
1211 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1212 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
1214 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
1216 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
1217 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
1218 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
1221 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
1222 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP"
1224 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
1227 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
1228 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
1232 static void free_item_prefix_sid(struct isis_item
*i
)
1234 XFREE(MTYPE_ISIS_SUBTLV
, i
);
1237 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
1240 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1242 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
1244 if (STREAM_WRITEABLE(s
) < size
) {
1249 stream_putc(s
, sid
->flags
);
1250 stream_putc(s
, sid
->algorithm
);
1252 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1253 stream_put3(s
, sid
->value
);
1255 stream_putl(s
, sid
->value
);
1261 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1262 struct sbuf
*log
, void *dest
, int indent
)
1264 struct isis_subtlvs
*subtlvs
= dest
;
1265 struct isis_prefix_sid sid
= {
1268 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
1271 sbuf_push(log
, indent
,
1272 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1277 sid
.flags
= stream_getc(s
);
1278 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1279 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
1280 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
1284 sid
.algorithm
= stream_getc(s
);
1286 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1287 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1288 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
1289 if (len
!= expected_size
) {
1290 sbuf_push(log
, indent
,
1291 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1292 expected_size
, len
);
1296 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
1297 sid
.value
= stream_get3(s
);
1298 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
1299 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
1304 sid
.value
= stream_getl(s
);
1307 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, NULL
, indent
+ 2);
1308 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
1312 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1314 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
1319 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1320 rv
->family
= p
->family
;
1321 rv
->prefixlen
= p
->prefixlen
;
1322 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
1326 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1328 struct json_object
*json
,
1334 char prefixbuf
[PREFIX2STR_BUFFER
];
1336 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
));
1337 json_object_string_add(json
, "ipv6-src-prefix", prefixbuf
);
1339 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1340 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1344 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1350 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1353 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1354 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1355 stream_putc(s
, p
->prefixlen
);
1356 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1360 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1361 uint8_t tlv_type
, uint8_t tlv_len
,
1362 struct stream
*s
, struct sbuf
*log
,
1363 void *dest
, int indent
)
1365 struct isis_subtlvs
*subtlvs
= dest
;
1366 struct prefix_ipv6 p
= {
1370 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1373 sbuf_push(log
, indent
,
1374 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1379 p
.prefixlen
= stream_getc(s
);
1380 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1381 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1386 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1389 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1390 1 + PSIZE(p
.prefixlen
), tlv_len
);
1394 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1396 if (subtlvs
->source_prefix
) {
1399 "WARNING: source prefix Sub-TLV present multiple times.\n");
1400 /* Ignore all but first occurrence of the source prefix Sub-TLV
1405 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1406 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1410 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1411 enum isis_tlv_type type
,
1412 struct isis_item
*item
);
1413 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1414 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1415 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1416 enum isis_tlv_type type
, struct isis_item_list
*items
,
1417 struct sbuf
*buf
, struct json_object
*json
,
1419 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1420 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1421 struct isis_item_list
*items
);
1422 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1423 enum isis_tlv_type type
, struct isis_item_list
*items
,
1424 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1425 const struct pack_order_entry
*pe
,
1426 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1427 struct list
*new_fragment_arg
);
1428 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1430 /* Functions related to subtlvs */
1432 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1434 struct isis_subtlvs
*result
;
1436 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1437 result
->context
= context
;
1439 init_item_list(&result
->prefix_sids
);
1444 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1449 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1451 rv
->context
= subtlvs
->context
;
1453 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1454 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1457 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1461 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1462 struct json_object
*json
, int indent
)
1464 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1465 &subtlvs
->prefix_sids
, buf
, json
, indent
);
1467 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, json
, indent
);
1470 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1475 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1476 &subtlvs
->prefix_sids
);
1478 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1480 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1483 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1486 size_t subtlv_len_pos
= stream_get_endp(s
);
1488 if (STREAM_WRITEABLE(s
) < 1)
1491 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1493 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1494 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1498 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1502 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1503 if (subtlv_len
> 255)
1506 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1510 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1511 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1512 int indent
, bool *unpacked_known_tlvs
);
1514 /* Functions related to TLVs 1 Area Addresses */
1516 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1518 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1519 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1521 rv
->len
= addr
->len
;
1522 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1523 return (struct isis_item
*)rv
;
1526 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1527 struct sbuf
*buf
, struct json_object
*json
,
1530 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1533 json_object_string_add(json
, "area-addr",
1534 isonet_print(addr
->addr
, addr
->len
));
1536 sbuf_push(buf
, indent
, "Area Address: %s\n",
1537 isonet_print(addr
->addr
, addr
->len
));
1541 static void free_item_area_address(struct isis_item
*i
)
1543 XFREE(MTYPE_ISIS_TLV
, i
);
1546 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
1549 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1551 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
1552 *min_len
= (unsigned)1 + addr
->len
;
1555 stream_putc(s
, addr
->len
);
1556 stream_put(s
, addr
->addr
, addr
->len
);
1560 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1561 struct stream
*s
, struct sbuf
*log
,
1562 void *dest
, int indent
)
1564 struct isis_tlvs
*tlvs
= dest
;
1565 struct isis_area_address
*rv
= NULL
;
1567 sbuf_push(log
, indent
, "Unpack area address...\n");
1571 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1576 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1577 rv
->len
= stream_getc(s
);
1579 if (len
< 1 + rv
->len
) {
1580 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1585 if (rv
->len
< 1 || rv
->len
> 20) {
1586 sbuf_push(log
, indent
,
1587 "Implausible area address length %hhu\n",
1592 stream_get(rv
->addr
, s
, rv
->len
);
1594 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1595 log
, NULL
, indent
+ 2);
1596 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1599 XFREE(MTYPE_ISIS_TLV
, rv
);
1603 /* Functions related to TLV 2 (Old-Style) IS Reach */
1604 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1606 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1607 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1609 memcpy(rv
->id
, r
->id
, 7);
1610 rv
->metric
= r
->metric
;
1611 return (struct isis_item
*)rv
;
1614 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1616 struct json_object
*json
, int indent
)
1618 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1621 struct json_object
*old_json
;
1622 old_json
= json_object_new_object();
1623 json_object_object_add(json
, "old-reach-style", old_json
);
1624 json_object_string_add(old_json
, "is-reach",
1625 isis_format_id(r
->id
, 7));
1626 json_object_int_add(old_json
, "metric", r
->metric
);
1628 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
1629 isis_format_id(r
->id
, 7), r
->metric
);
1632 static void free_item_oldstyle_reach(struct isis_item
*i
)
1634 XFREE(MTYPE_ISIS_TLV
, i
);
1637 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
1640 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1642 if (STREAM_WRITEABLE(s
) < 11) {
1647 stream_putc(s
, r
->metric
);
1648 stream_putc(s
, 0x80); /* delay metric - unsupported */
1649 stream_putc(s
, 0x80); /* expense metric - unsupported */
1650 stream_putc(s
, 0x80); /* error metric - unsupported */
1651 stream_put(s
, r
->id
, 7);
1656 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1657 struct stream
*s
, struct sbuf
*log
,
1658 void *dest
, int indent
)
1660 struct isis_tlvs
*tlvs
= dest
;
1662 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1666 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1671 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1672 rv
->metric
= stream_getc(s
);
1673 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1674 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1677 stream_forward_getp(s
, 3); /* Skip other metrics */
1678 stream_get(rv
->id
, s
, 7);
1680 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1682 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1686 /* Functions related to TLV 6 LAN Neighbors */
1687 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1689 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1690 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1692 memcpy(rv
->mac
, n
->mac
, 6);
1693 return (struct isis_item
*)rv
;
1696 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1697 struct sbuf
*buf
, struct json_object
*json
,
1700 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1703 json_object_string_add(json
, "lan-neighbor",
1704 isis_format_id(n
->mac
, 6));
1706 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n",
1707 isis_format_id(n
->mac
, 6));
1710 static void free_item_lan_neighbor(struct isis_item
*i
)
1712 XFREE(MTYPE_ISIS_TLV
, i
);
1715 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
1718 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1720 if (STREAM_WRITEABLE(s
) < 6) {
1725 stream_put(s
, n
->mac
, 6);
1730 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1731 struct stream
*s
, struct sbuf
*log
,
1732 void *dest
, int indent
)
1734 struct isis_tlvs
*tlvs
= dest
;
1736 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1740 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1745 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1746 stream_get(rv
->mac
, s
, 6);
1748 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1749 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1753 /* Functions related to TLV 9 LSP Entry */
1754 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1756 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1757 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1759 rv
->rem_lifetime
= e
->rem_lifetime
;
1760 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1761 rv
->seqno
= e
->seqno
;
1762 rv
->checksum
= e
->checksum
;
1764 return (struct isis_item
*)rv
;
1767 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1768 struct sbuf
*buf
, struct json_object
*json
,
1771 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1775 struct json_object
*lsp_json
;
1776 lsp_json
= json_object_new_object();
1777 json_object_object_add(json
, "lsp-entry", lsp_json
);
1778 json_object_string_add(lsp_json
, "id", isis_format_id(e
->id
, 8));
1779 snprintfrr(buf
,sizeof(buf
),"0x%08x",e
->seqno
);
1780 json_object_string_add(lsp_json
, "seq", buf
);
1781 snprintfrr(buf
,sizeof(buf
),"0x%04hx",e
->checksum
);
1782 json_object_string_add(lsp_json
, "chksum", buf
);
1783 json_object_int_add(lsp_json
, "lifetime", e
->checksum
);
1785 sbuf_push(buf
, indent
,
1786 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1787 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1791 static void free_item_lsp_entry(struct isis_item
*i
)
1793 XFREE(MTYPE_ISIS_TLV
, i
);
1796 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
1799 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1801 if (STREAM_WRITEABLE(s
) < 16) {
1806 stream_putw(s
, e
->rem_lifetime
);
1807 stream_put(s
, e
->id
, 8);
1808 stream_putl(s
, e
->seqno
);
1809 stream_putw(s
, e
->checksum
);
1814 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1815 struct sbuf
*log
, void *dest
, int indent
)
1817 struct isis_tlvs
*tlvs
= dest
;
1819 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1823 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1828 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1829 rv
->rem_lifetime
= stream_getw(s
);
1830 stream_get(rv
->id
, s
, 8);
1831 rv
->seqno
= stream_getl(s
);
1832 rv
->checksum
= stream_getw(s
);
1834 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1835 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1839 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1841 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1843 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1844 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1846 memcpy(rv
->id
, r
->id
, 7);
1847 rv
->metric
= r
->metric
;
1850 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1852 return (struct isis_item
*)rv
;
1855 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1857 struct json_object
*json
, int indent
)
1859 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1862 struct json_object
*reach_json
;
1863 reach_json
= json_object_new_object();
1864 json_object_object_add(json
, "ext-reach", reach_json
);
1865 json_object_string_add(
1866 reach_json
, "mt-id",
1867 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
1868 json_object_string_add(reach_json
, "id",
1869 isis_format_id(r
->id
, 7));
1870 json_object_int_add(reach_json
, "metric", r
->metric
);
1871 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1872 json_object_string_add(reach_json
, "mt-name",
1873 isis_mtid2str(mtid
));
1876 format_item_ext_subtlvs(r
->subtlvs
, NULL
, json
,
1879 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1880 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1881 isis_format_id(r
->id
, 7), r
->metric
);
1882 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1883 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1884 sbuf_push(buf
, 0, "\n");
1887 format_item_ext_subtlvs(r
->subtlvs
, buf
, NULL
,
1892 static void free_item_extended_reach(struct isis_item
*i
)
1894 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1895 if (item
->subtlvs
!= NULL
)
1896 free_item_ext_subtlvs(item
->subtlvs
);
1897 XFREE(MTYPE_ISIS_TLV
, item
);
1900 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
1903 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1907 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
1908 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
1912 stream_put(s
, r
->id
, sizeof(r
->id
));
1913 stream_put3(s
, r
->metric
);
1914 len_pos
= stream_get_endp(s
);
1915 /* Real length will be adjust after adding subTLVs */
1918 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
1920 len
= stream_get_endp(s
) - len_pos
- 1;
1921 stream_putc_at(s
, len_pos
, len
);
1925 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1926 struct stream
*s
, struct sbuf
*log
,
1927 void *dest
, int indent
)
1929 struct isis_tlvs
*tlvs
= dest
;
1930 struct isis_extended_reach
*rv
= NULL
;
1932 struct isis_item_list
*items
;
1934 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1935 items
= &tlvs
->extended_reach
;
1937 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1940 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1941 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1944 sbuf_push(log
, indent
,
1945 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
1950 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1951 stream_get(rv
->id
, s
, 7);
1952 rv
->metric
= stream_get3(s
);
1953 subtlv_len
= stream_getc(s
);
1955 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1956 sbuf_push(log
, indent
,
1957 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
1958 subtlv_len
, len
- 11);
1962 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
1966 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1972 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1974 append_item(items
, (struct isis_item
*)rv
);
1978 free_item_extended_reach((struct isis_item
*)rv
);
1983 /* Functions related to TLV 128 (Old-Style) IP Reach */
1984 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1986 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1987 struct isis_oldstyle_ip_reach
*rv
=
1988 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1990 rv
->metric
= r
->metric
;
1991 rv
->prefix
= r
->prefix
;
1992 return (struct isis_item
*)rv
;
1995 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1997 struct json_object
*json
, int indent
)
1999 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2000 char prefixbuf
[PREFIX2STR_BUFFER
];
2003 struct json_object
*old_json
;
2004 old_json
= json_object_new_object();
2005 json_object_object_add(json
, "old-ip-reach-style", old_json
);
2006 json_object_string_add(old_json
, "prefix",
2007 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2008 json_object_int_add(old_json
, "metric", r
->metric
);
2010 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
2011 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2015 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
2017 XFREE(MTYPE_ISIS_TLV
, i
);
2020 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
2023 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2025 if (STREAM_WRITEABLE(s
) < 12) {
2030 stream_putc(s
, r
->metric
);
2031 stream_putc(s
, 0x80); /* delay metric - unsupported */
2032 stream_putc(s
, 0x80); /* expense metric - unsupported */
2033 stream_putc(s
, 0x80); /* error metric - unsupported */
2034 stream_put(s
, &r
->prefix
.prefix
, 4);
2036 struct in_addr mask
;
2037 masklen2ip(r
->prefix
.prefixlen
, &mask
);
2038 stream_put(s
, &mask
, sizeof(mask
));
2043 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
2044 struct stream
*s
, struct sbuf
*log
,
2045 void *dest
, int indent
)
2047 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
2051 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2056 struct isis_oldstyle_ip_reach
*rv
=
2057 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2058 rv
->metric
= stream_getc(s
);
2059 if ((rv
->metric
& 0x7f) != rv
->metric
) {
2060 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2063 stream_forward_getp(s
, 3); /* Skip other metrics */
2064 rv
->prefix
.family
= AF_INET
;
2065 stream_get(&rv
->prefix
.prefix
, s
, 4);
2067 struct in_addr mask
;
2068 stream_get(&mask
, s
, 4);
2069 rv
->prefix
.prefixlen
= ip_masklen(mask
);
2071 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2073 append_item(dest
, (struct isis_item
*)rv
);
2078 /* Functions related to TLV 129 protocols supported */
2080 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
2081 struct isis_protocols_supported
*dest
)
2083 if (!src
->protocols
|| !src
->count
)
2085 dest
->count
= src
->count
;
2086 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
2087 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
2090 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2092 struct json_object
*json
, int indent
)
2094 if (!p
|| !p
->count
|| !p
->protocols
)
2098 struct json_object
*protocol_json
;
2101 protocol_json
= json_object_new_object();
2102 json_object_object_add(json
, "protocols-supported",
2104 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2105 snprintfrr(buf
, sizeof(buf
), "%d", i
);
2106 json_object_string_add(protocol_json
, buf
,
2107 nlpid2str(p
->protocols
[i
]));
2110 sbuf_push(buf
, indent
, "Protocols Supported: ");
2111 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2112 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
2113 (i
+ 1 < p
->count
) ? ", " : "");
2115 sbuf_push(buf
, 0, "\n");
2119 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
2121 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
2124 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2127 if (!p
|| !p
->count
|| !p
->protocols
)
2130 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
2133 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
2134 stream_putc(s
, p
->count
);
2135 stream_put(s
, p
->protocols
, p
->count
);
2139 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
2140 uint8_t tlv_type
, uint8_t tlv_len
,
2141 struct stream
*s
, struct sbuf
*log
,
2142 void *dest
, int indent
)
2144 struct isis_tlvs
*tlvs
= dest
;
2146 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
2148 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
2151 if (tlvs
->protocols_supported
.protocols
) {
2154 "WARNING: protocols supported TLV present multiple times.\n");
2155 stream_forward_getp(s
, tlv_len
);
2159 tlvs
->protocols_supported
.count
= tlv_len
;
2160 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
2161 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
2163 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
, NULL
,
2168 /* Functions related to TLV 132 IPv4 Interface addresses */
2169 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
2171 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2172 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2175 return (struct isis_item
*)rv
;
2178 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
2179 struct sbuf
*buf
, struct json_object
*json
,
2182 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2183 char addrbuf
[INET_ADDRSTRLEN
];
2185 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2187 json_object_string_add(json
, "ipv4", addrbuf
);
2189 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
2193 static void free_item_ipv4_address(struct isis_item
*i
)
2195 XFREE(MTYPE_ISIS_TLV
, i
);
2198 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
2201 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2203 if (STREAM_WRITEABLE(s
) < 4) {
2208 stream_put(s
, &a
->addr
, 4);
2213 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
2214 struct stream
*s
, struct sbuf
*log
,
2215 void *dest
, int indent
)
2217 struct isis_tlvs
*tlvs
= dest
;
2219 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
2223 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2228 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2229 stream_get(&rv
->addr
, s
, 4);
2231 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2232 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
2237 /* Functions related to TLV 232 IPv6 Interface addresses */
2238 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
2240 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2241 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2244 return (struct isis_item
*)rv
;
2247 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2248 struct sbuf
*buf
, struct json_object
*json
,
2251 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2252 char addrbuf
[INET6_ADDRSTRLEN
];
2254 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2256 json_object_string_add(json
, "ipv6", addrbuf
);
2258 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
2261 static void free_item_ipv6_address(struct isis_item
*i
)
2263 XFREE(MTYPE_ISIS_TLV
, i
);
2266 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2269 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2271 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2272 *min_len
= IPV6_MAX_BYTELEN
;
2276 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2281 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
2282 struct stream
*s
, struct sbuf
*log
,
2283 void *dest
, int indent
)
2285 struct isis_tlvs
*tlvs
= dest
;
2287 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
2291 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2296 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2297 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2299 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2300 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
2305 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2306 static struct isis_item
*copy_item_global_ipv6_address(struct isis_item
*i
)
2308 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2309 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2312 return (struct isis_item
*)rv
;
2315 static void format_item_global_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2317 struct json_object
*json
,
2320 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2321 char addrbuf
[INET6_ADDRSTRLEN
];
2323 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2325 json_object_string_add(json
, "global-ipv6", addrbuf
);
2327 sbuf_push(buf
, indent
, "Global IPv6 Interface Address: %s\n",
2331 static void free_item_global_ipv6_address(struct isis_item
*i
)
2333 XFREE(MTYPE_ISIS_TLV
, i
);
2336 static int pack_item_global_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2339 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2341 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2342 *min_len
= IPV6_MAX_BYTELEN
;
2346 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2351 static int unpack_item_global_ipv6_address(uint16_t mtid
, uint8_t len
,
2352 struct stream
*s
, struct sbuf
*log
,
2353 void *dest
, int indent
)
2355 struct isis_tlvs
*tlvs
= dest
;
2357 sbuf_push(log
, indent
, "Unpack Global IPv6 Interface address...\n");
2358 if (len
< IPV6_MAX_BYTELEN
) {
2361 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2366 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2367 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2369 format_item_global_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2371 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)rv
);
2375 /* Functions related to TLV 229 MT Router information */
2376 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
2378 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2379 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2381 rv
->overload
= info
->overload
;
2382 rv
->attached
= info
->attached
;
2383 rv
->mtid
= info
->mtid
;
2384 return (struct isis_item
*)rv
;
2387 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
2389 struct json_object
*json
, int indent
)
2391 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2394 struct json_object
*mt_json
;
2395 mt_json
= json_object_new_object();
2396 json_object_object_add(json
, "mt", mt_json
);
2397 json_object_int_add(mt_json
, "mtid", info
->mtid
);
2398 json_object_string_add(mt_json
, "overload", info
->overload
?"true":"false");
2399 json_object_string_add(mt_json
, "attached", info
->attached
?"true":"false");
2401 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
2402 isis_mtid2str_fake(info
->mtid
),
2403 info
->overload
? " Overload" : "",
2404 info
->attached
? " Attached" : "");
2407 static void free_item_mt_router_info(struct isis_item
*i
)
2409 XFREE(MTYPE_ISIS_TLV
, i
);
2412 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
2415 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2417 if (STREAM_WRITEABLE(s
) < 2) {
2422 uint16_t entry
= info
->mtid
;
2425 entry
|= ISIS_MT_OL_MASK
;
2427 entry
|= ISIS_MT_AT_MASK
;
2429 stream_putw(s
, entry
);
2434 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
2435 struct stream
*s
, struct sbuf
*log
,
2436 void *dest
, int indent
)
2438 struct isis_tlvs
*tlvs
= dest
;
2440 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
2444 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2449 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2451 uint16_t entry
= stream_getw(s
);
2452 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
2453 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
2454 rv
->mtid
= entry
& ISIS_MT_MASK
;
2456 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2458 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
2462 /* Functions related to TLV 134 TE Router ID */
2464 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
2469 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2470 memcpy(rv
, id
, sizeof(*rv
));
2474 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
2475 struct json_object
*json
, int indent
)
2480 char addrbuf
[INET_ADDRSTRLEN
];
2481 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
2483 json_object_string_add(json
, "te-router-id", addrbuf
);
2485 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
2488 static void free_tlv_te_router_id(struct in_addr
*id
)
2490 XFREE(MTYPE_ISIS_TLV
, id
);
2493 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
2498 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2501 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
2503 stream_put(s
, id
, 4);
2507 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
2508 uint8_t tlv_type
, uint8_t tlv_len
,
2509 struct stream
*s
, struct sbuf
*log
,
2510 void *dest
, int indent
)
2512 struct isis_tlvs
*tlvs
= dest
;
2514 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
2516 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2520 if (tlvs
->te_router_id
) {
2521 sbuf_push(log
, indent
,
2522 "WARNING: TE Router ID present multiple times.\n");
2523 stream_forward_getp(s
, tlv_len
);
2527 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
2528 stream_get(tlvs
->te_router_id
, s
, 4);
2529 format_tlv_te_router_id(tlvs
->te_router_id
, log
, NULL
, indent
+ 2);
2534 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
2536 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
2538 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2539 struct isis_extended_ip_reach
*rv
=
2540 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2542 rv
->metric
= r
->metric
;
2544 rv
->prefix
= r
->prefix
;
2545 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2547 return (struct isis_item
*)rv
;
2550 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2552 struct json_object
*json
, int indent
)
2554 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2555 char prefixbuf
[PREFIX2STR_BUFFER
];
2558 struct json_object
*ext_json
;
2559 ext_json
= json_object_new_object();
2560 json_object_object_add(json
, "ext-ip-reach", ext_json
);
2561 json_object_string_add(
2563 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
2564 json_object_string_add(
2566 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2567 json_object_int_add(json
, "ip-reach-metric", r
->metric
);
2568 json_object_string_add(json
, "down", r
->down
? "yes" : "");
2569 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2570 json_object_string_add(json
, "mt-name",
2571 isis_mtid2str(mtid
));
2573 struct json_object
*subtlv_json
;
2574 subtlv_json
= json_object_new_object();
2575 json_object_object_add(json
, "subtlvs", subtlv_json
);
2576 format_subtlvs(r
->subtlvs
, NULL
, subtlv_json
, 0);
2579 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
2580 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2581 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2582 r
->metric
, r
->down
? " Down" : "");
2583 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2584 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2585 sbuf_push(buf
, 0, "\n");
2588 sbuf_push(buf
, indent
, " Subtlvs:\n");
2589 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
2594 static void free_item_extended_ip_reach(struct isis_item
*i
)
2596 struct isis_extended_ip_reach
*item
=
2597 (struct isis_extended_ip_reach
*)i
;
2598 isis_free_subtlvs(item
->subtlvs
);
2599 XFREE(MTYPE_ISIS_TLV
, item
);
2602 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
2605 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2608 if (STREAM_WRITEABLE(s
) < 5) {
2612 stream_putl(s
, r
->metric
);
2614 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
2615 control
|= r
->prefix
.prefixlen
;
2616 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
2618 stream_putc(s
, control
);
2620 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2621 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2624 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2627 return pack_subtlvs(r
->subtlvs
, s
);
2631 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2632 struct stream
*s
, struct sbuf
*log
,
2633 void *dest
, int indent
)
2635 struct isis_tlvs
*tlvs
= dest
;
2636 struct isis_extended_ip_reach
*rv
= NULL
;
2638 uint8_t control
, subtlv_len
;
2639 struct isis_item_list
*items
;
2641 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2642 items
= &tlvs
->extended_ip_reach
;
2644 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2647 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2648 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2651 if (len
< consume
) {
2652 sbuf_push(log
, indent
,
2653 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2658 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2660 rv
->metric
= stream_getl(s
);
2661 control
= stream_getc(s
);
2662 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2663 rv
->prefix
.family
= AF_INET
;
2664 rv
->prefix
.prefixlen
= control
& 0x3f;
2665 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
2666 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2667 rv
->prefix
.prefixlen
);
2671 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2672 if (len
< consume
) {
2673 sbuf_push(log
, indent
,
2674 "Expected %u bytes of prefix, but only %u bytes available.\n",
2675 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2678 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2679 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2680 apply_mask_ipv4(&rv
->prefix
);
2681 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2682 sbuf_push(log
, indent
+ 2,
2683 "WARNING: Prefix had hostbits set.\n");
2684 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2687 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2689 if (len
< consume
) {
2690 sbuf_push(log
, indent
,
2691 "Expected 1 byte of subtlv len, but no more data present.\n");
2694 subtlv_len
= stream_getc(s
);
2697 sbuf_push(log
, indent
+ 2,
2698 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2700 consume
+= subtlv_len
;
2701 if (len
< consume
) {
2702 sbuf_push(log
, indent
,
2703 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2705 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2709 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2710 bool unpacked_known_tlvs
= false;
2712 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2713 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2716 if (!unpacked_known_tlvs
) {
2717 isis_free_subtlvs(rv
->subtlvs
);
2722 append_item(items
, (struct isis_item
*)rv
);
2726 free_item_extended_ip_reach((struct isis_item
*)rv
);
2730 /* Functions related to TLV 137 Dynamic Hostname */
2732 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2737 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2740 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2741 struct json_object
*json
, int indent
)
2747 json_object_string_add(json
, "hostname", hostname
);
2749 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2752 static void free_tlv_dynamic_hostname(char *hostname
)
2754 XFREE(MTYPE_ISIS_TLV
, hostname
);
2757 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2762 uint8_t name_len
= strlen(hostname
);
2764 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2767 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2768 stream_putc(s
, name_len
);
2769 stream_put(s
, hostname
, name_len
);
2773 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2774 uint8_t tlv_type
, uint8_t tlv_len
,
2775 struct stream
*s
, struct sbuf
*log
,
2776 void *dest
, int indent
)
2778 struct isis_tlvs
*tlvs
= dest
;
2780 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2782 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2786 if (tlvs
->hostname
) {
2787 sbuf_push(log
, indent
,
2788 "WARNING: Hostname present multiple times.\n");
2789 stream_forward_getp(s
, tlv_len
);
2793 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2794 stream_get(tlvs
->hostname
, s
, tlv_len
);
2795 tlvs
->hostname
[tlv_len
] = '\0';
2798 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2799 if ((unsigned char)tlvs
->hostname
[i
] > 127
2800 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2802 tlvs
->hostname
[i
] = '?';
2808 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2814 /* Functions related to TLV 140 IPv6 TE Router ID */
2816 static struct in6_addr
*copy_tlv_te_router_id_ipv6(const struct in6_addr
*id
)
2821 struct in6_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2822 memcpy(rv
, id
, sizeof(*rv
));
2826 static void format_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2828 struct json_object
*json
, int indent
)
2833 char addrbuf
[INET6_ADDRSTRLEN
];
2834 inet_ntop(AF_INET6
, id
, addrbuf
, sizeof(addrbuf
));
2836 json_object_string_add(json
, "ipv6-te-router-id", addrbuf
);
2838 sbuf_push(buf
, indent
, "IPv6 TE Router ID: %s\n", addrbuf
);
2841 static void free_tlv_te_router_id_ipv6(struct in6_addr
*id
)
2843 XFREE(MTYPE_ISIS_TLV
, id
);
2846 static int pack_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2852 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2855 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID_IPV6
);
2856 stream_putc(s
, IPV6_MAX_BYTELEN
);
2857 stream_put(s
, id
, IPV6_MAX_BYTELEN
);
2861 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context
,
2862 uint8_t tlv_type
, uint8_t tlv_len
,
2863 struct stream
*s
, struct sbuf
*log
,
2864 void *dest
, int indent
)
2866 struct isis_tlvs
*tlvs
= dest
;
2868 sbuf_push(log
, indent
, "Unpacking IPv6 TE Router ID TLV...\n");
2869 if (tlv_len
!= IPV6_MAX_BYTELEN
) {
2870 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2874 if (tlvs
->te_router_id_ipv6
) {
2877 "WARNING: IPv6 TE Router ID present multiple times.\n");
2878 stream_forward_getp(s
, tlv_len
);
2882 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, IPV6_MAX_BYTELEN
);
2883 stream_get(tlvs
->te_router_id_ipv6
, s
, IPV6_MAX_BYTELEN
);
2884 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, log
, NULL
, indent
+ 2);
2889 /* Functions related to TLV 150 Spine-Leaf-Extension */
2891 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2892 const struct isis_spine_leaf
*spine_leaf
)
2897 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2898 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2903 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2904 struct sbuf
*buf
, struct json_object
*json
,
2913 struct json_object
*spine_json
;
2914 spine_json
= json_object_new_object();
2915 json_object_object_add(json
, "spine-leaf-extension",
2917 if (spine_leaf
->has_tier
) {
2918 snprintfrr(aux_buf
, sizeof(aux_buf
), "%hhu",
2920 json_object_string_add(
2922 (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
)
2926 json_object_string_add(spine_json
, "flag-leaf",
2927 spine_leaf
->is_leaf
? "yes" : "");
2928 json_object_string_add(spine_json
, "flag-spine",
2929 spine_leaf
->is_spine
? "yes" : "");
2930 json_object_string_add(spine_json
, "flag-backup",
2931 spine_leaf
->is_backup
? "yes" : "");
2933 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2934 if (spine_leaf
->has_tier
) {
2935 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2936 sbuf_push(buf
, indent
, " Tier: undefined\n");
2938 sbuf_push(buf
, indent
, " Tier: %hhu\n",
2943 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2944 spine_leaf
->is_leaf
? " LEAF" : "",
2945 spine_leaf
->is_spine
? " SPINE" : "",
2946 spine_leaf
->is_backup
? " BACKUP" : "");
2950 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2952 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2955 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2956 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2957 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2958 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2960 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2966 uint8_t tlv_len
= 2;
2968 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2971 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2972 stream_putc(s
, tlv_len
);
2974 uint16_t spine_leaf_flags
= 0;
2976 if (spine_leaf
->has_tier
) {
2977 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2978 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2981 if (spine_leaf
->is_leaf
)
2982 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2984 if (spine_leaf
->is_spine
)
2985 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
2987 if (spine_leaf
->is_backup
)
2988 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
2990 stream_putw(s
, spine_leaf_flags
);
2995 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
2996 uint8_t tlv_type
, uint8_t tlv_len
,
2997 struct stream
*s
, struct sbuf
*log
,
2998 void *dest
, int indent
)
3000 struct isis_tlvs
*tlvs
= dest
;
3002 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
3004 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3005 stream_forward_getp(s
, tlv_len
);
3009 if (tlvs
->spine_leaf
) {
3010 sbuf_push(log
, indent
,
3011 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3012 stream_forward_getp(s
, tlv_len
);
3016 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3018 uint16_t spine_leaf_flags
= stream_getw(s
);
3020 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
3021 tlvs
->spine_leaf
->has_tier
= true;
3022 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
3025 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
3026 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
3027 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
3029 stream_forward_getp(s
, tlv_len
- 2);
3033 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3035 const char *isis_threeway_state_name(enum isis_threeway_state state
)
3038 case ISIS_THREEWAY_DOWN
:
3040 case ISIS_THREEWAY_INITIALIZING
:
3041 return "Initializing";
3042 case ISIS_THREEWAY_UP
:
3049 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
3050 const struct isis_threeway_adj
*threeway_adj
)
3055 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3056 memcpy(rv
, threeway_adj
, sizeof(*rv
));
3062 format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3063 struct sbuf
*buf
, struct json_object
*json
, int indent
)
3069 struct json_object
*three_json
;
3070 three_json
= json_object_new_object();
3071 json_object_object_add(json
, "p2p-three-way-adj", three_json
);
3072 json_object_string_add(
3073 three_json
, "state-name",
3074 isis_threeway_state_name(threeway_adj
->state
));
3075 json_object_int_add(three_json
, "state", threeway_adj
->state
);
3076 json_object_int_add(three_json
, "ext-local-circuit-id",
3077 threeway_adj
->local_circuit_id
);
3078 if (!threeway_adj
->neighbor_set
)
3080 json_object_string_add(
3081 three_json
, "neigh-system-id",
3082 isis_format_id(threeway_adj
->neighbor_id
, 6));
3083 json_object_int_add(three_json
, "neigh-ext-circuit-id",
3084 threeway_adj
->neighbor_circuit_id
);
3086 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
3087 sbuf_push(buf
, indent
, " State: %s (%d)\n",
3088 isis_threeway_state_name(threeway_adj
->state
),
3089 threeway_adj
->state
);
3090 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
3091 threeway_adj
->local_circuit_id
);
3092 if (!threeway_adj
->neighbor_set
)
3095 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
3096 isis_format_id(threeway_adj
->neighbor_id
, 6));
3097 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
3098 threeway_adj
->neighbor_circuit_id
);
3102 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
3104 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
3107 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3113 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
3115 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3118 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
3119 stream_putc(s
, tlv_len
);
3120 stream_putc(s
, threeway_adj
->state
);
3121 stream_putl(s
, threeway_adj
->local_circuit_id
);
3123 if (threeway_adj
->neighbor_set
) {
3124 stream_put(s
, threeway_adj
->neighbor_id
, 6);
3125 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
3131 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
3132 uint8_t tlv_type
, uint8_t tlv_len
,
3133 struct stream
*s
, struct sbuf
*log
,
3134 void *dest
, int indent
)
3136 struct isis_tlvs
*tlvs
= dest
;
3138 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
3139 if (tlv_len
!= 5 && tlv_len
!= 15) {
3140 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3141 stream_forward_getp(s
, tlv_len
);
3145 if (tlvs
->threeway_adj
) {
3146 sbuf_push(log
, indent
,
3147 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3148 stream_forward_getp(s
, tlv_len
);
3152 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3154 tlvs
->threeway_adj
->state
= stream_getc(s
);
3155 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
3157 if (tlv_len
== 15) {
3158 tlvs
->threeway_adj
->neighbor_set
= true;
3159 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
3160 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
3166 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3167 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
3169 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3170 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3172 rv
->metric
= r
->metric
;
3174 rv
->external
= r
->external
;
3175 rv
->prefix
= r
->prefix
;
3176 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3178 return (struct isis_item
*)rv
;
3181 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
3182 struct sbuf
*buf
, struct json_object
*json
,
3185 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3186 char prefixbuf
[PREFIX2STR_BUFFER
];
3189 struct json_object
*reach_json
;
3190 reach_json
= json_object_new_object();
3191 json_object_object_add(json
, "ipv6-reach", reach_json
);
3192 json_object_string_add(reach_json
, "mt-id",
3193 (mtid
== ISIS_MT_IPV4_UNICAST
) ? ""
3195 json_object_string_add(
3196 reach_json
, "prefix",
3197 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3198 json_object_int_add(reach_json
, "metric", r
->metric
);
3199 json_object_string_add(reach_json
, "down",
3200 r
->down
? "yes" : "");
3201 json_object_string_add(reach_json
, "external",
3202 r
->external
? "yes" : "");
3203 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3204 json_object_string_add(reach_json
, "mt-name",
3205 isis_mtid2str(mtid
));
3207 struct json_object
*subtlvs_json
;
3208 subtlvs_json
= json_object_new_object();
3209 json_object_object_add(json
, "subtlvs", subtlvs_json
);
3210 format_subtlvs(r
->subtlvs
, NULL
, subtlvs_json
, 0);
3213 sbuf_push(buf
, indent
,
3214 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3215 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
3216 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3217 r
->metric
, r
->down
? " Down" : "",
3218 r
->external
? " External" : "");
3219 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3220 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3221 sbuf_push(buf
, 0, "\n");
3224 sbuf_push(buf
, indent
, " Subtlvs:\n");
3225 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3230 static void free_item_ipv6_reach(struct isis_item
*i
)
3232 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
3234 isis_free_subtlvs(item
->subtlvs
);
3235 XFREE(MTYPE_ISIS_TLV
, item
);
3238 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
3241 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3244 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3245 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3248 stream_putl(s
, r
->metric
);
3250 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
3251 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
3252 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
3254 stream_putc(s
, control
);
3255 stream_putc(s
, r
->prefix
.prefixlen
);
3257 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
3260 return pack_subtlvs(r
->subtlvs
, s
);
3265 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3266 struct sbuf
*log
, void *dest
, int indent
)
3268 struct isis_tlvs
*tlvs
= dest
;
3269 struct isis_ipv6_reach
*rv
= NULL
;
3271 uint8_t control
, subtlv_len
;
3272 struct isis_item_list
*items
;
3274 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3275 items
= &tlvs
->ipv6_reach
;
3277 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3280 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
3281 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
3283 if (len
< consume
) {
3284 sbuf_push(log
, indent
,
3285 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3290 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3292 rv
->metric
= stream_getl(s
);
3293 control
= stream_getc(s
);
3294 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
3295 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
3297 rv
->prefix
.family
= AF_INET6
;
3298 rv
->prefix
.prefixlen
= stream_getc(s
);
3299 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
3300 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
3301 rv
->prefix
.prefixlen
);
3305 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3306 if (len
< consume
) {
3307 sbuf_push(log
, indent
,
3308 "Expected %u bytes of prefix, but only %u bytes available.\n",
3309 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
3312 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3313 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
3315 apply_mask_ipv6(&rv
->prefix
);
3316 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
3317 sbuf_push(log
, indent
+ 2,
3318 "WARNING: Prefix had hostbits set.\n");
3319 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3321 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
3323 if (len
< consume
) {
3324 sbuf_push(log
, indent
,
3325 "Expected 1 byte of subtlv len, but no more data persent.\n");
3328 subtlv_len
= stream_getc(s
);
3331 sbuf_push(log
, indent
+ 2,
3332 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3334 consume
+= subtlv_len
;
3335 if (len
< consume
) {
3336 sbuf_push(log
, indent
,
3337 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3339 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3343 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3344 bool unpacked_known_tlvs
= false;
3346 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
3347 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3350 if (!unpacked_known_tlvs
) {
3351 isis_free_subtlvs(rv
->subtlvs
);
3356 append_item(items
, (struct isis_item
*)rv
);
3360 free_item_ipv6_reach((struct isis_item
*)rv
);
3364 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3365 static struct isis_router_cap
*copy_tlv_router_cap(
3366 const struct isis_router_cap
*router_cap
)
3368 struct isis_router_cap
*rv
;
3373 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3375 memcpy(rv
, router_cap
, sizeof(*rv
));
3380 static void format_tlv_router_cap_json(const struct isis_router_cap
*router_cap
,
3381 struct json_object
*json
)
3383 char addrbuf
[INET_ADDRSTRLEN
];
3388 /* Router ID and Flags */
3389 struct json_object
*cap_json
;
3390 cap_json
= json_object_new_object();
3391 json_object_object_add(json
, "router-capability", cap_json
);
3392 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3393 json_object_string_add(cap_json
, "id", addrbuf
);
3394 json_object_string_add(
3396 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? "1" : "0");
3397 json_object_string_add(
3399 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? "1" : "0");
3401 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3402 if (router_cap
->srgb
.range_size
!= 0) {
3403 struct json_object
*gb_json
;
3404 gb_json
= json_object_new_object();
3405 json_object_object_add(json
, "segment-routing-gb", gb_json
);
3406 json_object_string_add(gb_json
, "ipv4",
3407 IS_SR_IPV4(&router_cap
->srgb
) ? "1"
3409 json_object_string_add(gb_json
, "ipv6",
3410 IS_SR_IPV6(&router_cap
->srgb
) ? "1"
3412 json_object_int_add(gb_json
, "global-block-base",
3413 router_cap
->srgb
.lower_bound
);
3414 json_object_int_add(gb_json
, "global-block-range",
3415 router_cap
->srgb
.range_size
);
3418 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3419 if (router_cap
->srlb
.range_size
!= 0) {
3420 struct json_object
*lb_json
;
3421 lb_json
= json_object_new_object();
3422 json_object_object_add(json
, "segment-routing-lb", lb_json
);
3423 json_object_int_add(lb_json
, "global-block-base",
3424 router_cap
->srlb
.lower_bound
);
3425 json_object_int_add(lb_json
, "global-block-range",
3426 router_cap
->srlb
.range_size
);
3429 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3430 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3432 struct json_object
*alg_json
;
3433 alg_json
= json_object_new_object();
3434 json_object_object_add(json
, "segment-routing-algorithm",
3436 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3437 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
) {
3438 snprintfrr(buf
, sizeof(buf
), "%d", i
);
3439 json_object_string_add(alg_json
, buf
,
3440 router_cap
->algo
[i
] == 0
3446 /* Segment Routing Node MSD as per RFC8491 section #2 */
3447 if (router_cap
->msd
!= 0)
3448 json_object_int_add(json
, "msd", router_cap
->msd
);
3451 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3452 struct sbuf
*buf
, int indent
)
3454 char addrbuf
[INET_ADDRSTRLEN
];
3459 /* Router ID and Flags */
3460 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3461 sbuf_push(buf
, indent
, "Router Capability:");
3462 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
3463 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
3464 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
3466 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3467 if (router_cap
->srgb
.range_size
!= 0)
3470 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
3471 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
3472 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
3473 router_cap
->srgb
.lower_bound
,
3474 router_cap
->srgb
.range_size
);
3476 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3477 if (router_cap
->srlb
.range_size
!= 0)
3478 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
3479 router_cap
->srlb
.lower_bound
,
3480 router_cap
->srlb
.range_size
);
3482 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3483 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3484 sbuf_push(buf
, indent
, " SR Algorithm:\n");
3485 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3486 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
3487 sbuf_push(buf
, indent
, " %u: %s\n", i
,
3488 router_cap
->algo
[i
] == 0
3493 /* Segment Routing Node MSD as per RFC8491 section #2 */
3494 if (router_cap
->msd
!= 0)
3495 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
3499 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
3501 XFREE(MTYPE_ISIS_TLV
, router_cap
);
3504 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3507 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
3514 /* Compute Maximum TLV size */
3515 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
3516 + ISIS_SUBTLV_HDR_SIZE
3517 + ISIS_SUBTLV_ALGORITHM_SIZE
3518 + ISIS_SUBTLV_NODE_MSD_SIZE
;
3520 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
3523 /* Add Router Capability TLV 242 with Router ID and Flags */
3524 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
3525 /* Real length will be adjusted later */
3526 len_pos
= stream_get_endp(s
);
3527 stream_putc(s
, tlv_len
);
3528 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
3529 stream_putc(s
, router_cap
->flags
);
3531 /* Add SRGB if set as per RFC8667 section #3.1 */
3532 if ((router_cap
->srgb
.range_size
!= 0)
3533 && (router_cap
->srgb
.lower_bound
!= 0)) {
3534 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
3535 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3536 stream_putc(s
, router_cap
->srgb
.flags
);
3537 stream_put3(s
, router_cap
->srgb
.range_size
);
3538 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3539 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3540 stream_put3(s
, router_cap
->srgb
.lower_bound
);
3542 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
3543 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
3544 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
3547 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
3548 stream_putc(s
, nb_algo
);
3549 for (int i
= 0; i
< nb_algo
; i
++)
3550 stream_putc(s
, router_cap
->algo
[i
]);
3553 /* Local Block if defined as per RFC8667 section #3.3 */
3554 if ((router_cap
->srlb
.range_size
!= 0)
3555 && (router_cap
->srlb
.lower_bound
!= 0)) {
3556 stream_putc(s
, ISIS_SUBTLV_SRLB
);
3557 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3558 /* No Flags are defined for SRLB */
3560 stream_put3(s
, router_cap
->srlb
.range_size
);
3561 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3562 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3563 stream_put3(s
, router_cap
->srlb
.lower_bound
);
3566 /* And finish with MSD if set as per RFC8491 section #2 */
3567 if (router_cap
->msd
!= 0) {
3568 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
3569 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
3570 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
3571 stream_putc(s
, router_cap
->msd
);
3575 /* Adjust TLV length which depends on subTLVs presence */
3576 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
3577 stream_putc_at(s
, len_pos
, tlv_len
);
3582 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
3583 uint8_t tlv_type
, uint8_t tlv_len
,
3584 struct stream
*s
, struct sbuf
*log
, void *dest
,
3587 struct isis_tlvs
*tlvs
= dest
;
3588 struct isis_router_cap
*rcap
;
3594 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
3595 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
3596 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3597 stream_forward_getp(s
, tlv_len
);
3601 if (tlvs
->router_cap
) {
3602 sbuf_push(log
, indent
,
3603 "WARNING: Router Capability TLV present multiple times.\n");
3604 stream_forward_getp(s
, tlv_len
);
3608 /* Allocate router cap structure and initialize SR Algorithms */
3609 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
3610 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3611 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
3613 /* Get Router ID and Flags */
3614 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
3615 rcap
->flags
= stream_getc(s
);
3617 /* Parse remaining part of the TLV if present */
3618 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
3619 while (subtlv_len
> 2) {
3622 type
= stream_getc(s
);
3623 length
= stream_getc(s
);
3625 if (length
> STREAM_READABLE(s
) || length
> subtlv_len
- 2) {
3628 "WARNING: Router Capability subTLV length too large compared to expected size\n");
3629 stream_forward_getp(s
, STREAM_READABLE(s
));
3630 XFREE(MTYPE_ISIS_TLV
, rcap
);
3635 case ISIS_SUBTLV_SID_LABEL_RANGE
:
3636 /* Check that SRGB is correctly formated */
3637 if (length
< SUBTLV_RANGE_LABEL_SIZE
3638 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3639 stream_forward_getp(s
, length
);
3642 /* Only one SRGB is supported. Skip subsequent one */
3643 if (rcap
->srgb
.range_size
!= 0) {
3644 stream_forward_getp(s
, length
);
3647 rcap
->srgb
.flags
= stream_getc(s
);
3648 rcap
->srgb
.range_size
= stream_get3(s
);
3649 /* Skip Type and get Length of SID Label */
3651 size
= stream_getc(s
);
3653 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3654 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3655 stream_forward_getp(s
, length
- 6);
3659 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3660 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3661 stream_forward_getp(s
, length
- 6);
3665 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3666 rcap
->srgb
.lower_bound
= stream_get3(s
);
3667 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3668 rcap
->srgb
.lower_bound
= stream_getl(s
);
3670 stream_forward_getp(s
, length
- 6);
3674 /* SRGB sanity checks. */
3675 if (rcap
->srgb
.range_size
== 0
3676 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3677 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
3678 > MPLS_LABEL_UNRESERVED_MAX
)) {
3679 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
3680 rcap
->srgb
.lower_bound
= 0;
3681 rcap
->srgb
.range_size
= 0;
3683 /* Only one range is supported. Skip subsequent one */
3684 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3686 stream_forward_getp(s
, size
);
3689 case ISIS_SUBTLV_ALGORITHM
:
3692 /* Only 2 algorithms are supported: SPF & Strict SPF */
3693 stream_get(&rcap
->algo
, s
,
3694 length
> SR_ALGORITHM_COUNT
3695 ? SR_ALGORITHM_COUNT
3697 if (length
> SR_ALGORITHM_COUNT
)
3698 stream_forward_getp(
3699 s
, length
- SR_ALGORITHM_COUNT
);
3701 case ISIS_SUBTLV_SRLB
:
3702 /* Check that SRLB is correctly formated */
3703 if (length
< SUBTLV_RANGE_LABEL_SIZE
3704 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3705 stream_forward_getp(s
, length
);
3708 /* RFC 8667 section #3.3: Only one SRLB is authorized */
3709 if (rcap
->srlb
.range_size
!= 0) {
3710 stream_forward_getp(s
, length
);
3713 /* Ignore Flags which are not defined */
3715 rcap
->srlb
.range_size
= stream_get3(s
);
3716 /* Skip Type and get Length of SID Label */
3718 size
= stream_getc(s
);
3720 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3721 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3722 stream_forward_getp(s
, length
- 6);
3726 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3727 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3728 stream_forward_getp(s
, length
- 6);
3732 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3733 rcap
->srlb
.lower_bound
= stream_get3(s
);
3734 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3735 rcap
->srlb
.lower_bound
= stream_getl(s
);
3737 stream_forward_getp(s
, length
- 6);
3741 /* SRLB sanity checks. */
3742 if (rcap
->srlb
.range_size
== 0
3743 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3744 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
3745 > MPLS_LABEL_UNRESERVED_MAX
)) {
3746 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
3747 rcap
->srlb
.lower_bound
= 0;
3748 rcap
->srlb
.range_size
= 0;
3750 /* Only one range is supported. Skip subsequent one */
3751 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3753 stream_forward_getp(s
, size
);
3756 case ISIS_SUBTLV_NODE_MSD
:
3757 /* Check that MSD is correctly formated */
3758 if (length
< MSD_TLV_SIZE
) {
3759 stream_forward_getp(s
, length
);
3762 msd_type
= stream_getc(s
);
3763 rcap
->msd
= stream_getc(s
);
3764 /* Only BMI-MSD type has been defined in RFC 8491 */
3765 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
3767 /* Only one MSD is standardized. Skip others */
3768 if (length
> MSD_TLV_SIZE
)
3769 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
3772 stream_forward_getp(s
, length
);
3775 subtlv_len
= subtlv_len
- length
- 2;
3777 tlvs
->router_cap
= rcap
;
3781 /* Functions related to TLV 10 Authentication */
3782 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
3784 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3785 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3787 rv
->type
= auth
->type
;
3788 rv
->length
= auth
->length
;
3789 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
3790 return (struct isis_item
*)rv
;
3793 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
3794 struct sbuf
*buf
, struct json_object
*json
,
3797 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3801 json_object_string_add(json
, "test-auth", "ok");
3803 sbuf_push(buf
, indent
, "Authentication:\n");
3804 switch (auth
->type
) {
3805 case ISIS_PASSWD_TYPE_CLEARTXT
:
3806 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
3808 json_object_string_add(json
, "auth-pass", obuf
);
3810 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
3812 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3813 for (unsigned int j
= 0; j
< 16; j
++) {
3814 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
, "%02hhx",
3818 json_object_string_add(json
, "auth-hmac-md5", obuf
);
3820 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
3824 json_object_int_add(json
, "auth-unknown", auth
->type
);
3826 sbuf_push(buf
, indent
, " Unknown (%hhu)\n",
3832 static void free_item_auth(struct isis_item
*i
)
3834 XFREE(MTYPE_ISIS_TLV
, i
);
3837 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
3840 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3842 if (STREAM_WRITEABLE(s
) < 1) {
3846 stream_putc(s
, auth
->type
);
3848 switch (auth
->type
) {
3849 case ISIS_PASSWD_TYPE_CLEARTXT
:
3850 if (STREAM_WRITEABLE(s
) < auth
->length
) {
3851 *min_len
= 1 + auth
->length
;
3854 stream_put(s
, auth
->passwd
, auth
->length
);
3856 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3857 if (STREAM_WRITEABLE(s
) < 16) {
3861 auth
->offset
= stream_get_endp(s
);
3862 stream_put(s
, NULL
, 16);
3871 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3872 struct sbuf
*log
, void *dest
, int indent
)
3874 struct isis_tlvs
*tlvs
= dest
;
3876 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
3880 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
3885 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3887 rv
->type
= stream_getc(s
);
3888 rv
->length
= len
- 1;
3890 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
3893 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
3895 XFREE(MTYPE_ISIS_TLV
, rv
);
3899 rv
->offset
= stream_get_getp(s
);
3900 stream_get(rv
->value
, s
, rv
->length
);
3901 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3902 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
3906 /* Functions related to TLV 13 Purge Originator */
3908 static struct isis_purge_originator
*copy_tlv_purge_originator(
3909 struct isis_purge_originator
*poi
)
3914 struct isis_purge_originator
*rv
;
3916 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3917 rv
->sender_set
= poi
->sender_set
;
3918 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3919 if (poi
->sender_set
)
3920 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
3924 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
3926 struct json_object
*json
, int indent
)
3932 struct json_object
*purge_json
;
3933 purge_json
= json_object_new_object();
3934 json_object_object_add(json
, "purge_originator", purge_json
);
3936 json_object_string_add(
3938 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3939 if (poi
->sender_set
) {
3940 json_object_string_add(
3941 purge_json
, "rec-from",
3942 isis_format_id(poi
->sender
,
3943 sizeof(poi
->sender
)));
3946 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
3948 buf
, indent
, " Generator: %s\n",
3949 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3950 if (poi
->sender_set
) {
3951 sbuf_push(buf
, indent
, " Received-From: %s\n",
3952 isis_format_id(poi
->sender
,
3953 sizeof(poi
->sender
)));
3958 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
3960 XFREE(MTYPE_ISIS_TLV
, poi
);
3963 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
3969 uint8_t data_len
= 1 + sizeof(poi
->generator
);
3971 if (poi
->sender_set
)
3972 data_len
+= sizeof(poi
->sender
);
3974 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
3977 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
3978 stream_putc(s
, data_len
);
3979 stream_putc(s
, poi
->sender_set
? 2 : 1);
3980 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
3981 if (poi
->sender_set
)
3982 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
3986 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
3987 uint8_t tlv_type
, uint8_t tlv_len
,
3988 struct stream
*s
, struct sbuf
*log
,
3989 void *dest
, int indent
)
3991 struct isis_tlvs
*tlvs
= dest
;
3992 struct isis_purge_originator poi
= {};
3994 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
3996 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
4000 uint8_t number_of_ids
= stream_getc(s
);
4002 if (number_of_ids
== 1) {
4003 poi
.sender_set
= false;
4004 } else if (number_of_ids
== 2) {
4005 poi
.sender_set
= true;
4007 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
4011 if (tlv_len
!= 1 + 6 * number_of_ids
) {
4012 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
4016 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
4018 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
4020 if (tlvs
->purge_originator
) {
4021 sbuf_push(log
, indent
,
4022 "WARNING: Purge originator present multiple times, ignoring.\n");
4026 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
4031 /* Functions relating to item TLVs */
4033 static void init_item_list(struct isis_item_list
*items
)
4036 items
->tail
= &items
->head
;
4040 static struct isis_item
*copy_item(enum isis_tlv_context context
,
4041 enum isis_tlv_type type
,
4042 struct isis_item
*item
)
4044 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4046 if (ops
&& ops
->copy_item
)
4047 return ops
->copy_item(item
);
4049 assert(!"Unknown item tlv type!");
4053 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4054 struct isis_item_list
*src
, struct isis_item_list
*dest
)
4056 struct isis_item
*item
;
4058 init_item_list(dest
);
4060 for (item
= src
->head
; item
; item
= item
->next
) {
4061 append_item(dest
, copy_item(context
, type
, item
));
4065 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
4066 enum isis_tlv_type type
, struct isis_item
*i
,
4067 struct sbuf
*buf
, struct json_object
*json
, int indent
)
4069 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4071 if (ops
&& ops
->format_item
) {
4072 ops
->format_item(mtid
, i
, buf
, json
, indent
);
4076 assert(!"Unknown item tlv type!");
4079 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
4080 enum isis_tlv_type type
, struct isis_item_list
*items
,
4081 struct sbuf
*buf
, struct json_object
*json
,
4084 struct isis_item
*i
;
4086 for (i
= items
->head
; i
; i
= i
->next
)
4087 format_item(mtid
, context
, type
, i
, buf
, json
, indent
);
4090 static void free_item(enum isis_tlv_context tlv_context
,
4091 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
4093 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
4095 if (ops
&& ops
->free_item
) {
4096 ops
->free_item(item
);
4100 assert(!"Unknown item tlv type!");
4103 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4104 struct isis_item_list
*items
)
4106 struct isis_item
*item
, *next_item
;
4108 for (item
= items
->head
; item
; item
= next_item
) {
4109 next_item
= item
->next
;
4110 free_item(context
, type
, item
);
4114 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
4115 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
4116 struct isis_tlvs
**fragment_tlvs
,
4117 const struct pack_order_entry
*pe
, uint16_t mtid
)
4119 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4121 if (ops
&& ops
->pack_item
) {
4122 return ops
->pack_item(i
, s
, min_len
);
4125 assert(!"Unknown item tlv type!");
4129 static void add_item_to_fragment(struct isis_item
*i
,
4130 const struct pack_order_entry
*pe
,
4131 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
4133 struct isis_item_list
*l
;
4135 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4136 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4138 struct isis_mt_item_list
*m
;
4139 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4140 l
= isis_get_mt_items(m
, mtid
);
4143 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
4146 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
4147 enum isis_tlv_type type
, struct isis_item_list
*items
,
4148 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
4149 const struct pack_order_entry
*pe
,
4150 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4151 struct list
*new_fragment_arg
)
4153 size_t len_pos
, last_len
, len
;
4154 struct isis_item
*item
= NULL
;
4162 if (STREAM_WRITEABLE(s
) < 2)
4165 stream_putc(s
, type
);
4166 len_pos
= stream_get_endp(s
);
4167 stream_putc(s
, 0); /* Put 0 as length for now */
4169 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
4170 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
4171 if (STREAM_WRITEABLE(s
) < 2)
4173 stream_putw(s
, mtid
);
4176 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
4177 if (STREAM_WRITEABLE(s
) < 1)
4179 stream_putc(s
, 0); /* Virtual flag is set to 0 */
4183 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
4184 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
4189 len
= stream_get_endp(s
) - len_pos
- 1;
4191 /* Multiple auths don't go into one TLV, so always break */
4192 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
4197 /* Multiple prefix-sids don't go into one TLV, so always break */
4198 if (type
== ISIS_SUBTLV_PREFIX_SID
4199 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
4200 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
4206 if (!last_len
) /* strange, not a single item fit */
4208 /* drop last tlv, otherwise, its too long */
4209 stream_set_endp(s
, len_pos
+ 1 + last_len
);
4215 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
4220 stream_putc_at(s
, len_pos
, len
);
4229 if (STREAM_WRITEABLE(s
) < min_len
)
4231 *fragment_tlvs
= new_fragment(new_fragment_arg
);
4234 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
4236 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
4239 dest
->tail
= &(*dest
->tail
)->next
;
4243 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
4245 struct isis_item
*item
, *prev
= NULL
, *next
;
4248 if ((dest
== NULL
) || (del
== NULL
))
4252 * TODO: delete is tricky because "dest" is a singly linked list.
4253 * We need to switch a doubly linked list.
4255 for (item
= dest
->head
; item
; item
= next
) {
4256 if (item
->next
== del
) {
4263 prev
->next
= del
->next
;
4264 if (dest
->head
== del
)
4265 dest
->head
= del
->next
;
4266 if ((struct isis_item
*)dest
->tail
== del
) {
4269 dest
->tail
= &(*dest
->tail
)->next
;
4271 dest
->tail
= &dest
->head
;
4276 static struct isis_item
*last_item(struct isis_item_list
*list
)
4278 return container_of(list
->tail
, struct isis_item
, next
);
4281 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
4282 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
4283 struct sbuf
*log
, void *dest
, int indent
)
4285 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
4287 if (ops
&& ops
->unpack_item
)
4288 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
4290 assert(!"Unknown item tlv type!");
4291 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
4295 static int unpack_tlv_with_items(enum isis_tlv_context context
,
4296 uint8_t tlv_type
, uint8_t tlv_len
,
4297 struct stream
*s
, struct sbuf
*log
, void *dest
,
4305 tlv_start
= stream_get_getp(s
);
4308 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
4310 sbuf_push(log
, indent
,
4311 "TLV is too short to contain MTID\n");
4314 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
4316 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
4317 isis_mtid2str_fake(mtid
));
4319 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
4320 mtid
= ISIS_MT_IPV4_UNICAST
;
4323 if (context
== ISIS_CONTEXT_LSP
4324 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
4325 if (tlv_len
- tlv_pos
< 1) {
4326 sbuf_push(log
, indent
,
4327 "TLV is too short for old style reach\n");
4330 stream_forward_getp(s
, 1);
4334 if (context
== ISIS_CONTEXT_LSP
4335 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
4336 struct isis_tlvs
*tlvs
= dest
;
4337 dest
= &tlvs
->oldstyle_ip_reach
;
4338 } else if (context
== ISIS_CONTEXT_LSP
4339 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
4340 struct isis_tlvs
*tlvs
= dest
;
4341 dest
= &tlvs
->oldstyle_ip_reach_ext
;
4344 if (context
== ISIS_CONTEXT_LSP
4345 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
4346 struct isis_tlvs
*tlvs
= dest
;
4347 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
4350 while (tlv_pos
< (size_t)tlv_len
) {
4351 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
4352 log
, dest
, indent
+ 2);
4356 tlv_pos
= stream_get_getp(s
) - tlv_start
;
4362 /* Functions to manipulate mt_item_lists */
4364 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
4365 const struct isis_item_list
*b
)
4367 if (a
->mtid
< b
->mtid
)
4369 if (a
->mtid
> b
->mtid
)
4374 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4375 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4377 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
4380 struct isis_item_list
*rv
;
4382 rv
= isis_lookup_mt_items(m
, mtid
);
4384 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
4387 RB_INSERT(isis_mt_item_list
, m
, rv
);
4393 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
4396 struct isis_item_list key
= {.mtid
= mtid
};
4398 return RB_FIND(isis_mt_item_list
, m
, &key
);
4401 static void free_mt_items(enum isis_tlv_context context
,
4402 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
4404 struct isis_item_list
*n
, *nnext
;
4406 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
4407 free_items(context
, type
, n
);
4408 RB_REMOVE(isis_mt_item_list
, m
, n
);
4409 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
4413 static void format_mt_items(enum isis_tlv_context context
,
4414 enum isis_tlv_type type
,
4415 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
4416 struct json_object
*json
, int indent
)
4418 struct isis_item_list
*n
;
4420 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4421 format_items_(n
->mtid
, context
, type
, n
, buf
, json
, indent
);
4425 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4426 struct isis_mt_item_list
*m
, struct stream
*s
,
4427 struct isis_tlvs
**fragment_tlvs
,
4428 const struct pack_order_entry
*pe
,
4429 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4430 struct list
*new_fragment_arg
)
4432 struct isis_item_list
*n
;
4434 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4437 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
4438 pe
, new_fragment
, new_fragment_arg
);
4446 static void copy_mt_items(enum isis_tlv_context context
,
4447 enum isis_tlv_type type
,
4448 struct isis_mt_item_list
*src
,
4449 struct isis_mt_item_list
*dest
)
4451 struct isis_item_list
*n
;
4453 RB_INIT(isis_mt_item_list
, dest
);
4455 RB_FOREACH (n
, isis_mt_item_list
, src
) {
4456 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
4460 /* Functions related to tlvs in general */
4462 struct isis_tlvs
*isis_alloc_tlvs(void)
4464 struct isis_tlvs
*result
;
4466 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
4468 init_item_list(&result
->isis_auth
);
4469 init_item_list(&result
->area_addresses
);
4470 init_item_list(&result
->mt_router_info
);
4471 init_item_list(&result
->oldstyle_reach
);
4472 init_item_list(&result
->lan_neighbor
);
4473 init_item_list(&result
->lsp_entries
);
4474 init_item_list(&result
->extended_reach
);
4475 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
4476 init_item_list(&result
->oldstyle_ip_reach
);
4477 init_item_list(&result
->oldstyle_ip_reach_ext
);
4478 init_item_list(&result
->ipv4_address
);
4479 init_item_list(&result
->ipv6_address
);
4480 init_item_list(&result
->global_ipv6_address
);
4481 init_item_list(&result
->extended_ip_reach
);
4482 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
4483 init_item_list(&result
->ipv6_reach
);
4484 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
4489 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
4491 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4493 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
4496 rv
->purge_originator
=
4497 copy_tlv_purge_originator(tlvs
->purge_originator
);
4499 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4500 &tlvs
->area_addresses
, &rv
->area_addresses
);
4502 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4503 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
4505 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
4507 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4508 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
4510 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4511 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
4513 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4516 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4517 &tlvs
->extended_reach
, &rv
->extended_reach
);
4519 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4522 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4523 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
4525 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
4526 &rv
->protocols_supported
);
4528 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4529 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
4531 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
4534 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
4537 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4538 &tlvs
->global_ipv6_address
, &rv
->global_ipv6_address
);
4540 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
4542 rv
->te_router_id_ipv6
=
4543 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4545 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4546 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
4548 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4549 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
4551 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
4553 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4556 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4557 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
4559 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4561 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
4563 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4568 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, struct json_object
*json
, int indent
)
4570 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, json
,
4573 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
4576 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, json
, indent
);
4578 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4579 &tlvs
->area_addresses
, buf
, json
, indent
);
4581 if (tlvs
->mt_router_info_empty
) {
4583 json_object_string_add(json
, "mt-router-info", "none");
4585 sbuf_push(buf
, indent
, "MT Router Info: None\n");
4587 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4588 &tlvs
->mt_router_info
, buf
, json
, indent
);
4591 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4592 &tlvs
->oldstyle_reach
, buf
, json
, indent
);
4594 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4595 &tlvs
->lan_neighbor
, buf
, json
, indent
);
4597 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4600 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, json
, indent
);
4601 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, json
, indent
);
4602 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, buf
, json
,
4605 format_tlv_router_cap_json(tlvs
->router_cap
, json
);
4607 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
4609 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4610 &tlvs
->extended_reach
, buf
, json
, indent
);
4612 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4615 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4616 &tlvs
->oldstyle_ip_reach
, buf
, json
, indent
);
4618 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4619 &tlvs
->oldstyle_ip_reach_ext
, buf
, json
, indent
);
4621 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4622 &tlvs
->ipv4_address
, buf
, json
, indent
);
4624 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4625 &tlvs
->ipv6_address
, buf
, json
, indent
);
4627 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4628 &tlvs
->global_ipv6_address
, buf
, json
, indent
);
4630 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4631 &tlvs
->extended_ip_reach
, buf
, json
, indent
);
4633 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4634 &tlvs
->mt_ip_reach
, buf
, json
, indent
);
4636 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4639 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4640 &tlvs
->mt_ipv6_reach
, buf
, json
, indent
);
4642 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, json
, indent
);
4644 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, json
, indent
);
4647 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
, struct json_object
*json
)
4650 format_tlvs(tlvs
, NULL
, json
, 0);
4653 static struct sbuf buf
;
4655 if (!sbuf_buf(&buf
))
4656 sbuf_init(&buf
, NULL
, 0);
4659 format_tlvs(tlvs
, &buf
, NULL
, 0);
4660 return sbuf_buf(&buf
);
4664 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
4669 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4670 free_tlv_purge_originator(tlvs
->purge_originator
);
4671 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4672 &tlvs
->area_addresses
);
4673 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4674 &tlvs
->mt_router_info
);
4675 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4676 &tlvs
->oldstyle_reach
);
4677 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4678 &tlvs
->lan_neighbor
);
4679 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
4680 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4681 &tlvs
->extended_reach
);
4682 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
4683 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4684 &tlvs
->oldstyle_ip_reach
);
4685 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
4686 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4687 &tlvs
->oldstyle_ip_reach_ext
);
4688 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4689 &tlvs
->ipv4_address
);
4690 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4691 &tlvs
->ipv6_address
);
4692 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4693 &tlvs
->global_ipv6_address
);
4694 free_tlv_te_router_id(tlvs
->te_router_id
);
4695 free_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4696 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4697 &tlvs
->extended_ip_reach
);
4698 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4699 &tlvs
->mt_ip_reach
);
4700 free_tlv_dynamic_hostname(tlvs
->hostname
);
4701 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
4702 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4703 &tlvs
->mt_ipv6_reach
);
4704 free_tlv_threeway_adj(tlvs
->threeway_adj
);
4705 free_tlv_router_cap(tlvs
->router_cap
);
4706 free_tlv_spine_leaf(tlvs
->spine_leaf
);
4708 XFREE(MTYPE_ISIS_TLV
, tlvs
);
4711 static void add_padding(struct stream
*s
)
4713 while (STREAM_WRITEABLE(s
)) {
4714 if (STREAM_WRITEABLE(s
) == 1)
4716 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
4718 if (padding_len
> 255) {
4719 if (padding_len
== 256)
4725 stream_putc(s
, ISIS_TLV_PADDING
);
4726 stream_putc(s
, padding_len
);
4727 stream_put(s
, NULL
, padding_len
);
4731 #define LSP_REM_LIFETIME_OFF 10
4732 #define LSP_CHECKSUM_OFF 24
4733 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
4734 uint16_t *rem_lifetime
)
4736 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
4737 sizeof(*rem_lifetime
));
4738 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
4739 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
4740 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
4743 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
4744 uint16_t rem_lifetime
)
4746 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
4747 sizeof(rem_lifetime
));
4748 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
4751 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
4755 uint16_t checksum
, rem_lifetime
;
4758 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
4760 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
4761 #ifdef CRYPTO_OPENSSL
4762 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
4763 auth
->plength
, STREAM_DATA(s
),
4764 stream_get_endp(s
), NULL
, NULL
);
4766 memcpy(digest
, result
, 16);
4767 #elif CRYPTO_INTERNAL
4768 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
4769 auth
->plength
, digest
);
4771 memcpy(auth
->value
, digest
, 16);
4772 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
4775 restore_auth_md5(s
, checksum
, rem_lifetime
);
4778 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
4780 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4782 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
4783 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
4784 update_auth_hmac_md5(auth
, s
, is_lsp
);
4788 static int handle_pack_entry(const struct pack_order_entry
*pe
,
4789 struct isis_tlvs
*tlvs
, struct stream
*stream
,
4790 struct isis_tlvs
**fragment_tlvs
,
4791 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4792 struct list
*new_fragment_arg
)
4796 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4797 struct isis_item_list
*l
;
4798 l
= (struct isis_item_list
*)(((char *)tlvs
)
4799 + pe
->what_to_pack
);
4800 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
4801 pe
, new_fragment
, new_fragment_arg
);
4803 struct isis_mt_item_list
*l
;
4804 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
4805 + pe
->what_to_pack
);
4806 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
4807 fragment_tlvs
, pe
, new_fragment
,
4814 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4815 struct isis_tlvs
*fragment_tlvs
,
4816 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4817 struct list
*new_fragment_arg
)
4821 /* When fragmenting, don't add auth as it's already accounted for in the
4822 * size we are given. */
4823 if (!fragment_tlvs
) {
4824 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
4825 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
4831 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
4834 if (fragment_tlvs
) {
4835 fragment_tlvs
->purge_originator
=
4836 copy_tlv_purge_originator(tlvs
->purge_originator
);
4839 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
4842 if (fragment_tlvs
) {
4843 copy_tlv_protocols_supported(
4844 &tlvs
->protocols_supported
,
4845 &fragment_tlvs
->protocols_supported
);
4848 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4849 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
4852 if (fragment_tlvs
) {
4853 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4854 &tlvs
->area_addresses
,
4855 &fragment_tlvs
->area_addresses
);
4859 if (tlvs
->mt_router_info_empty
) {
4860 if (STREAM_WRITEABLE(stream
) < 2)
4862 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
4863 stream_putc(stream
, 0);
4865 fragment_tlvs
->mt_router_info_empty
= true;
4867 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4868 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
4872 if (fragment_tlvs
) {
4873 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4874 &tlvs
->mt_router_info
,
4875 &fragment_tlvs
->mt_router_info
);
4879 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
4883 fragment_tlvs
->hostname
=
4884 copy_tlv_dynamic_hostname(tlvs
->hostname
);
4886 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
4889 if (fragment_tlvs
) {
4890 fragment_tlvs
->router_cap
=
4891 copy_tlv_router_cap(tlvs
->router_cap
);
4894 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
4897 if (fragment_tlvs
) {
4898 fragment_tlvs
->te_router_id
=
4899 copy_tlv_te_router_id(tlvs
->te_router_id
);
4902 rv
= pack_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, stream
);
4905 if (fragment_tlvs
) {
4906 fragment_tlvs
->te_router_id_ipv6
=
4907 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4910 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
4913 if (fragment_tlvs
) {
4914 fragment_tlvs
->threeway_adj
=
4915 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4918 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
4921 if (fragment_tlvs
) {
4922 fragment_tlvs
->spine_leaf
=
4923 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4926 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
4928 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
4929 fragment_tlvs
? &fragment_tlvs
: NULL
,
4930 new_fragment
, new_fragment_arg
);
4939 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4940 size_t len_pointer
, bool pad
, bool is_lsp
)
4944 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
4949 add_padding(stream
);
4951 if (len_pointer
!= (size_t)-1) {
4952 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
4955 update_auth(tlvs
, stream
, is_lsp
);
4960 static struct isis_tlvs
*new_fragment(struct list
*l
)
4962 struct isis_tlvs
*rv
= isis_alloc_tlvs();
4964 listnode_add(l
, rv
);
4968 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
4970 struct stream
*dummy_stream
= stream_new(size
);
4971 struct list
*rv
= list_new();
4972 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
4974 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
4975 struct listnode
*node
;
4976 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
4977 isis_free_tlvs(fragment_tlvs
);
4981 stream_free(dummy_stream
);
4985 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
4986 uint8_t tlv_len
, struct stream
*s
,
4987 struct sbuf
*log
, int indent
)
4989 stream_forward_getp(s
, tlv_len
);
4990 sbuf_push(log
, indent
,
4991 "Skipping unknown TLV %hhu (%hhu bytes)\n",
4996 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
4997 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4998 int indent
, bool *unpacked_known_tlvs
)
5000 uint8_t tlv_type
, tlv_len
;
5001 const struct tlv_ops
*ops
;
5003 sbuf_push(log
, indent
, "Unpacking TLV...\n");
5005 if (avail_len
< 2) {
5008 "Available data %zu too short to contain a TLV header.\n",
5013 tlv_type
= stream_getc(stream
);
5014 tlv_len
= stream_getc(stream
);
5016 sbuf_push(log
, indent
+ 2,
5017 "Found TLV of type %hhu and len %hhu.\n",
5020 if (avail_len
< ((size_t)tlv_len
) + 2) {
5021 sbuf_push(log
, indent
+ 2,
5022 "Available data %zu too short for claimed TLV len %hhu.\n",
5023 avail_len
- 2, tlv_len
);
5027 ops
= tlv_table
[context
][tlv_type
];
5028 if (ops
&& ops
->unpack
) {
5029 if (unpacked_known_tlvs
)
5030 *unpacked_known_tlvs
= true;
5031 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
5035 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
5039 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
5040 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5041 int indent
, bool *unpacked_known_tlvs
)
5044 size_t tlv_start
, tlv_pos
;
5046 tlv_start
= stream_get_getp(stream
);
5049 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
5050 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
5052 while (tlv_pos
< avail_len
) {
5053 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
5054 indent
+ 2, unpacked_known_tlvs
);
5058 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
5064 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
5065 struct isis_tlvs
**dest
, const char **log
)
5067 static struct sbuf logbuf
;
5070 struct isis_tlvs
*result
;
5072 if (!sbuf_buf(&logbuf
))
5073 sbuf_init(&logbuf
, NULL
, 0);
5075 sbuf_reset(&logbuf
);
5076 if (avail_len
> STREAM_READABLE(stream
)) {
5077 sbuf_push(&logbuf
, indent
,
5078 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5079 avail_len
, STREAM_READABLE(stream
));
5083 result
= isis_alloc_tlvs();
5084 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
5087 *log
= sbuf_buf(&logbuf
);
5093 #define TLV_OPS(_name_, _desc_) \
5094 static const struct tlv_ops tlv_##_name_##_ops = { \
5095 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5098 #define ITEM_TLV_OPS(_name_, _desc_) \
5099 static const struct tlv_ops tlv_##_name_##_ops = { \
5101 .unpack = unpack_tlv_with_items, \
5103 .pack_item = pack_item_##_name_, \
5104 .free_item = free_item_##_name_, \
5105 .unpack_item = unpack_item_##_name_, \
5106 .format_item = format_item_##_name_, \
5107 .copy_item = copy_item_##_name_}
5109 #define SUBTLV_OPS(_name_, _desc_) \
5110 static const struct tlv_ops subtlv_##_name_##_ops = { \
5111 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5114 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5115 ITEM_TLV_OPS(_name_, _desc_)
5117 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
5118 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
5119 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
5120 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
5121 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
5122 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
5123 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
5124 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
5125 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
5126 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
5127 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
5128 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
5129 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
5130 TLV_OPS(te_router_id_ipv6
, "TLV 140 IPv6 TE Router ID");
5131 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
5132 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
5133 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
5134 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
5135 ITEM_TLV_OPS(global_ipv6_address
, "TLV 233 Global IPv6 Interface Address");
5136 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
5137 TLV_OPS(router_cap
, "TLV 242 Router Capability");
5139 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
5140 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
5142 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
5143 [ISIS_CONTEXT_LSP
] = {
5144 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
5145 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
5146 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
5147 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
5148 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
5149 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
5150 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
5151 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
5152 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
5153 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
5154 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
5155 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
5156 [ISIS_TLV_TE_ROUTER_ID_IPV6
] = &tlv_te_router_id_ipv6_ops
,
5157 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5158 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
5159 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
5160 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
5161 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
5162 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
5163 [ISIS_TLV_GLOBAL_IPV6_ADDRESS
] = &tlv_global_ipv6_address_ops
,
5164 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5165 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5166 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5167 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
5168 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
5170 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
5171 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
5172 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5174 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
5175 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5176 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
5180 /* Accessor functions */
5182 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
5184 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
5185 init_item_list(&tlvs
->isis_auth
);
5187 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
5190 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
5192 auth
->type
= passwd
->type
;
5194 auth
->plength
= passwd
->len
;
5195 memcpy(auth
->passwd
, passwd
->passwd
,
5196 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
5198 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
5199 auth
->length
= passwd
->len
;
5200 memcpy(auth
->value
, passwd
->passwd
,
5201 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
5204 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
5207 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
5208 struct list
*addresses
)
5210 struct listnode
*node
;
5211 struct area_addr
*area_addr
;
5213 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
5214 struct isis_area_address
*a
=
5215 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5217 a
->len
= area_addr
->addr_len
;
5218 memcpy(a
->addr
, area_addr
->area_addr
, 20);
5219 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
5223 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
5225 struct listnode
*node
;
5228 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
5229 struct isis_lan_neighbor
*n
=
5230 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
5232 memcpy(n
->mac
, snpa
, 6);
5233 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
5237 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
5238 struct nlpids
*nlpids
)
5240 tlvs
->protocols_supported
.count
= nlpids
->count
;
5241 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
5242 if (nlpids
->count
) {
5243 tlvs
->protocols_supported
.protocols
=
5244 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
5245 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
5248 tlvs
->protocols_supported
.protocols
= NULL
;
5252 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5253 bool overload
, bool attached
)
5255 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
5257 i
->overload
= overload
;
5258 i
->attached
= attached
;
5260 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
5263 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
5265 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5267 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
5271 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
5272 struct list
*addresses
)
5274 struct listnode
*node
;
5275 struct prefix_ipv4
*ip_addr
;
5276 unsigned int addr_count
= 0;
5278 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5279 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
5281 if (addr_count
>= 63)
5286 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
5287 struct list
*addresses
)
5289 struct listnode
*node
;
5290 struct prefix_ipv6
*ip_addr
;
5291 unsigned int addr_count
= 0;
5293 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5294 if (addr_count
>= 15)
5297 struct isis_ipv6_address
*a
=
5298 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5300 a
->addr
= ip_addr
->prefix
;
5301 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
5306 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs
*tlvs
,
5307 struct list
*addresses
)
5309 struct listnode
*node
;
5310 struct prefix_ipv6
*ip_addr
;
5311 unsigned int addr_count
= 0;
5313 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5314 if (addr_count
>= 15)
5317 struct isis_ipv6_address
*a
=
5318 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5320 a
->addr
= ip_addr
->prefix
;
5321 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)a
);
5326 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
5327 struct stream
*stream
,
5328 struct isis_auth
*auth
, bool is_lsp
);
5330 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
5331 struct stream
*stream
,
5332 struct isis_auth
*auth
, bool is_lsp
)
5334 return (auth
->length
== passwd
->len
5335 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
5338 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
5339 struct stream
*stream
,
5340 struct isis_auth
*auth
, bool is_lsp
)
5344 uint16_t rem_lifetime
;
5347 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
5349 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
5350 #ifdef CRYPTO_OPENSSL
5351 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
5352 passwd
->len
, STREAM_DATA(stream
),
5353 stream_get_endp(stream
), NULL
, NULL
);
5355 memcpy(digest
, result
, 16);
5356 #elif CRYPTO_INTERNAL
5357 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
5358 passwd
->len
, digest
);
5360 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
5362 bool rv
= !memcmp(digest
, auth
->value
, 16);
5365 restore_auth_md5(stream
, checksum
, rem_lifetime
);
5370 static const auth_validator_func auth_validators
[] = {
5371 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
5372 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
5375 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
5376 struct stream
*stream
, bool is_lsp
)
5378 /* If no auth is set, always pass authentication */
5380 return ISIS_AUTH_OK
;
5382 /* If we don't known how to validate the auth, return invalid */
5383 if (passwd
->type
>= array_size(auth_validators
)
5384 || !auth_validators
[passwd
->type
])
5385 return ISIS_AUTH_NO_VALIDATOR
;
5387 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
5388 struct isis_auth
*auth
;
5389 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
5390 if (auth
->type
== passwd
->type
)
5394 /* If matching auth TLV could not be found, return invalid */
5396 return ISIS_AUTH_TYPE_FAILURE
;
5399 /* Perform validation and return result */
5400 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
5401 return ISIS_AUTH_OK
;
5403 return ISIS_AUTH_FAILURE
;
5406 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
5407 struct list
*addresses
)
5409 struct isis_area_address
*addr_head
;
5411 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
5412 for (struct isis_area_address
*addr
= addr_head
; addr
;
5413 addr
= addr
->next
) {
5414 struct listnode
*node
;
5415 struct area_addr
*a
;
5417 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
5418 if (a
->addr_len
== addr
->len
5419 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
5427 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
5428 struct isis_adjacency
*adj
,
5431 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
5432 uint32_t oc
= adj
->area_address_count
;
5435 adj
->area_address_count
= tlvs
->area_addresses
.count
;
5436 adj
->area_addresses
= XREALLOC(
5437 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
5438 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
5440 for (; oc
< adj
->area_address_count
; oc
++) {
5441 adj
->area_addresses
[oc
].addr_len
= 0;
5442 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
5443 sizeof(adj
->area_addresses
[oc
].area_addr
));
5447 struct isis_area_address
*addr
= NULL
;
5448 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
5450 addr
= (struct isis_area_address
*)
5451 tlvs
->area_addresses
.head
;
5455 if (adj
->area_addresses
[i
].addr_len
== addr
->len
5456 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
5462 adj
->area_addresses
[i
].addr_len
= addr
->len
;
5463 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
5467 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
5468 struct isis_adjacency
*adj
,
5471 bool ipv4_supported
= false, ipv6_supported
= false;
5473 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
5474 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
5475 ipv4_supported
= true;
5476 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
5477 ipv6_supported
= true;
5480 struct nlpids reduced
= {};
5482 if (ipv4_supported
&& ipv6_supported
) {
5484 reduced
.nlpids
[0] = NLPID_IP
;
5485 reduced
.nlpids
[1] = NLPID_IPV6
;
5486 } else if (ipv4_supported
) {
5488 reduced
.nlpids
[0] = NLPID_IP
;
5489 } else if (ipv6_supported
) {
5491 reduced
.nlpids
[0] = NLPID_IPV6
;
5496 if (adj
->nlpids
.count
== reduced
.count
5497 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
5501 adj
->nlpids
.count
= reduced
.count
;
5502 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
5505 DEFINE_HOOK(isis_adj_ip_enabled_hook
,
5506 (struct isis_adjacency
* adj
, int family
, bool global
),
5507 (adj
, family
, global
));
5508 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
5509 (struct isis_adjacency
* adj
, int family
, bool global
),
5510 (adj
, family
, global
));
5512 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
5513 struct isis_adjacency
*adj
,
5516 bool ipv4_enabled
= false;
5518 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
5519 ipv4_enabled
= true;
5520 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
5521 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
, false);
5523 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
5524 uint32_t oc
= adj
->ipv4_address_count
;
5527 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
5528 adj
->ipv4_addresses
= XREALLOC(
5529 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
5530 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
5532 for (; oc
< adj
->ipv4_address_count
; oc
++) {
5533 memset(&adj
->ipv4_addresses
[oc
], 0,
5534 sizeof(adj
->ipv4_addresses
[oc
]));
5538 struct isis_ipv4_address
*addr
= NULL
;
5539 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
5541 addr
= (struct isis_ipv4_address
*)
5542 tlvs
->ipv4_address
.head
;
5546 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
5547 sizeof(addr
->addr
)))
5551 adj
->ipv4_addresses
[i
] = addr
->addr
;
5555 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
, false);
5558 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5559 struct isis_adjacency
*adj
,
5562 bool ipv6_enabled
= false;
5564 if (adj
->ll_ipv6_count
== 0 && tlvs
->ipv6_address
.count
> 0)
5565 ipv6_enabled
= true;
5566 else if (adj
->ll_ipv6_count
> 0 && tlvs
->ipv6_address
.count
== 0)
5567 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, false);
5569 if (adj
->ll_ipv6_count
!= tlvs
->ipv6_address
.count
) {
5570 uint32_t oc
= adj
->ll_ipv6_count
;
5573 adj
->ll_ipv6_count
= tlvs
->ipv6_address
.count
;
5574 adj
->ll_ipv6_addrs
= XREALLOC(
5575 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
,
5576 adj
->ll_ipv6_count
* sizeof(*adj
->ll_ipv6_addrs
));
5578 for (; oc
< adj
->ll_ipv6_count
; oc
++) {
5579 memset(&adj
->ll_ipv6_addrs
[oc
], 0,
5580 sizeof(adj
->ll_ipv6_addrs
[oc
]));
5584 struct isis_ipv6_address
*addr
= NULL
;
5585 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
5587 addr
= (struct isis_ipv6_address
*)
5588 tlvs
->ipv6_address
.head
;
5592 if (!memcmp(&adj
->ll_ipv6_addrs
[i
], &addr
->addr
,
5593 sizeof(addr
->addr
)))
5597 adj
->ll_ipv6_addrs
[i
] = addr
->addr
;
5601 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, false);
5605 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5606 struct isis_adjacency
*adj
,
5609 bool global_ipv6_enabled
= false;
5611 if (adj
->global_ipv6_count
== 0 && tlvs
->global_ipv6_address
.count
> 0)
5612 global_ipv6_enabled
= true;
5613 else if (adj
->global_ipv6_count
> 0
5614 && tlvs
->global_ipv6_address
.count
== 0)
5615 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, true);
5617 if (adj
->global_ipv6_count
!= tlvs
->global_ipv6_address
.count
) {
5618 uint32_t oc
= adj
->global_ipv6_count
;
5621 adj
->global_ipv6_count
= tlvs
->global_ipv6_address
.count
;
5622 adj
->global_ipv6_addrs
= XREALLOC(
5623 MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
,
5624 adj
->global_ipv6_count
5625 * sizeof(*adj
->global_ipv6_addrs
));
5627 for (; oc
< adj
->global_ipv6_count
; oc
++) {
5628 memset(&adj
->global_ipv6_addrs
[oc
], 0,
5629 sizeof(adj
->global_ipv6_addrs
[oc
]));
5633 struct isis_ipv6_address
*addr
= NULL
;
5634 for (unsigned int i
= 0; i
< tlvs
->global_ipv6_address
.count
; i
++) {
5636 addr
= (struct isis_ipv6_address
*)
5637 tlvs
->global_ipv6_address
.head
;
5641 if (!memcmp(&adj
->global_ipv6_addrs
[i
], &addr
->addr
,
5642 sizeof(addr
->addr
)))
5646 adj
->global_ipv6_addrs
[i
] = addr
->addr
;
5649 if (global_ipv6_enabled
)
5650 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, true);
5653 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
5658 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
5659 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
5660 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
5661 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5662 tlvs_global_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5665 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
5667 struct isis_lan_neighbor
*ne_head
;
5669 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
5670 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
5671 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
5678 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
5680 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
5682 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
5683 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
5684 entry
->checksum
= lsp
->hdr
.checksum
;
5685 entry
->seqno
= lsp
->hdr
.seqno
;
5688 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
5691 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
5692 uint8_t *stop_id
, uint16_t num_lsps
,
5693 struct lspdb_head
*head
,
5694 struct isis_lsp
**last_lsp
)
5696 struct isis_lsp searchfor
;
5697 struct isis_lsp
*first
, *lsp
;
5699 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
5700 first
= lspdb_find_gteq(head
, &searchfor
);
5704 frr_each_from (lspdb
, head
, lsp
, first
) {
5705 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
5706 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
5709 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
5714 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
5715 const char *hostname
)
5717 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
5719 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
5722 /* Set Router Capability TLV parameters */
5723 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
5724 const struct isis_router_cap
*cap
)
5726 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
5730 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
5731 *tlvs
->router_cap
= *cap
;
5734 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
5735 const struct in_addr
*id
)
5737 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
5740 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5741 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
5744 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs
*tlvs
,
5745 const struct in6_addr
*id
)
5747 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id_ipv6
);
5750 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5751 memcpy(tlvs
->te_router_id_ipv6
, id
, sizeof(*id
));
5754 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
5755 struct prefix_ipv4
*dest
, uint8_t metric
)
5757 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5760 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5761 apply_mask_ipv4(&r
->prefix
);
5762 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
5765 /* Add IS-IS SR Adjacency-SID subTLVs */
5766 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
5767 struct isis_adj_sid
*adj
)
5769 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5770 SET_SUBTLV(exts
, EXT_ADJ_SID
);
5773 /* Delete IS-IS SR Adjacency-SID subTLVs */
5774 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
5775 struct isis_adj_sid
*adj
)
5777 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5778 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
5779 if (exts
->adj_sid
.count
== 0)
5780 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
5783 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
5784 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5785 struct isis_lan_adj_sid
*lan
)
5787 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5788 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5791 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
5792 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5793 struct isis_lan_adj_sid
*lan
)
5795 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5796 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
5797 if (exts
->lan_sid
.count
== 0)
5798 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5801 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
5802 struct prefix_ipv4
*dest
, uint32_t metric
,
5803 bool external
, struct sr_prefix_cfg
*pcfg
)
5805 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5808 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5809 apply_mask_ipv4(&r
->prefix
);
5811 struct isis_prefix_sid
*psid
=
5812 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5814 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5815 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5816 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5818 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
5821 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5822 struct prefix_ipv6
*dest
, uint32_t metric
,
5823 bool external
, struct sr_prefix_cfg
*pcfg
)
5825 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5828 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5829 apply_mask_ipv6(&r
->prefix
);
5831 struct isis_prefix_sid
*psid
=
5832 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5834 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5835 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5836 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5839 struct isis_item_list
*l
;
5840 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
5842 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
5843 append_item(l
, (struct isis_item
*)r
);
5846 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5847 struct prefix_ipv6
*dest
,
5848 struct prefix_ipv6
*src
,
5851 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
5852 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
5855 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
5856 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
5857 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
5858 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
5861 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
5864 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5867 memcpy(r
->id
, id
, sizeof(r
->id
));
5868 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
5871 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5872 uint8_t *id
, uint32_t metric
,
5873 struct isis_ext_subtlvs
*exts
)
5875 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5877 memcpy(r
->id
, id
, sizeof(r
->id
));
5880 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
5882 struct isis_item_list
*l
;
5883 if ((mtid
== ISIS_MT_IPV4_UNICAST
) || (mtid
== ISIS_MT_DISABLE
))
5884 l
= &tlvs
->extended_reach
;
5886 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
5887 append_item(l
, (struct isis_item
*)r
);
5890 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
5891 enum isis_threeway_state state
,
5892 uint32_t local_circuit_id
,
5893 const uint8_t *neighbor_id
,
5894 uint32_t neighbor_circuit_id
)
5896 assert(!tlvs
->threeway_adj
);
5898 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
5899 tlvs
->threeway_adj
->state
= state
;
5900 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
5903 tlvs
->threeway_adj
->neighbor_set
= true;
5904 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
5905 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
5909 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
5910 bool has_tier
, bool is_leaf
, bool is_spine
,
5913 assert(!tlvs
->spine_leaf
);
5915 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
5918 tlvs
->spine_leaf
->tier
= tier
;
5921 tlvs
->spine_leaf
->has_tier
= has_tier
;
5922 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
5923 tlvs
->spine_leaf
->is_spine
= is_spine
;
5924 tlvs
->spine_leaf
->is_backup
= is_backup
;
5927 struct isis_mt_router_info
*
5928 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
5930 if (!tlvs
|| tlvs
->mt_router_info_empty
)
5933 struct isis_mt_router_info
*rv
;
5934 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
5936 if (rv
->mtid
== mtid
)
5943 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
5944 const uint8_t *generator
,
5945 const uint8_t *sender
)
5947 assert(!tlvs
->purge_originator
);
5949 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
5950 sizeof(*tlvs
->purge_originator
));
5951 memcpy(tlvs
->purge_originator
->generator
, generator
,
5952 sizeof(tlvs
->purge_originator
->generator
));
5954 tlvs
->purge_originator
->sender_set
= true;
5955 memcpy(tlvs
->purge_originator
->sender
, sender
,
5956 sizeof(tlvs
->purge_originator
->sender
));