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
);
142 void isis_del_ext_subtlvs(struct isis_ext_subtlvs
*ext
)
144 struct isis_item
*item
, *next_item
;
149 /* First, free Adj SID and LAN Adj SID list if needed */
150 for (item
= ext
->adj_sid
.head
; item
; item
= next_item
) {
151 next_item
= item
->next
;
152 XFREE(MTYPE_ISIS_SUBTLV
, item
);
154 for (item
= ext
->lan_sid
.head
; item
; item
= next_item
) {
155 next_item
= item
->next
;
156 XFREE(MTYPE_ISIS_SUBTLV
, item
);
158 XFREE(MTYPE_ISIS_SUBTLV
, ext
);
162 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
163 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
164 * that MT is disabled i.e. IS-IS is working with a Single Topology.
166 static struct isis_ext_subtlvs
*
167 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, uint16_t mtid
)
169 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
170 struct isis_adj_sid
*adj
;
171 struct isis_lan_adj_sid
*lan
;
173 /* Copy the Extended IS main part */
174 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
176 /* Disable IPv4 / IPv6 advertisement in function of MTID */
177 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
178 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR6
);
179 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR6
);
181 if (mtid
== ISIS_MT_IPV6_UNICAST
) {
182 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR
);
183 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR
);
186 /* Prepare (LAN)-Adjacency Segment Routing ID*/
187 init_item_list(&rv
->adj_sid
);
188 init_item_list(&rv
->lan_sid
);
190 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
191 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
193 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
194 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
196 if ((mtid
!= ISIS_MT_DISABLE
)
197 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
198 && (adj
->family
!= AF_INET
))
199 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
200 && (adj
->family
!= AF_INET6
))))
203 struct isis_adj_sid
*new;
205 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
206 new->family
= adj
->family
;
207 new->flags
= adj
->flags
;
208 new->weight
= adj
->weight
;
210 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
211 SET_SUBTLV(rv
, EXT_ADJ_SID
);
214 /* Same for LAN Adj SID */
215 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
217 if ((mtid
!= ISIS_MT_DISABLE
)
218 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
219 && (lan
->family
!= AF_INET
))
220 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
221 && (lan
->family
!= AF_INET6
))))
224 struct isis_lan_adj_sid
*new;
226 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
227 new->family
= lan
->family
;
228 new->flags
= lan
->flags
;
229 new->weight
= lan
->weight
;
230 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
232 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
233 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
239 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
240 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
241 struct sbuf
*buf
, struct json_object
*json
,
242 int indent
, uint16_t mtid
)
247 /* Standard metrics */
248 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
250 snprintfrr(aux_buf
, sizeof(aux_buf
), "0x%x",
252 json_object_string_add(json
, "adm-group", aux_buf
);
254 sbuf_push(buf
, indent
, "Administrative Group: 0x%x\n",
257 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
259 json_object_int_add(json
, "link-local-id",
261 json_object_int_add(json
, "link-remote-id",
264 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
266 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
270 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
272 inet_ntop(AF_INET
, &exts
->local_addr
, aux_buf
,
274 json_object_string_add(json
, "local-iface-ip", aux_buf
);
276 sbuf_push(buf
, indent
,
277 "Local Interface IP Address(es): %pI4\n",
280 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
282 inet_ntop(AF_INET
, &exts
->neigh_addr
, aux_buf
,
284 json_object_string_add(json
, "remote-iface-ip",
287 sbuf_push(buf
, indent
,
288 "Remote Interface IP Address(es): %pI4\n",
291 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
293 inet_ntop(AF_INET6
, &exts
->local_addr6
, aux_buf
,
295 json_object_string_add(json
, "local-iface-ipv6",
298 sbuf_push(buf
, indent
,
299 "Local Interface IPv6 Address(es): %pI6\n",
302 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
304 inet_ntop(AF_INET6
, &exts
->neigh_addr6
, aux_buf
,
306 json_object_string_add(json
, "remote-iface-ipv6",
309 sbuf_push(buf
, indent
,
310 "Remote Interface IPv6 Address(es): %pI6\n",
313 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
315 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
317 json_object_string_add(json
, "max-bandwith-bytes-sec",
320 sbuf_push(buf
, indent
,
321 "Maximum Bandwidth: %g (Bytes/sec)\n",
324 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
326 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
328 json_object_string_add(
329 json
, "max-res-bandwith-bytes-sec", aux_buf
);
333 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
336 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
338 struct json_object
*unrsv_json
;
339 unrsv_json
= json_object_new_object();
340 json_object_object_add(json
, "unrsv-bandwith-bytes-sec",
342 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 1) {
343 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d", j
);
344 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
346 json_object_string_add(unrsv_json
, cnt_buf
,
350 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
351 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
354 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
355 j
, exts
->unrsv_bw
[j
], j
+ 1,
356 exts
->unrsv_bw
[j
+ 1]);
360 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
362 json_object_int_add(json
, "te-metric", exts
->te_metric
);
364 sbuf_push(buf
, indent
,
365 "Traffic Engineering Metric: %u\n",
368 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
370 json_object_int_add(json
, "inter-as-te-remote-as",
373 sbuf_push(buf
, indent
,
374 "Inter-AS TE Remote AS number: %u\n",
377 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
379 inet_ntop(AF_INET6
, &exts
->remote_ip
, aux_buf
,
381 json_object_string_add(
382 json
, "inter-as-te-remote-asbr-ip", aux_buf
);
384 sbuf_push(buf
, indent
,
385 "Inter-AS TE Remote ASBR IP address: %pI4\n",
388 /* Extended metrics */
389 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
391 struct json_object
*avg_json
;
392 avg_json
= json_object_new_object();
393 json_object_object_add(json
, "avg-delay", avg_json
);
394 json_object_string_add(avg_json
, "delay",
395 IS_ANORMAL(exts
->delay
)
398 json_object_int_add(avg_json
, "micro-sec", exts
->delay
);
400 sbuf_push(buf
, indent
,
401 "%s Average Link Delay: %u (micro-sec)\n",
402 IS_ANORMAL(exts
->delay
) ? "Anomalous"
406 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
408 struct json_object
*avg_json
;
409 avg_json
= json_object_new_object();
410 json_object_object_add(json
, "max-min-delay", avg_json
);
411 json_object_string_add(avg_json
, "delay",
412 IS_ANORMAL(exts
->min_delay
)
415 snprintfrr(aux_buf
, sizeof(aux_buf
), "%u / %u",
416 exts
->min_delay
& TE_EXT_MASK
,
417 exts
->max_delay
& TE_EXT_MASK
);
418 json_object_string_add(avg_json
, "micro-sec", aux_buf
);
423 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
424 IS_ANORMAL(exts
->min_delay
) ? "Anomalous"
426 exts
->min_delay
& TE_EXT_MASK
,
427 exts
->max_delay
& TE_EXT_MASK
);
429 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
431 json_object_int_add(json
, "delay-variation-micro-sec",
432 exts
->delay_var
& TE_EXT_MASK
);
434 sbuf_push(buf
, indent
,
435 "Delay Variation: %u (micro-sec)\n",
436 exts
->delay_var
& TE_EXT_MASK
);
438 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
440 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
441 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
443 struct json_object
*link_json
;
444 link_json
= json_object_new_object();
445 json_object_object_add(json
, "link-packet-loss",
447 json_object_string_add(link_json
, "loss",
448 IS_ANORMAL(exts
->pkt_loss
)
451 json_object_string_add(link_json
, "percentaje",
454 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
455 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous"
457 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
460 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
462 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
464 json_object_string_add(json
,
465 "unidir-residual-band-bytes-sec",
470 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
473 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
475 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
477 json_object_string_add(
478 json
, "unidir-available-band-bytes-sec",
483 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
486 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
488 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
490 json_object_string_add(json
,
491 "unidir-utilized-band-bytes-sec",
496 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
499 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
500 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
501 struct isis_adj_sid
*adj
;
504 struct json_object
*arr_adj_json
, *flags_json
;
505 arr_adj_json
= json_object_new_array();
506 json_object_object_add(json
, "adj-sid", arr_adj_json
);
507 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
508 adj
; adj
= adj
->next
) {
509 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
511 flags_json
= json_object_new_object();
512 json_object_int_add(flags_json
, "sid",
514 json_object_int_add(flags_json
, "weight",
516 json_object_string_add(
517 flags_json
, "flag-f",
518 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
521 json_object_string_add(
522 flags_json
, "flag-b",
523 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
526 json_object_string_add(
527 flags_json
, "flag-v",
528 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
531 json_object_string_add(
532 flags_json
, "flag-l",
533 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
536 json_object_string_add(
537 flags_json
, "flag-s",
538 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
541 json_object_string_add(
542 flags_json
, "flag-p",
543 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
546 json_object_array_add(arr_adj_json
, flags_json
);
549 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
550 adj
; adj
= adj
->next
) {
553 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
554 adj
->sid
, adj
->weight
,
555 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
558 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
561 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
564 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
567 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
570 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
575 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
576 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
577 struct isis_lan_adj_sid
*lan
;
579 struct json_object
*arr_adj_json
, *flags_json
;
580 arr_adj_json
= json_object_new_array();
581 json_object_object_add(json
, "lan-adj-sid",
583 for (lan
= (struct isis_lan_adj_sid
*)
585 lan
; lan
= lan
->next
) {
586 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
587 (lan
->family
!= AF_INET
)) ||
588 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
589 (lan
->family
!= AF_INET6
)))
591 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
593 flags_json
= json_object_new_object();
594 json_object_int_add(flags_json
, "sid",
596 json_object_int_add(flags_json
, "weight",
598 json_object_string_add(
599 flags_json
, "flag-f",
600 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
603 json_object_string_add(
604 flags_json
, "flag-b",
605 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
608 json_object_string_add(
609 flags_json
, "flag-v",
610 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
613 json_object_string_add(
614 flags_json
, "flag-l",
615 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
618 json_object_string_add(
619 flags_json
, "flag-s",
620 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
623 json_object_string_add(
624 flags_json
, "flag-p",
625 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
628 json_object_array_add(arr_adj_json
, flags_json
);
632 for (lan
= (struct isis_lan_adj_sid
*)
634 lan
; lan
= lan
->next
) {
635 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
636 (lan
->family
!= AF_INET
)) ||
637 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
638 (lan
->family
!= AF_INET6
)))
642 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
643 " Neighbor-ID: %s\n",
644 lan
->sid
, lan
->weight
,
645 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
648 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
651 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
654 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
657 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
660 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
663 isis_format_id(lan
->neighbor_id
, 6));
668 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
670 isis_del_ext_subtlvs(exts
);
673 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
674 struct stream
*s
, size_t *min_len
)
678 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
679 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
683 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
684 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
685 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
686 stream_putl(s
, exts
->adm_group
);
688 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
689 stream_putc(s
, ISIS_SUBTLV_LLRI
);
690 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
691 stream_putl(s
, exts
->local_llri
);
692 stream_putl(s
, exts
->remote_llri
);
694 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
695 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
696 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
697 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
699 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
700 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
701 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
702 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
704 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
705 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
706 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
707 stream_put(s
, &exts
->local_addr6
, 16);
709 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
710 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
711 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
712 stream_put(s
, &exts
->neigh_addr6
, 16);
714 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
715 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
716 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
717 stream_putf(s
, exts
->max_bw
);
719 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
720 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
721 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
722 stream_putf(s
, exts
->max_rsv_bw
);
724 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
725 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
726 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
727 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
728 stream_putf(s
, exts
->unrsv_bw
[j
]);
730 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
731 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
732 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
733 stream_put3(s
, exts
->te_metric
);
735 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
736 stream_putc(s
, ISIS_SUBTLV_RAS
);
737 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
738 stream_putl(s
, exts
->remote_as
);
740 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
741 stream_putc(s
, ISIS_SUBTLV_RIP
);
742 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
743 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
745 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
746 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
747 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
748 stream_putl(s
, exts
->delay
);
750 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
751 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
752 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
753 stream_putl(s
, exts
->min_delay
);
754 stream_putl(s
, exts
->max_delay
);
756 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
757 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
758 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
759 stream_putl(s
, exts
->delay_var
);
761 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
762 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
763 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
764 stream_putl(s
, exts
->pkt_loss
);
766 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
767 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
768 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
769 stream_putf(s
, exts
->res_bw
);
771 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
772 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
773 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
774 stream_putf(s
, exts
->ava_bw
);
776 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
777 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
778 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
779 stream_putf(s
, exts
->use_bw
);
781 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
782 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
783 struct isis_adj_sid
*adj
;
785 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
787 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
788 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
789 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
791 stream_putc(s
, size
);
792 stream_putc(s
, adj
->flags
);
793 stream_putc(s
, adj
->weight
);
794 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
795 stream_put3(s
, adj
->sid
);
797 stream_putl(s
, adj
->sid
);
801 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
802 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
803 struct isis_lan_adj_sid
*lan
;
805 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
807 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
808 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
809 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
811 stream_putc(s
, size
);
812 stream_putc(s
, lan
->flags
);
813 stream_putc(s
, lan
->weight
);
814 stream_put(s
, lan
->neighbor_id
, 6);
815 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
816 stream_put3(s
, lan
->sid
);
818 stream_putl(s
, lan
->sid
);
825 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
826 struct sbuf
*log
, void *dest
, int indent
)
832 struct isis_extended_reach
*rv
= dest
;
833 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
838 * Parse subTLVs until reach subTLV length
839 * Check that it remains at least 2 bytes: subTLV Type & Length
841 while (len
> sum
+ 2) {
842 /* Read SubTLV Type and Length */
843 subtlv_type
= stream_getc(s
);
844 subtlv_len
= stream_getc(s
);
845 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
848 "TLV %hhu: Available data %u is less than TLV size %u !\n",
849 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
854 switch (subtlv_type
) {
855 /* Standard Metric as defined in RFC5305 */
856 case ISIS_SUBTLV_ADMIN_GRP
:
857 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
858 sbuf_push(log
, indent
,
859 "TLV size does not match expected size for Administrative Group!\n");
860 stream_forward_getp(s
, subtlv_len
);
862 exts
->adm_group
= stream_getl(s
);
863 SET_SUBTLV(exts
, EXT_ADM_GRP
);
866 case ISIS_SUBTLV_LLRI
:
867 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
868 sbuf_push(log
, indent
,
869 "TLV size does not match expected size for Link ID!\n");
870 stream_forward_getp(s
, subtlv_len
);
872 exts
->local_llri
= stream_getl(s
);
873 exts
->remote_llri
= stream_getl(s
);
874 SET_SUBTLV(exts
, EXT_LLRI
);
877 case ISIS_SUBTLV_LOCAL_IPADDR
:
878 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
879 sbuf_push(log
, indent
,
880 "TLV size does not match expected size for Local IP address!\n");
881 stream_forward_getp(s
, subtlv_len
);
883 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
884 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
887 case ISIS_SUBTLV_RMT_IPADDR
:
888 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
889 sbuf_push(log
, indent
,
890 "TLV size does not match expected size for Remote IP address!\n");
891 stream_forward_getp(s
, subtlv_len
);
893 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
894 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
897 case ISIS_SUBTLV_LOCAL_IPADDR6
:
898 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
899 sbuf_push(log
, indent
,
900 "TLV size does not match expected size for Local IPv6 address!\n");
901 stream_forward_getp(s
, subtlv_len
);
903 stream_get(&exts
->local_addr6
, s
, 16);
904 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
907 case ISIS_SUBTLV_RMT_IPADDR6
:
908 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
909 sbuf_push(log
, indent
,
910 "TLV size does not match expected size for Remote IPv6 address!\n");
911 stream_forward_getp(s
, subtlv_len
);
913 stream_get(&exts
->neigh_addr6
, s
, 16);
914 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
917 case ISIS_SUBTLV_MAX_BW
:
918 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
919 sbuf_push(log
, indent
,
920 "TLV size does not match expected size for Maximum Bandwidth!\n");
921 stream_forward_getp(s
, subtlv_len
);
923 exts
->max_bw
= stream_getf(s
);
924 SET_SUBTLV(exts
, EXT_MAX_BW
);
927 case ISIS_SUBTLV_MAX_RSV_BW
:
928 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
929 sbuf_push(log
, indent
,
930 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
931 stream_forward_getp(s
, subtlv_len
);
933 exts
->max_rsv_bw
= stream_getf(s
);
934 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
937 case ISIS_SUBTLV_UNRSV_BW
:
938 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
939 sbuf_push(log
, indent
,
940 "TLV size does not match expected size for Unreserved Bandwidth!\n");
941 stream_forward_getp(s
, subtlv_len
);
943 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
944 exts
->unrsv_bw
[i
] = stream_getf(s
);
945 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
948 case ISIS_SUBTLV_TE_METRIC
:
949 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
950 sbuf_push(log
, indent
,
951 "TLV size does not match expected size for Traffic Engineering Metric!\n");
952 stream_forward_getp(s
, subtlv_len
);
954 exts
->te_metric
= stream_get3(s
);
955 SET_SUBTLV(exts
, EXT_TE_METRIC
);
958 case ISIS_SUBTLV_RAS
:
959 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
960 sbuf_push(log
, indent
,
961 "TLV size does not match expected size for Remote AS number!\n");
962 stream_forward_getp(s
, subtlv_len
);
964 exts
->remote_as
= stream_getl(s
);
965 SET_SUBTLV(exts
, EXT_RMT_AS
);
968 case ISIS_SUBTLV_RIP
:
969 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
970 sbuf_push(log
, indent
,
971 "TLV size does not match expected size for Remote ASBR IP Address!\n");
972 stream_forward_getp(s
, subtlv_len
);
974 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
975 SET_SUBTLV(exts
, EXT_RMT_IP
);
978 /* Extended Metrics as defined in RFC 7810 */
979 case ISIS_SUBTLV_AV_DELAY
:
980 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
981 sbuf_push(log
, indent
,
982 "TLV size does not match expected size for Average Link Delay!\n");
983 stream_forward_getp(s
, subtlv_len
);
985 exts
->delay
= stream_getl(s
);
986 SET_SUBTLV(exts
, EXT_DELAY
);
989 case ISIS_SUBTLV_MM_DELAY
:
990 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
991 sbuf_push(log
, indent
,
992 "TLV size does not match expected size for Min/Max Link Delay!\n");
993 stream_forward_getp(s
, subtlv_len
);
995 exts
->min_delay
= stream_getl(s
);
996 exts
->max_delay
= stream_getl(s
);
997 SET_SUBTLV(exts
, EXT_MM_DELAY
);
1000 case ISIS_SUBTLV_DELAY_VAR
:
1001 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1002 sbuf_push(log
, indent
,
1003 "TLV size does not match expected size for Delay Variation!\n");
1004 stream_forward_getp(s
, subtlv_len
);
1006 exts
->delay_var
= stream_getl(s
);
1007 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
1010 case ISIS_SUBTLV_PKT_LOSS
:
1011 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1012 sbuf_push(log
, indent
,
1013 "TLV size does not match expected size for Link Packet Loss!\n");
1014 stream_forward_getp(s
, subtlv_len
);
1016 exts
->pkt_loss
= stream_getl(s
);
1017 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
1020 case ISIS_SUBTLV_RES_BW
:
1021 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1022 sbuf_push(log
, indent
,
1023 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
1024 stream_forward_getp(s
, subtlv_len
);
1026 exts
->res_bw
= stream_getf(s
);
1027 SET_SUBTLV(exts
, EXT_RES_BW
);
1030 case ISIS_SUBTLV_AVA_BW
:
1031 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1032 sbuf_push(log
, indent
,
1033 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
1034 stream_forward_getp(s
, subtlv_len
);
1036 exts
->ava_bw
= stream_getf(s
);
1037 SET_SUBTLV(exts
, EXT_AVA_BW
);
1040 case ISIS_SUBTLV_USE_BW
:
1041 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1042 sbuf_push(log
, indent
,
1043 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
1044 stream_forward_getp(s
, subtlv_len
);
1046 exts
->use_bw
= stream_getf(s
);
1047 SET_SUBTLV(exts
, EXT_USE_BW
);
1050 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1051 case ISIS_SUBTLV_ADJ_SID
:
1052 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
1053 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
1054 sbuf_push(log
, indent
,
1055 "TLV size does not match expected size for Adjacency SID!\n");
1056 stream_forward_getp(s
, subtlv_len
);
1058 struct isis_adj_sid
*adj
;
1060 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1061 sizeof(struct isis_adj_sid
));
1062 adj
->flags
= stream_getc(s
);
1063 adj
->weight
= stream_getc(s
);
1064 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1065 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
1068 "TLV size does not match expected size for Adjacency SID!\n");
1069 stream_forward_getp(s
, subtlv_len
- 2);
1070 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
1074 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1076 != ISIS_SUBTLV_ADJ_SID_SIZE
1080 "TLV size does not match expected size for Adjacency SID!\n");
1081 stream_forward_getp(s
, subtlv_len
- 2);
1082 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
1086 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1087 adj
->sid
= stream_get3(s
);
1088 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
1090 adj
->sid
= stream_getl(s
);
1092 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1093 adj
->family
= AF_INET
;
1094 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1095 adj
->family
= AF_INET6
;
1096 append_item(&exts
->adj_sid
,
1097 (struct isis_item
*)adj
);
1098 SET_SUBTLV(exts
, EXT_ADJ_SID
);
1101 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1102 case ISIS_SUBTLV_LAN_ADJ_SID
:
1103 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1104 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
1105 sbuf_push(log
, indent
,
1106 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1107 stream_forward_getp(s
, subtlv_len
);
1109 struct isis_lan_adj_sid
*lan
;
1111 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1112 sizeof(struct isis_lan_adj_sid
));
1113 lan
->flags
= stream_getc(s
);
1114 lan
->weight
= stream_getc(s
);
1115 stream_get(&(lan
->neighbor_id
), s
,
1118 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1120 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
1123 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1124 stream_forward_getp(
1127 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
1131 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1133 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1137 "TLV size does not match expected size for LAN-Adjacency SID!\n");
1138 stream_forward_getp(
1141 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
1145 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1146 lan
->sid
= stream_get3(s
);
1147 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
1149 lan
->sid
= stream_getl(s
);
1151 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1152 lan
->family
= AF_INET
;
1153 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1154 lan
->family
= AF_INET6
;
1155 append_item(&exts
->lan_sid
,
1156 (struct isis_item
*)lan
);
1157 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
1161 /* Skip unknown TLV */
1162 stream_forward_getp(s
, subtlv_len
);
1165 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
1171 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1172 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
1174 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1175 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1177 rv
->flags
= sid
->flags
;
1178 rv
->algorithm
= sid
->algorithm
;
1179 rv
->value
= sid
->value
;
1180 return (struct isis_item
*)rv
;
1183 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
1184 struct sbuf
*buf
, struct json_object
*json
,
1187 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1190 struct json_object
*sr_json
;
1191 sr_json
= json_object_new_object();
1192 json_object_object_add(json
, "sr", sr_json
);
1193 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1194 json_object_int_add(sr_json
, "label", sid
->value
);
1196 json_object_int_add(sr_json
, "index", sid
->value
);
1198 json_object_int_add(sr_json
, "alg", sid
->algorithm
);
1199 json_object_string_add(
1200 sr_json
, "readvertised",
1201 ((sid
->flags
& ISIS_PREFIX_SID_READVERTISED
) ? "yes"
1203 json_object_string_add(
1205 ((sid
->flags
& ISIS_PREFIX_SID_NODE
) ? "yes" : ""));
1206 json_object_string_add(sr_json
, "php",
1207 ((sid
->flags
& ISIS_PREFIX_SID_NO_PHP
)
1210 json_object_string_add(
1211 sr_json
, "explicit-null",
1212 ((sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
) ? "yes"
1214 json_object_string_add(
1216 ((sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? "yes" : ""));
1217 json_object_string_add(
1219 ((sid
->flags
& ISIS_PREFIX_SID_LOCAL
) ? "yes" : ""));
1222 sbuf_push(buf
, indent
, "SR Prefix-SID ");
1223 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1224 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
1226 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
1228 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
1229 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
1230 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
1233 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
1234 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP"
1236 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
1239 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
1240 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
1244 static void free_item_prefix_sid(struct isis_item
*i
)
1246 XFREE(MTYPE_ISIS_SUBTLV
, i
);
1249 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
1252 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1254 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
1256 if (STREAM_WRITEABLE(s
) < size
) {
1261 stream_putc(s
, sid
->flags
);
1262 stream_putc(s
, sid
->algorithm
);
1264 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1265 stream_put3(s
, sid
->value
);
1267 stream_putl(s
, sid
->value
);
1273 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1274 struct sbuf
*log
, void *dest
, int indent
)
1276 struct isis_subtlvs
*subtlvs
= dest
;
1277 struct isis_prefix_sid sid
= {
1280 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
1283 sbuf_push(log
, indent
,
1284 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1289 sid
.flags
= stream_getc(s
);
1290 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1291 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
1292 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
1296 sid
.algorithm
= stream_getc(s
);
1298 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1299 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1300 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
1301 if (len
!= expected_size
) {
1302 sbuf_push(log
, indent
,
1303 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1304 expected_size
, len
);
1308 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
1309 sid
.value
= stream_get3(s
);
1310 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
1311 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
1316 sid
.value
= stream_getl(s
);
1319 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, NULL
, indent
+ 2);
1320 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
1324 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1326 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
1331 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1332 rv
->family
= p
->family
;
1333 rv
->prefixlen
= p
->prefixlen
;
1334 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
1338 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1340 struct json_object
*json
,
1346 char prefixbuf
[PREFIX2STR_BUFFER
];
1348 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
));
1349 json_object_string_add(json
, "ipv6-src-prefix", prefixbuf
);
1351 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1352 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1356 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1362 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1365 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1366 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1367 stream_putc(s
, p
->prefixlen
);
1368 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1372 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1373 uint8_t tlv_type
, uint8_t tlv_len
,
1374 struct stream
*s
, struct sbuf
*log
,
1375 void *dest
, int indent
)
1377 struct isis_subtlvs
*subtlvs
= dest
;
1378 struct prefix_ipv6 p
= {
1382 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1385 sbuf_push(log
, indent
,
1386 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1391 p
.prefixlen
= stream_getc(s
);
1392 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1393 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1398 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1401 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1402 1 + PSIZE(p
.prefixlen
), tlv_len
);
1406 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1408 if (subtlvs
->source_prefix
) {
1411 "WARNING: source prefix Sub-TLV present multiple times.\n");
1412 /* Ignore all but first occurrence of the source prefix Sub-TLV
1417 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1418 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1422 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1423 enum isis_tlv_type type
,
1424 struct isis_item
*item
);
1425 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1426 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1427 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1428 enum isis_tlv_type type
, struct isis_item_list
*items
,
1429 struct sbuf
*buf
, struct json_object
*json
,
1431 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1432 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1433 struct isis_item_list
*items
);
1434 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1435 enum isis_tlv_type type
, struct isis_item_list
*items
,
1436 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1437 const struct pack_order_entry
*pe
,
1438 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1439 struct list
*new_fragment_arg
);
1440 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1442 /* Functions related to subtlvs */
1444 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1446 struct isis_subtlvs
*result
;
1448 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1449 result
->context
= context
;
1451 init_item_list(&result
->prefix_sids
);
1456 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1461 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1463 rv
->context
= subtlvs
->context
;
1465 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1466 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1469 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1473 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1474 struct json_object
*json
, int indent
)
1476 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1477 &subtlvs
->prefix_sids
, buf
, json
, indent
);
1479 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, json
, indent
);
1482 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1487 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1488 &subtlvs
->prefix_sids
);
1490 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1492 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1495 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1498 size_t subtlv_len_pos
= stream_get_endp(s
);
1500 if (STREAM_WRITEABLE(s
) < 1)
1503 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1505 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1506 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1510 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1514 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1515 if (subtlv_len
> 255)
1518 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1522 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1523 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1524 int indent
, bool *unpacked_known_tlvs
);
1526 /* Functions related to TLVs 1 Area Addresses */
1528 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1530 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1531 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1533 rv
->len
= addr
->len
;
1534 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1535 return (struct isis_item
*)rv
;
1538 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1539 struct sbuf
*buf
, struct json_object
*json
,
1542 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1545 json_object_string_add(json
, "area-addr",
1546 isonet_print(addr
->addr
, addr
->len
));
1548 sbuf_push(buf
, indent
, "Area Address: %s\n",
1549 isonet_print(addr
->addr
, addr
->len
));
1553 static void free_item_area_address(struct isis_item
*i
)
1555 XFREE(MTYPE_ISIS_TLV
, i
);
1558 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
1561 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1563 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
1564 *min_len
= (unsigned)1 + addr
->len
;
1567 stream_putc(s
, addr
->len
);
1568 stream_put(s
, addr
->addr
, addr
->len
);
1572 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1573 struct stream
*s
, struct sbuf
*log
,
1574 void *dest
, int indent
)
1576 struct isis_tlvs
*tlvs
= dest
;
1577 struct isis_area_address
*rv
= NULL
;
1579 sbuf_push(log
, indent
, "Unpack area address...\n");
1583 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1588 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1589 rv
->len
= stream_getc(s
);
1591 if (len
< 1 + rv
->len
) {
1592 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1597 if (rv
->len
< 1 || rv
->len
> 20) {
1598 sbuf_push(log
, indent
,
1599 "Implausible area address length %hhu\n",
1604 stream_get(rv
->addr
, s
, rv
->len
);
1606 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1607 log
, NULL
, indent
+ 2);
1608 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1611 XFREE(MTYPE_ISIS_TLV
, rv
);
1615 /* Functions related to TLV 2 (Old-Style) IS Reach */
1616 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1618 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1619 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1621 memcpy(rv
->id
, r
->id
, 7);
1622 rv
->metric
= r
->metric
;
1623 return (struct isis_item
*)rv
;
1626 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1628 struct json_object
*json
, int indent
)
1630 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1633 struct json_object
*old_json
;
1634 old_json
= json_object_new_object();
1635 json_object_object_add(json
, "old-reach-style", old_json
);
1636 json_object_string_add(old_json
, "is-reach",
1637 isis_format_id(r
->id
, 7));
1638 json_object_int_add(old_json
, "metric", r
->metric
);
1640 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
1641 isis_format_id(r
->id
, 7), r
->metric
);
1644 static void free_item_oldstyle_reach(struct isis_item
*i
)
1646 XFREE(MTYPE_ISIS_TLV
, i
);
1649 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
1652 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1654 if (STREAM_WRITEABLE(s
) < 11) {
1659 stream_putc(s
, r
->metric
);
1660 stream_putc(s
, 0x80); /* delay metric - unsupported */
1661 stream_putc(s
, 0x80); /* expense metric - unsupported */
1662 stream_putc(s
, 0x80); /* error metric - unsupported */
1663 stream_put(s
, r
->id
, 7);
1668 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1669 struct stream
*s
, struct sbuf
*log
,
1670 void *dest
, int indent
)
1672 struct isis_tlvs
*tlvs
= dest
;
1674 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1678 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1683 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1684 rv
->metric
= stream_getc(s
);
1685 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1686 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1689 stream_forward_getp(s
, 3); /* Skip other metrics */
1690 stream_get(rv
->id
, s
, 7);
1692 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1694 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1698 /* Functions related to TLV 6 LAN Neighbors */
1699 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1701 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1702 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1704 memcpy(rv
->mac
, n
->mac
, 6);
1705 return (struct isis_item
*)rv
;
1708 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1709 struct sbuf
*buf
, struct json_object
*json
,
1712 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1715 json_object_string_add(json
, "lan-neighbor",
1716 isis_format_id(n
->mac
, 6));
1718 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n",
1719 isis_format_id(n
->mac
, 6));
1722 static void free_item_lan_neighbor(struct isis_item
*i
)
1724 XFREE(MTYPE_ISIS_TLV
, i
);
1727 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
1730 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1732 if (STREAM_WRITEABLE(s
) < 6) {
1737 stream_put(s
, n
->mac
, 6);
1742 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1743 struct stream
*s
, struct sbuf
*log
,
1744 void *dest
, int indent
)
1746 struct isis_tlvs
*tlvs
= dest
;
1748 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1752 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1757 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1758 stream_get(rv
->mac
, s
, 6);
1760 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1761 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1765 /* Functions related to TLV 9 LSP Entry */
1766 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1768 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1769 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1771 rv
->rem_lifetime
= e
->rem_lifetime
;
1772 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1773 rv
->seqno
= e
->seqno
;
1774 rv
->checksum
= e
->checksum
;
1776 return (struct isis_item
*)rv
;
1779 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1780 struct sbuf
*buf
, struct json_object
*json
,
1783 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1787 struct json_object
*lsp_json
;
1788 lsp_json
= json_object_new_object();
1789 json_object_object_add(json
, "lsp-entry", lsp_json
);
1790 json_object_string_add(lsp_json
, "id", isis_format_id(e
->id
, 8));
1791 snprintfrr(buf
,sizeof(buf
),"0x%08x",e
->seqno
);
1792 json_object_string_add(lsp_json
, "seq", buf
);
1793 snprintfrr(buf
,sizeof(buf
),"0x%04hx",e
->checksum
);
1794 json_object_string_add(lsp_json
, "chksum", buf
);
1795 json_object_int_add(lsp_json
, "lifetime", e
->checksum
);
1797 sbuf_push(buf
, indent
,
1798 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1799 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1803 static void free_item_lsp_entry(struct isis_item
*i
)
1805 XFREE(MTYPE_ISIS_TLV
, i
);
1808 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
1811 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1813 if (STREAM_WRITEABLE(s
) < 16) {
1818 stream_putw(s
, e
->rem_lifetime
);
1819 stream_put(s
, e
->id
, 8);
1820 stream_putl(s
, e
->seqno
);
1821 stream_putw(s
, e
->checksum
);
1826 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1827 struct sbuf
*log
, void *dest
, int indent
)
1829 struct isis_tlvs
*tlvs
= dest
;
1831 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1835 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1840 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1841 rv
->rem_lifetime
= stream_getw(s
);
1842 stream_get(rv
->id
, s
, 8);
1843 rv
->seqno
= stream_getl(s
);
1844 rv
->checksum
= stream_getw(s
);
1846 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
1847 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1851 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1853 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1855 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1856 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1858 memcpy(rv
->id
, r
->id
, 7);
1859 rv
->metric
= r
->metric
;
1862 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1864 return (struct isis_item
*)rv
;
1867 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1869 struct json_object
*json
, int indent
)
1871 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1874 struct json_object
*reach_json
;
1875 reach_json
= json_object_new_object();
1876 json_object_object_add(json
, "ext-reach", reach_json
);
1877 json_object_string_add(
1878 reach_json
, "mt-id",
1879 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
1880 json_object_string_add(reach_json
, "id",
1881 isis_format_id(r
->id
, 7));
1882 json_object_int_add(reach_json
, "metric", r
->metric
);
1883 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1884 json_object_string_add(reach_json
, "mt-name",
1885 isis_mtid2str(mtid
));
1888 format_item_ext_subtlvs(r
->subtlvs
, NULL
, json
,
1891 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1892 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1893 isis_format_id(r
->id
, 7), r
->metric
);
1894 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1895 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1896 sbuf_push(buf
, 0, "\n");
1899 format_item_ext_subtlvs(r
->subtlvs
, buf
, NULL
,
1904 static void free_item_extended_reach(struct isis_item
*i
)
1906 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1908 if (item
->subtlvs
!= NULL
)
1909 free_item_ext_subtlvs(item
->subtlvs
);
1910 XFREE(MTYPE_ISIS_TLV
, item
);
1913 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
1916 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1920 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
1921 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
1925 stream_put(s
, r
->id
, sizeof(r
->id
));
1926 stream_put3(s
, r
->metric
);
1927 len_pos
= stream_get_endp(s
);
1928 /* Real length will be adjust after adding subTLVs */
1931 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
1933 len
= stream_get_endp(s
) - len_pos
- 1;
1934 stream_putc_at(s
, len_pos
, len
);
1938 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1939 struct stream
*s
, struct sbuf
*log
,
1940 void *dest
, int indent
)
1942 struct isis_tlvs
*tlvs
= dest
;
1943 struct isis_extended_reach
*rv
= NULL
;
1945 struct isis_item_list
*items
;
1947 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1948 items
= &tlvs
->extended_reach
;
1950 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1953 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1954 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1957 sbuf_push(log
, indent
,
1958 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
1963 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1964 stream_get(rv
->id
, s
, 7);
1965 rv
->metric
= stream_get3(s
);
1966 subtlv_len
= stream_getc(s
);
1968 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1969 sbuf_push(log
, indent
,
1970 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
1971 subtlv_len
, len
- 11);
1975 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
1979 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1985 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
1987 append_item(items
, (struct isis_item
*)rv
);
1991 free_item_extended_reach((struct isis_item
*)rv
);
1996 /* Functions related to TLV 128 (Old-Style) IP Reach */
1997 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1999 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2000 struct isis_oldstyle_ip_reach
*rv
=
2001 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2003 rv
->metric
= r
->metric
;
2004 rv
->prefix
= r
->prefix
;
2005 return (struct isis_item
*)rv
;
2008 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2010 struct json_object
*json
, int indent
)
2012 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2013 char prefixbuf
[PREFIX2STR_BUFFER
];
2016 struct json_object
*old_json
;
2017 old_json
= json_object_new_object();
2018 json_object_object_add(json
, "old-ip-reach-style", old_json
);
2019 json_object_string_add(old_json
, "prefix",
2020 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2021 json_object_int_add(old_json
, "metric", r
->metric
);
2023 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
2024 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2028 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
2030 XFREE(MTYPE_ISIS_TLV
, i
);
2033 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
2036 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2038 if (STREAM_WRITEABLE(s
) < 12) {
2043 stream_putc(s
, r
->metric
);
2044 stream_putc(s
, 0x80); /* delay metric - unsupported */
2045 stream_putc(s
, 0x80); /* expense metric - unsupported */
2046 stream_putc(s
, 0x80); /* error metric - unsupported */
2047 stream_put(s
, &r
->prefix
.prefix
, 4);
2049 struct in_addr mask
;
2050 masklen2ip(r
->prefix
.prefixlen
, &mask
);
2051 stream_put(s
, &mask
, sizeof(mask
));
2056 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
2057 struct stream
*s
, struct sbuf
*log
,
2058 void *dest
, int indent
)
2060 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
2064 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2069 struct isis_oldstyle_ip_reach
*rv
=
2070 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2071 rv
->metric
= stream_getc(s
);
2072 if ((rv
->metric
& 0x7f) != rv
->metric
) {
2073 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2076 stream_forward_getp(s
, 3); /* Skip other metrics */
2077 rv
->prefix
.family
= AF_INET
;
2078 stream_get(&rv
->prefix
.prefix
, s
, 4);
2080 struct in_addr mask
;
2081 stream_get(&mask
, s
, 4);
2082 rv
->prefix
.prefixlen
= ip_masklen(mask
);
2084 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2086 append_item(dest
, (struct isis_item
*)rv
);
2091 /* Functions related to TLV 129 protocols supported */
2093 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
2094 struct isis_protocols_supported
*dest
)
2096 if (!src
->protocols
|| !src
->count
)
2098 dest
->count
= src
->count
;
2099 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
2100 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
2103 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2105 struct json_object
*json
, int indent
)
2107 if (!p
|| !p
->count
|| !p
->protocols
)
2111 struct json_object
*protocol_json
;
2114 protocol_json
= json_object_new_object();
2115 json_object_object_add(json
, "protocols-supported",
2117 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2118 snprintfrr(buf
, sizeof(buf
), "%d", i
);
2119 json_object_string_add(protocol_json
, buf
,
2120 nlpid2str(p
->protocols
[i
]));
2123 sbuf_push(buf
, indent
, "Protocols Supported: ");
2124 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2125 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
2126 (i
+ 1 < p
->count
) ? ", " : "");
2128 sbuf_push(buf
, 0, "\n");
2132 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
2134 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
2137 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2140 if (!p
|| !p
->count
|| !p
->protocols
)
2143 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
2146 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
2147 stream_putc(s
, p
->count
);
2148 stream_put(s
, p
->protocols
, p
->count
);
2152 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
2153 uint8_t tlv_type
, uint8_t tlv_len
,
2154 struct stream
*s
, struct sbuf
*log
,
2155 void *dest
, int indent
)
2157 struct isis_tlvs
*tlvs
= dest
;
2159 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
2161 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
2164 if (tlvs
->protocols_supported
.protocols
) {
2167 "WARNING: protocols supported TLV present multiple times.\n");
2168 stream_forward_getp(s
, tlv_len
);
2172 tlvs
->protocols_supported
.count
= tlv_len
;
2173 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
2174 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
2176 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
, NULL
,
2181 /* Functions related to TLV 132 IPv4 Interface addresses */
2182 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
2184 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2185 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2188 return (struct isis_item
*)rv
;
2191 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
2192 struct sbuf
*buf
, struct json_object
*json
,
2195 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2196 char addrbuf
[INET_ADDRSTRLEN
];
2198 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2200 json_object_string_add(json
, "ipv4", addrbuf
);
2202 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
2206 static void free_item_ipv4_address(struct isis_item
*i
)
2208 XFREE(MTYPE_ISIS_TLV
, i
);
2211 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
2214 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2216 if (STREAM_WRITEABLE(s
) < 4) {
2221 stream_put(s
, &a
->addr
, 4);
2226 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
2227 struct stream
*s
, struct sbuf
*log
,
2228 void *dest
, int indent
)
2230 struct isis_tlvs
*tlvs
= dest
;
2232 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
2236 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2241 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2242 stream_get(&rv
->addr
, s
, 4);
2244 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2245 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
2250 /* Functions related to TLV 232 IPv6 Interface addresses */
2251 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
2253 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2254 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2257 return (struct isis_item
*)rv
;
2260 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2261 struct sbuf
*buf
, struct json_object
*json
,
2264 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2265 char addrbuf
[INET6_ADDRSTRLEN
];
2267 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2269 json_object_string_add(json
, "ipv6", addrbuf
);
2271 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
2274 static void free_item_ipv6_address(struct isis_item
*i
)
2276 XFREE(MTYPE_ISIS_TLV
, i
);
2279 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2282 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2284 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2285 *min_len
= IPV6_MAX_BYTELEN
;
2289 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2294 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
2295 struct stream
*s
, struct sbuf
*log
,
2296 void *dest
, int indent
)
2298 struct isis_tlvs
*tlvs
= dest
;
2300 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
2304 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2309 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2310 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2312 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2313 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
2318 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2319 static struct isis_item
*copy_item_global_ipv6_address(struct isis_item
*i
)
2321 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2322 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2325 return (struct isis_item
*)rv
;
2328 static void format_item_global_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2330 struct json_object
*json
,
2333 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2334 char addrbuf
[INET6_ADDRSTRLEN
];
2336 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2338 json_object_string_add(json
, "global-ipv6", addrbuf
);
2340 sbuf_push(buf
, indent
, "Global IPv6 Interface Address: %s\n",
2344 static void free_item_global_ipv6_address(struct isis_item
*i
)
2346 XFREE(MTYPE_ISIS_TLV
, i
);
2349 static int pack_item_global_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2352 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2354 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2355 *min_len
= IPV6_MAX_BYTELEN
;
2359 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2364 static int unpack_item_global_ipv6_address(uint16_t mtid
, uint8_t len
,
2365 struct stream
*s
, struct sbuf
*log
,
2366 void *dest
, int indent
)
2368 struct isis_tlvs
*tlvs
= dest
;
2370 sbuf_push(log
, indent
, "Unpack Global IPv6 Interface address...\n");
2371 if (len
< IPV6_MAX_BYTELEN
) {
2374 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2379 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2380 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2382 format_item_global_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2384 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)rv
);
2388 /* Functions related to TLV 229 MT Router information */
2389 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
2391 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2392 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2394 rv
->overload
= info
->overload
;
2395 rv
->attached
= info
->attached
;
2396 rv
->mtid
= info
->mtid
;
2397 return (struct isis_item
*)rv
;
2400 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
2402 struct json_object
*json
, int indent
)
2404 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2407 struct json_object
*mt_json
;
2408 mt_json
= json_object_new_object();
2409 json_object_object_add(json
, "mt", mt_json
);
2410 json_object_int_add(mt_json
, "mtid", info
->mtid
);
2411 json_object_string_add(mt_json
, "overload", info
->overload
?"true":"false");
2412 json_object_string_add(mt_json
, "attached", info
->attached
?"true":"false");
2414 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
2415 isis_mtid2str_fake(info
->mtid
),
2416 info
->overload
? " Overload" : "",
2417 info
->attached
? " Attached" : "");
2420 static void free_item_mt_router_info(struct isis_item
*i
)
2422 XFREE(MTYPE_ISIS_TLV
, i
);
2425 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
2428 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2430 if (STREAM_WRITEABLE(s
) < 2) {
2435 uint16_t entry
= info
->mtid
;
2438 entry
|= ISIS_MT_OL_MASK
;
2440 entry
|= ISIS_MT_AT_MASK
;
2442 stream_putw(s
, entry
);
2447 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
2448 struct stream
*s
, struct sbuf
*log
,
2449 void *dest
, int indent
)
2451 struct isis_tlvs
*tlvs
= dest
;
2453 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
2457 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2462 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2464 uint16_t entry
= stream_getw(s
);
2465 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
2466 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
2467 rv
->mtid
= entry
& ISIS_MT_MASK
;
2469 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2471 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
2475 /* Functions related to TLV 134 TE Router ID */
2477 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
2482 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2483 memcpy(rv
, id
, sizeof(*rv
));
2487 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
2488 struct json_object
*json
, int indent
)
2493 char addrbuf
[INET_ADDRSTRLEN
];
2494 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
2496 json_object_string_add(json
, "te-router-id", addrbuf
);
2498 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
2501 static void free_tlv_te_router_id(struct in_addr
*id
)
2503 XFREE(MTYPE_ISIS_TLV
, id
);
2506 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
2511 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2514 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
2516 stream_put(s
, id
, 4);
2520 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
2521 uint8_t tlv_type
, uint8_t tlv_len
,
2522 struct stream
*s
, struct sbuf
*log
,
2523 void *dest
, int indent
)
2525 struct isis_tlvs
*tlvs
= dest
;
2527 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
2529 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2533 if (tlvs
->te_router_id
) {
2534 sbuf_push(log
, indent
,
2535 "WARNING: TE Router ID present multiple times.\n");
2536 stream_forward_getp(s
, tlv_len
);
2540 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
2541 stream_get(tlvs
->te_router_id
, s
, 4);
2542 format_tlv_te_router_id(tlvs
->te_router_id
, log
, NULL
, indent
+ 2);
2547 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
2549 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
2551 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2552 struct isis_extended_ip_reach
*rv
=
2553 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2555 rv
->metric
= r
->metric
;
2557 rv
->prefix
= r
->prefix
;
2558 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2560 return (struct isis_item
*)rv
;
2563 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2565 struct json_object
*json
, int indent
)
2567 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2568 char prefixbuf
[PREFIX2STR_BUFFER
];
2571 struct json_object
*ext_json
;
2572 ext_json
= json_object_new_object();
2573 json_object_object_add(json
, "ext-ip-reach", ext_json
);
2574 json_object_string_add(
2576 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
2577 json_object_string_add(
2579 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2580 json_object_int_add(json
, "ip-reach-metric", r
->metric
);
2581 json_object_string_add(json
, "down", r
->down
? "yes" : "");
2582 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2583 json_object_string_add(json
, "mt-name",
2584 isis_mtid2str(mtid
));
2586 struct json_object
*subtlv_json
;
2587 subtlv_json
= json_object_new_object();
2588 json_object_object_add(json
, "subtlvs", subtlv_json
);
2589 format_subtlvs(r
->subtlvs
, NULL
, subtlv_json
, 0);
2592 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
2593 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2594 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2595 r
->metric
, r
->down
? " Down" : "");
2596 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2597 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2598 sbuf_push(buf
, 0, "\n");
2601 sbuf_push(buf
, indent
, " Subtlvs:\n");
2602 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
2607 static void free_item_extended_ip_reach(struct isis_item
*i
)
2609 struct isis_extended_ip_reach
*item
=
2610 (struct isis_extended_ip_reach
*)i
;
2611 isis_free_subtlvs(item
->subtlvs
);
2612 XFREE(MTYPE_ISIS_TLV
, item
);
2615 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
2618 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2621 if (STREAM_WRITEABLE(s
) < 5) {
2625 stream_putl(s
, r
->metric
);
2627 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
2628 control
|= r
->prefix
.prefixlen
;
2629 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
2631 stream_putc(s
, control
);
2633 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2634 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2637 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2640 return pack_subtlvs(r
->subtlvs
, s
);
2644 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2645 struct stream
*s
, struct sbuf
*log
,
2646 void *dest
, int indent
)
2648 struct isis_tlvs
*tlvs
= dest
;
2649 struct isis_extended_ip_reach
*rv
= NULL
;
2651 uint8_t control
, subtlv_len
;
2652 struct isis_item_list
*items
;
2654 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2655 items
= &tlvs
->extended_ip_reach
;
2657 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2660 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2661 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2664 if (len
< consume
) {
2665 sbuf_push(log
, indent
,
2666 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2671 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2673 rv
->metric
= stream_getl(s
);
2674 control
= stream_getc(s
);
2675 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2676 rv
->prefix
.family
= AF_INET
;
2677 rv
->prefix
.prefixlen
= control
& 0x3f;
2678 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
2679 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2680 rv
->prefix
.prefixlen
);
2684 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2685 if (len
< consume
) {
2686 sbuf_push(log
, indent
,
2687 "Expected %u bytes of prefix, but only %u bytes available.\n",
2688 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2691 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2692 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2693 apply_mask_ipv4(&rv
->prefix
);
2694 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2695 sbuf_push(log
, indent
+ 2,
2696 "WARNING: Prefix had hostbits set.\n");
2697 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2700 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2702 if (len
< consume
) {
2703 sbuf_push(log
, indent
,
2704 "Expected 1 byte of subtlv len, but no more data present.\n");
2707 subtlv_len
= stream_getc(s
);
2710 sbuf_push(log
, indent
+ 2,
2711 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2713 consume
+= subtlv_len
;
2714 if (len
< consume
) {
2715 sbuf_push(log
, indent
,
2716 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2718 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2722 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2723 bool unpacked_known_tlvs
= false;
2725 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2726 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2729 if (!unpacked_known_tlvs
) {
2730 isis_free_subtlvs(rv
->subtlvs
);
2735 append_item(items
, (struct isis_item
*)rv
);
2739 free_item_extended_ip_reach((struct isis_item
*)rv
);
2743 /* Functions related to TLV 137 Dynamic Hostname */
2745 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2750 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2753 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2754 struct json_object
*json
, int indent
)
2760 json_object_string_add(json
, "hostname", hostname
);
2762 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2765 static void free_tlv_dynamic_hostname(char *hostname
)
2767 XFREE(MTYPE_ISIS_TLV
, hostname
);
2770 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2775 uint8_t name_len
= strlen(hostname
);
2777 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2780 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2781 stream_putc(s
, name_len
);
2782 stream_put(s
, hostname
, name_len
);
2786 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2787 uint8_t tlv_type
, uint8_t tlv_len
,
2788 struct stream
*s
, struct sbuf
*log
,
2789 void *dest
, int indent
)
2791 struct isis_tlvs
*tlvs
= dest
;
2793 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2795 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2799 if (tlvs
->hostname
) {
2800 sbuf_push(log
, indent
,
2801 "WARNING: Hostname present multiple times.\n");
2802 stream_forward_getp(s
, tlv_len
);
2806 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2807 stream_get(tlvs
->hostname
, s
, tlv_len
);
2808 tlvs
->hostname
[tlv_len
] = '\0';
2811 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2812 if ((unsigned char)tlvs
->hostname
[i
] > 127
2813 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2815 tlvs
->hostname
[i
] = '?';
2821 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2827 /* Functions related to TLV 140 IPv6 TE Router ID */
2829 static struct in6_addr
*copy_tlv_te_router_id_ipv6(const struct in6_addr
*id
)
2834 struct in6_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2835 memcpy(rv
, id
, sizeof(*rv
));
2839 static void format_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2841 struct json_object
*json
, int indent
)
2846 char addrbuf
[INET6_ADDRSTRLEN
];
2847 inet_ntop(AF_INET6
, id
, addrbuf
, sizeof(addrbuf
));
2849 json_object_string_add(json
, "ipv6-te-router-id", addrbuf
);
2851 sbuf_push(buf
, indent
, "IPv6 TE Router ID: %s\n", addrbuf
);
2854 static void free_tlv_te_router_id_ipv6(struct in6_addr
*id
)
2856 XFREE(MTYPE_ISIS_TLV
, id
);
2859 static int pack_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
2865 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
2868 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID_IPV6
);
2869 stream_putc(s
, IPV6_MAX_BYTELEN
);
2870 stream_put(s
, id
, IPV6_MAX_BYTELEN
);
2874 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context
,
2875 uint8_t tlv_type
, uint8_t tlv_len
,
2876 struct stream
*s
, struct sbuf
*log
,
2877 void *dest
, int indent
)
2879 struct isis_tlvs
*tlvs
= dest
;
2881 sbuf_push(log
, indent
, "Unpacking IPv6 TE Router ID TLV...\n");
2882 if (tlv_len
!= IPV6_MAX_BYTELEN
) {
2883 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2887 if (tlvs
->te_router_id_ipv6
) {
2890 "WARNING: IPv6 TE Router ID present multiple times.\n");
2891 stream_forward_getp(s
, tlv_len
);
2895 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, IPV6_MAX_BYTELEN
);
2896 stream_get(tlvs
->te_router_id_ipv6
, s
, IPV6_MAX_BYTELEN
);
2897 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, log
, NULL
, indent
+ 2);
2902 /* Functions related to TLV 150 Spine-Leaf-Extension */
2904 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2905 const struct isis_spine_leaf
*spine_leaf
)
2910 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2911 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2916 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2917 struct sbuf
*buf
, struct json_object
*json
,
2926 struct json_object
*spine_json
;
2927 spine_json
= json_object_new_object();
2928 json_object_object_add(json
, "spine-leaf-extension",
2930 if (spine_leaf
->has_tier
) {
2931 snprintfrr(aux_buf
, sizeof(aux_buf
), "%hhu",
2933 json_object_string_add(
2935 (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
)
2939 json_object_string_add(spine_json
, "flag-leaf",
2940 spine_leaf
->is_leaf
? "yes" : "");
2941 json_object_string_add(spine_json
, "flag-spine",
2942 spine_leaf
->is_spine
? "yes" : "");
2943 json_object_string_add(spine_json
, "flag-backup",
2944 spine_leaf
->is_backup
? "yes" : "");
2946 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2947 if (spine_leaf
->has_tier
) {
2948 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2949 sbuf_push(buf
, indent
, " Tier: undefined\n");
2951 sbuf_push(buf
, indent
, " Tier: %hhu\n",
2956 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2957 spine_leaf
->is_leaf
? " LEAF" : "",
2958 spine_leaf
->is_spine
? " SPINE" : "",
2959 spine_leaf
->is_backup
? " BACKUP" : "");
2963 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2965 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2968 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2969 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2970 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2971 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2973 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2979 uint8_t tlv_len
= 2;
2981 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2984 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2985 stream_putc(s
, tlv_len
);
2987 uint16_t spine_leaf_flags
= 0;
2989 if (spine_leaf
->has_tier
) {
2990 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2991 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2994 if (spine_leaf
->is_leaf
)
2995 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2997 if (spine_leaf
->is_spine
)
2998 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
3000 if (spine_leaf
->is_backup
)
3001 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
3003 stream_putw(s
, spine_leaf_flags
);
3008 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
3009 uint8_t tlv_type
, uint8_t tlv_len
,
3010 struct stream
*s
, struct sbuf
*log
,
3011 void *dest
, int indent
)
3013 struct isis_tlvs
*tlvs
= dest
;
3015 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
3017 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3018 stream_forward_getp(s
, tlv_len
);
3022 if (tlvs
->spine_leaf
) {
3023 sbuf_push(log
, indent
,
3024 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3025 stream_forward_getp(s
, tlv_len
);
3029 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3031 uint16_t spine_leaf_flags
= stream_getw(s
);
3033 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
3034 tlvs
->spine_leaf
->has_tier
= true;
3035 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
3038 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
3039 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
3040 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
3042 stream_forward_getp(s
, tlv_len
- 2);
3046 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3048 const char *isis_threeway_state_name(enum isis_threeway_state state
)
3051 case ISIS_THREEWAY_DOWN
:
3053 case ISIS_THREEWAY_INITIALIZING
:
3054 return "Initializing";
3055 case ISIS_THREEWAY_UP
:
3062 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
3063 const struct isis_threeway_adj
*threeway_adj
)
3068 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3069 memcpy(rv
, threeway_adj
, sizeof(*rv
));
3075 format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3076 struct sbuf
*buf
, struct json_object
*json
, int indent
)
3082 struct json_object
*three_json
;
3083 three_json
= json_object_new_object();
3084 json_object_object_add(json
, "p2p-three-way-adj", three_json
);
3085 json_object_string_add(
3086 three_json
, "state-name",
3087 isis_threeway_state_name(threeway_adj
->state
));
3088 json_object_int_add(three_json
, "state", threeway_adj
->state
);
3089 json_object_int_add(three_json
, "ext-local-circuit-id",
3090 threeway_adj
->local_circuit_id
);
3091 if (!threeway_adj
->neighbor_set
)
3093 json_object_string_add(
3094 three_json
, "neigh-system-id",
3095 isis_format_id(threeway_adj
->neighbor_id
, 6));
3096 json_object_int_add(three_json
, "neigh-ext-circuit-id",
3097 threeway_adj
->neighbor_circuit_id
);
3099 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
3100 sbuf_push(buf
, indent
, " State: %s (%d)\n",
3101 isis_threeway_state_name(threeway_adj
->state
),
3102 threeway_adj
->state
);
3103 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
3104 threeway_adj
->local_circuit_id
);
3105 if (!threeway_adj
->neighbor_set
)
3108 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
3109 isis_format_id(threeway_adj
->neighbor_id
, 6));
3110 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
3111 threeway_adj
->neighbor_circuit_id
);
3115 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
3117 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
3120 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3126 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
3128 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3131 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
3132 stream_putc(s
, tlv_len
);
3133 stream_putc(s
, threeway_adj
->state
);
3134 stream_putl(s
, threeway_adj
->local_circuit_id
);
3136 if (threeway_adj
->neighbor_set
) {
3137 stream_put(s
, threeway_adj
->neighbor_id
, 6);
3138 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
3144 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
3145 uint8_t tlv_type
, uint8_t tlv_len
,
3146 struct stream
*s
, struct sbuf
*log
,
3147 void *dest
, int indent
)
3149 struct isis_tlvs
*tlvs
= dest
;
3151 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
3152 if (tlv_len
!= 5 && tlv_len
!= 15) {
3153 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3154 stream_forward_getp(s
, tlv_len
);
3158 if (tlvs
->threeway_adj
) {
3159 sbuf_push(log
, indent
,
3160 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3161 stream_forward_getp(s
, tlv_len
);
3165 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3167 tlvs
->threeway_adj
->state
= stream_getc(s
);
3168 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
3170 if (tlv_len
== 15) {
3171 tlvs
->threeway_adj
->neighbor_set
= true;
3172 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
3173 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
3179 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3180 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
3182 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3183 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3185 rv
->metric
= r
->metric
;
3187 rv
->external
= r
->external
;
3188 rv
->prefix
= r
->prefix
;
3189 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3191 return (struct isis_item
*)rv
;
3194 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
3195 struct sbuf
*buf
, struct json_object
*json
,
3198 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3199 char prefixbuf
[PREFIX2STR_BUFFER
];
3202 struct json_object
*reach_json
;
3203 reach_json
= json_object_new_object();
3204 json_object_object_add(json
, "ipv6-reach", reach_json
);
3205 json_object_string_add(reach_json
, "mt-id",
3206 (mtid
== ISIS_MT_IPV4_UNICAST
) ? ""
3208 json_object_string_add(
3209 reach_json
, "prefix",
3210 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3211 json_object_int_add(reach_json
, "metric", r
->metric
);
3212 json_object_string_add(reach_json
, "down",
3213 r
->down
? "yes" : "");
3214 json_object_string_add(reach_json
, "external",
3215 r
->external
? "yes" : "");
3216 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3217 json_object_string_add(reach_json
, "mt-name",
3218 isis_mtid2str(mtid
));
3220 struct json_object
*subtlvs_json
;
3221 subtlvs_json
= json_object_new_object();
3222 json_object_object_add(json
, "subtlvs", subtlvs_json
);
3223 format_subtlvs(r
->subtlvs
, NULL
, subtlvs_json
, 0);
3226 sbuf_push(buf
, indent
,
3227 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3228 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
3229 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3230 r
->metric
, r
->down
? " Down" : "",
3231 r
->external
? " External" : "");
3232 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3233 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3234 sbuf_push(buf
, 0, "\n");
3237 sbuf_push(buf
, indent
, " Subtlvs:\n");
3238 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3243 static void free_item_ipv6_reach(struct isis_item
*i
)
3245 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
3247 isis_free_subtlvs(item
->subtlvs
);
3248 XFREE(MTYPE_ISIS_TLV
, item
);
3251 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
3254 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3257 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3258 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3261 stream_putl(s
, r
->metric
);
3263 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
3264 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
3265 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
3267 stream_putc(s
, control
);
3268 stream_putc(s
, r
->prefix
.prefixlen
);
3270 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
3273 return pack_subtlvs(r
->subtlvs
, s
);
3278 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3279 struct sbuf
*log
, void *dest
, int indent
)
3281 struct isis_tlvs
*tlvs
= dest
;
3282 struct isis_ipv6_reach
*rv
= NULL
;
3284 uint8_t control
, subtlv_len
;
3285 struct isis_item_list
*items
;
3287 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3288 items
= &tlvs
->ipv6_reach
;
3290 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3293 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
3294 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
3296 if (len
< consume
) {
3297 sbuf_push(log
, indent
,
3298 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3303 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3305 rv
->metric
= stream_getl(s
);
3306 control
= stream_getc(s
);
3307 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
3308 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
3310 rv
->prefix
.family
= AF_INET6
;
3311 rv
->prefix
.prefixlen
= stream_getc(s
);
3312 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
3313 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
3314 rv
->prefix
.prefixlen
);
3318 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3319 if (len
< consume
) {
3320 sbuf_push(log
, indent
,
3321 "Expected %u bytes of prefix, but only %u bytes available.\n",
3322 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
3325 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3326 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
3328 apply_mask_ipv6(&rv
->prefix
);
3329 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
3330 sbuf_push(log
, indent
+ 2,
3331 "WARNING: Prefix had hostbits set.\n");
3332 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3334 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
3336 if (len
< consume
) {
3337 sbuf_push(log
, indent
,
3338 "Expected 1 byte of subtlv len, but no more data persent.\n");
3341 subtlv_len
= stream_getc(s
);
3344 sbuf_push(log
, indent
+ 2,
3345 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3347 consume
+= subtlv_len
;
3348 if (len
< consume
) {
3349 sbuf_push(log
, indent
,
3350 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3352 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3356 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3357 bool unpacked_known_tlvs
= false;
3359 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
3360 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3363 if (!unpacked_known_tlvs
) {
3364 isis_free_subtlvs(rv
->subtlvs
);
3369 append_item(items
, (struct isis_item
*)rv
);
3373 free_item_ipv6_reach((struct isis_item
*)rv
);
3377 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3378 static struct isis_router_cap
*copy_tlv_router_cap(
3379 const struct isis_router_cap
*router_cap
)
3381 struct isis_router_cap
*rv
;
3386 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3388 memcpy(rv
, router_cap
, sizeof(*rv
));
3393 static void format_tlv_router_cap_json(const struct isis_router_cap
*router_cap
,
3394 struct json_object
*json
)
3396 char addrbuf
[INET_ADDRSTRLEN
];
3401 /* Router ID and Flags */
3402 struct json_object
*cap_json
;
3403 cap_json
= json_object_new_object();
3404 json_object_object_add(json
, "router-capability", cap_json
);
3405 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3406 json_object_string_add(cap_json
, "id", addrbuf
);
3407 json_object_string_add(
3409 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? "1" : "0");
3410 json_object_string_add(
3412 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? "1" : "0");
3414 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3415 if (router_cap
->srgb
.range_size
!= 0) {
3416 struct json_object
*gb_json
;
3417 gb_json
= json_object_new_object();
3418 json_object_object_add(json
, "segment-routing-gb", gb_json
);
3419 json_object_string_add(gb_json
, "ipv4",
3420 IS_SR_IPV4(&router_cap
->srgb
) ? "1"
3422 json_object_string_add(gb_json
, "ipv6",
3423 IS_SR_IPV6(&router_cap
->srgb
) ? "1"
3425 json_object_int_add(gb_json
, "global-block-base",
3426 router_cap
->srgb
.lower_bound
);
3427 json_object_int_add(gb_json
, "global-block-range",
3428 router_cap
->srgb
.range_size
);
3431 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3432 if (router_cap
->srlb
.range_size
!= 0) {
3433 struct json_object
*lb_json
;
3434 lb_json
= json_object_new_object();
3435 json_object_object_add(json
, "segment-routing-lb", lb_json
);
3436 json_object_int_add(lb_json
, "global-block-base",
3437 router_cap
->srlb
.lower_bound
);
3438 json_object_int_add(lb_json
, "global-block-range",
3439 router_cap
->srlb
.range_size
);
3442 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3443 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3445 struct json_object
*alg_json
;
3446 alg_json
= json_object_new_object();
3447 json_object_object_add(json
, "segment-routing-algorithm",
3449 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3450 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
) {
3451 snprintfrr(buf
, sizeof(buf
), "%d", i
);
3452 json_object_string_add(alg_json
, buf
,
3453 router_cap
->algo
[i
] == 0
3459 /* Segment Routing Node MSD as per RFC8491 section #2 */
3460 if (router_cap
->msd
!= 0)
3461 json_object_int_add(json
, "msd", router_cap
->msd
);
3464 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3465 struct sbuf
*buf
, int indent
)
3467 char addrbuf
[INET_ADDRSTRLEN
];
3472 /* Router ID and Flags */
3473 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3474 sbuf_push(buf
, indent
, "Router Capability:");
3475 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
3476 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
3477 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
3479 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3480 if (router_cap
->srgb
.range_size
!= 0)
3483 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
3484 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
3485 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
3486 router_cap
->srgb
.lower_bound
,
3487 router_cap
->srgb
.range_size
);
3489 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3490 if (router_cap
->srlb
.range_size
!= 0)
3491 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
3492 router_cap
->srlb
.lower_bound
,
3493 router_cap
->srlb
.range_size
);
3495 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
3496 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
3497 sbuf_push(buf
, indent
, " SR Algorithm:\n");
3498 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3499 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
3500 sbuf_push(buf
, indent
, " %u: %s\n", i
,
3501 router_cap
->algo
[i
] == 0
3506 /* Segment Routing Node MSD as per RFC8491 section #2 */
3507 if (router_cap
->msd
!= 0)
3508 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
3512 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
3514 XFREE(MTYPE_ISIS_TLV
, router_cap
);
3517 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
3520 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
3527 /* Compute Maximum TLV size */
3528 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
3529 + ISIS_SUBTLV_HDR_SIZE
3530 + ISIS_SUBTLV_ALGORITHM_SIZE
3531 + ISIS_SUBTLV_NODE_MSD_SIZE
;
3533 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
3536 /* Add Router Capability TLV 242 with Router ID and Flags */
3537 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
3538 /* Real length will be adjusted later */
3539 len_pos
= stream_get_endp(s
);
3540 stream_putc(s
, tlv_len
);
3541 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
3542 stream_putc(s
, router_cap
->flags
);
3544 /* Add SRGB if set as per RFC8667 section #3.1 */
3545 if ((router_cap
->srgb
.range_size
!= 0)
3546 && (router_cap
->srgb
.lower_bound
!= 0)) {
3547 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
3548 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3549 stream_putc(s
, router_cap
->srgb
.flags
);
3550 stream_put3(s
, router_cap
->srgb
.range_size
);
3551 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3552 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3553 stream_put3(s
, router_cap
->srgb
.lower_bound
);
3555 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
3556 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
3557 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
3560 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
3561 stream_putc(s
, nb_algo
);
3562 for (int i
= 0; i
< nb_algo
; i
++)
3563 stream_putc(s
, router_cap
->algo
[i
]);
3566 /* Local Block if defined as per RFC8667 section #3.3 */
3567 if ((router_cap
->srlb
.range_size
!= 0)
3568 && (router_cap
->srlb
.lower_bound
!= 0)) {
3569 stream_putc(s
, ISIS_SUBTLV_SRLB
);
3570 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
3571 /* No Flags are defined for SRLB */
3573 stream_put3(s
, router_cap
->srlb
.range_size
);
3574 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
3575 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
3576 stream_put3(s
, router_cap
->srlb
.lower_bound
);
3579 /* And finish with MSD if set as per RFC8491 section #2 */
3580 if (router_cap
->msd
!= 0) {
3581 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
3582 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
3583 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
3584 stream_putc(s
, router_cap
->msd
);
3588 /* Adjust TLV length which depends on subTLVs presence */
3589 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
3590 stream_putc_at(s
, len_pos
, tlv_len
);
3595 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
3596 uint8_t tlv_type
, uint8_t tlv_len
,
3597 struct stream
*s
, struct sbuf
*log
, void *dest
,
3600 struct isis_tlvs
*tlvs
= dest
;
3601 struct isis_router_cap
*rcap
;
3607 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
3608 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
3609 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3610 stream_forward_getp(s
, tlv_len
);
3614 if (tlvs
->router_cap
) {
3615 sbuf_push(log
, indent
,
3616 "WARNING: Router Capability TLV present multiple times.\n");
3617 stream_forward_getp(s
, tlv_len
);
3621 /* Allocate router cap structure and initialize SR Algorithms */
3622 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
3623 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
3624 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
3626 /* Get Router ID and Flags */
3627 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
3628 rcap
->flags
= stream_getc(s
);
3630 /* Parse remaining part of the TLV if present */
3631 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
3632 while (subtlv_len
> 2) {
3635 type
= stream_getc(s
);
3636 length
= stream_getc(s
);
3638 if (length
> STREAM_READABLE(s
) || length
> subtlv_len
- 2) {
3641 "WARNING: Router Capability subTLV length too large compared to expected size\n");
3642 stream_forward_getp(s
, STREAM_READABLE(s
));
3643 XFREE(MTYPE_ISIS_TLV
, rcap
);
3648 case ISIS_SUBTLV_SID_LABEL_RANGE
:
3649 /* Check that SRGB is correctly formated */
3650 if (length
< SUBTLV_RANGE_LABEL_SIZE
3651 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3652 stream_forward_getp(s
, length
);
3655 /* Only one SRGB is supported. Skip subsequent one */
3656 if (rcap
->srgb
.range_size
!= 0) {
3657 stream_forward_getp(s
, length
);
3660 rcap
->srgb
.flags
= stream_getc(s
);
3661 rcap
->srgb
.range_size
= stream_get3(s
);
3662 /* Skip Type and get Length of SID Label */
3664 size
= stream_getc(s
);
3666 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3667 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3668 stream_forward_getp(s
, length
- 6);
3672 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3673 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3674 stream_forward_getp(s
, length
- 6);
3678 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3679 rcap
->srgb
.lower_bound
= stream_get3(s
);
3680 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3681 rcap
->srgb
.lower_bound
= stream_getl(s
);
3683 stream_forward_getp(s
, length
- 6);
3687 /* SRGB sanity checks. */
3688 if (rcap
->srgb
.range_size
== 0
3689 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3690 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
3691 > MPLS_LABEL_UNRESERVED_MAX
)) {
3692 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
3693 rcap
->srgb
.lower_bound
= 0;
3694 rcap
->srgb
.range_size
= 0;
3696 /* Only one range is supported. Skip subsequent one */
3697 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3699 stream_forward_getp(s
, size
);
3702 case ISIS_SUBTLV_ALGORITHM
:
3705 /* Only 2 algorithms are supported: SPF & Strict SPF */
3706 stream_get(&rcap
->algo
, s
,
3707 length
> SR_ALGORITHM_COUNT
3708 ? SR_ALGORITHM_COUNT
3710 if (length
> SR_ALGORITHM_COUNT
)
3711 stream_forward_getp(
3712 s
, length
- SR_ALGORITHM_COUNT
);
3714 case ISIS_SUBTLV_SRLB
:
3715 /* Check that SRLB is correctly formated */
3716 if (length
< SUBTLV_RANGE_LABEL_SIZE
3717 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
3718 stream_forward_getp(s
, length
);
3721 /* RFC 8667 section #3.3: Only one SRLB is authorized */
3722 if (rcap
->srlb
.range_size
!= 0) {
3723 stream_forward_getp(s
, length
);
3726 /* Ignore Flags which are not defined */
3728 rcap
->srlb
.range_size
= stream_get3(s
);
3729 /* Skip Type and get Length of SID Label */
3731 size
= stream_getc(s
);
3733 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
3734 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
3735 stream_forward_getp(s
, length
- 6);
3739 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
3740 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
3741 stream_forward_getp(s
, length
- 6);
3745 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
3746 rcap
->srlb
.lower_bound
= stream_get3(s
);
3747 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
3748 rcap
->srlb
.lower_bound
= stream_getl(s
);
3750 stream_forward_getp(s
, length
- 6);
3754 /* SRLB sanity checks. */
3755 if (rcap
->srlb
.range_size
== 0
3756 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
3757 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
3758 > MPLS_LABEL_UNRESERVED_MAX
)) {
3759 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
3760 rcap
->srlb
.lower_bound
= 0;
3761 rcap
->srlb
.range_size
= 0;
3763 /* Only one range is supported. Skip subsequent one */
3764 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
3766 stream_forward_getp(s
, size
);
3769 case ISIS_SUBTLV_NODE_MSD
:
3770 /* Check that MSD is correctly formated */
3771 if (length
< MSD_TLV_SIZE
) {
3772 stream_forward_getp(s
, length
);
3775 msd_type
= stream_getc(s
);
3776 rcap
->msd
= stream_getc(s
);
3777 /* Only BMI-MSD type has been defined in RFC 8491 */
3778 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
3780 /* Only one MSD is standardized. Skip others */
3781 if (length
> MSD_TLV_SIZE
)
3782 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
3785 stream_forward_getp(s
, length
);
3788 subtlv_len
= subtlv_len
- length
- 2;
3790 tlvs
->router_cap
= rcap
;
3794 /* Functions related to TLV 10 Authentication */
3795 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
3797 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3798 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3800 rv
->type
= auth
->type
;
3801 rv
->length
= auth
->length
;
3802 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
3803 return (struct isis_item
*)rv
;
3806 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
3807 struct sbuf
*buf
, struct json_object
*json
,
3810 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3814 json_object_string_add(json
, "test-auth", "ok");
3816 sbuf_push(buf
, indent
, "Authentication:\n");
3817 switch (auth
->type
) {
3818 case ISIS_PASSWD_TYPE_CLEARTXT
:
3819 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
3821 json_object_string_add(json
, "auth-pass", obuf
);
3823 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
3825 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3826 for (unsigned int j
= 0; j
< 16; j
++) {
3827 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
, "%02hhx",
3831 json_object_string_add(json
, "auth-hmac-md5", obuf
);
3833 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
3837 json_object_int_add(json
, "auth-unknown", auth
->type
);
3839 sbuf_push(buf
, indent
, " Unknown (%hhu)\n",
3845 static void free_item_auth(struct isis_item
*i
)
3847 XFREE(MTYPE_ISIS_TLV
, i
);
3850 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
3853 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3855 if (STREAM_WRITEABLE(s
) < 1) {
3859 stream_putc(s
, auth
->type
);
3861 switch (auth
->type
) {
3862 case ISIS_PASSWD_TYPE_CLEARTXT
:
3863 if (STREAM_WRITEABLE(s
) < auth
->length
) {
3864 *min_len
= 1 + auth
->length
;
3867 stream_put(s
, auth
->passwd
, auth
->length
);
3869 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3870 if (STREAM_WRITEABLE(s
) < 16) {
3874 auth
->offset
= stream_get_endp(s
);
3875 stream_put(s
, NULL
, 16);
3884 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3885 struct sbuf
*log
, void *dest
, int indent
)
3887 struct isis_tlvs
*tlvs
= dest
;
3889 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
3893 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
3898 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3900 rv
->type
= stream_getc(s
);
3901 rv
->length
= len
- 1;
3903 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
3906 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
3908 XFREE(MTYPE_ISIS_TLV
, rv
);
3912 rv
->offset
= stream_get_getp(s
);
3913 stream_get(rv
->value
, s
, rv
->length
);
3914 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3915 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
3919 /* Functions related to TLV 13 Purge Originator */
3921 static struct isis_purge_originator
*copy_tlv_purge_originator(
3922 struct isis_purge_originator
*poi
)
3927 struct isis_purge_originator
*rv
;
3929 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3930 rv
->sender_set
= poi
->sender_set
;
3931 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3932 if (poi
->sender_set
)
3933 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
3937 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
3939 struct json_object
*json
, int indent
)
3945 struct json_object
*purge_json
;
3946 purge_json
= json_object_new_object();
3947 json_object_object_add(json
, "purge_originator", purge_json
);
3949 json_object_string_add(
3951 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3952 if (poi
->sender_set
) {
3953 json_object_string_add(
3954 purge_json
, "rec-from",
3955 isis_format_id(poi
->sender
,
3956 sizeof(poi
->sender
)));
3959 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
3961 buf
, indent
, " Generator: %s\n",
3962 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3963 if (poi
->sender_set
) {
3964 sbuf_push(buf
, indent
, " Received-From: %s\n",
3965 isis_format_id(poi
->sender
,
3966 sizeof(poi
->sender
)));
3971 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
3973 XFREE(MTYPE_ISIS_TLV
, poi
);
3976 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
3982 uint8_t data_len
= 1 + sizeof(poi
->generator
);
3984 if (poi
->sender_set
)
3985 data_len
+= sizeof(poi
->sender
);
3987 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
3990 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
3991 stream_putc(s
, data_len
);
3992 stream_putc(s
, poi
->sender_set
? 2 : 1);
3993 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
3994 if (poi
->sender_set
)
3995 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
3999 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
4000 uint8_t tlv_type
, uint8_t tlv_len
,
4001 struct stream
*s
, struct sbuf
*log
,
4002 void *dest
, int indent
)
4004 struct isis_tlvs
*tlvs
= dest
;
4005 struct isis_purge_originator poi
= {};
4007 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
4009 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
4013 uint8_t number_of_ids
= stream_getc(s
);
4015 if (number_of_ids
== 1) {
4016 poi
.sender_set
= false;
4017 } else if (number_of_ids
== 2) {
4018 poi
.sender_set
= true;
4020 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
4024 if (tlv_len
!= 1 + 6 * number_of_ids
) {
4025 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
4029 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
4031 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
4033 if (tlvs
->purge_originator
) {
4034 sbuf_push(log
, indent
,
4035 "WARNING: Purge originator present multiple times, ignoring.\n");
4039 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
4044 /* Functions relating to item TLVs */
4046 static void init_item_list(struct isis_item_list
*items
)
4049 items
->tail
= &items
->head
;
4053 static struct isis_item
*copy_item(enum isis_tlv_context context
,
4054 enum isis_tlv_type type
,
4055 struct isis_item
*item
)
4057 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4059 if (ops
&& ops
->copy_item
)
4060 return ops
->copy_item(item
);
4062 assert(!"Unknown item tlv type!");
4066 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4067 struct isis_item_list
*src
, struct isis_item_list
*dest
)
4069 struct isis_item
*item
;
4071 init_item_list(dest
);
4073 for (item
= src
->head
; item
; item
= item
->next
) {
4074 append_item(dest
, copy_item(context
, type
, item
));
4078 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
4079 enum isis_tlv_type type
, struct isis_item
*i
,
4080 struct sbuf
*buf
, struct json_object
*json
, int indent
)
4082 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4084 if (ops
&& ops
->format_item
) {
4085 ops
->format_item(mtid
, i
, buf
, json
, indent
);
4089 assert(!"Unknown item tlv type!");
4092 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
4093 enum isis_tlv_type type
, struct isis_item_list
*items
,
4094 struct sbuf
*buf
, struct json_object
*json
,
4097 struct isis_item
*i
;
4099 for (i
= items
->head
; i
; i
= i
->next
)
4100 format_item(mtid
, context
, type
, i
, buf
, json
, indent
);
4103 static void free_item(enum isis_tlv_context tlv_context
,
4104 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
4106 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
4108 if (ops
&& ops
->free_item
) {
4109 ops
->free_item(item
);
4113 assert(!"Unknown item tlv type!");
4116 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4117 struct isis_item_list
*items
)
4119 struct isis_item
*item
, *next_item
;
4121 for (item
= items
->head
; item
; item
= next_item
) {
4122 next_item
= item
->next
;
4123 free_item(context
, type
, item
);
4127 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
4128 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
4129 struct isis_tlvs
**fragment_tlvs
,
4130 const struct pack_order_entry
*pe
, uint16_t mtid
)
4132 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4134 if (ops
&& ops
->pack_item
) {
4135 return ops
->pack_item(i
, s
, min_len
);
4138 assert(!"Unknown item tlv type!");
4142 static void add_item_to_fragment(struct isis_item
*i
,
4143 const struct pack_order_entry
*pe
,
4144 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
4146 struct isis_item_list
*l
;
4148 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4149 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4151 struct isis_mt_item_list
*m
;
4152 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4153 l
= isis_get_mt_items(m
, mtid
);
4156 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
4159 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
4160 enum isis_tlv_type type
, struct isis_item_list
*items
,
4161 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
4162 const struct pack_order_entry
*pe
,
4163 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4164 struct list
*new_fragment_arg
)
4166 size_t len_pos
, last_len
, len
;
4167 struct isis_item
*item
= NULL
;
4175 if (STREAM_WRITEABLE(s
) < 2)
4178 stream_putc(s
, type
);
4179 len_pos
= stream_get_endp(s
);
4180 stream_putc(s
, 0); /* Put 0 as length for now */
4182 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
4183 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
4184 if (STREAM_WRITEABLE(s
) < 2)
4186 stream_putw(s
, mtid
);
4189 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
4190 if (STREAM_WRITEABLE(s
) < 1)
4192 stream_putc(s
, 0); /* Virtual flag is set to 0 */
4196 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
4197 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
4202 len
= stream_get_endp(s
) - len_pos
- 1;
4204 /* Multiple auths don't go into one TLV, so always break */
4205 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
4210 /* Multiple prefix-sids don't go into one TLV, so always break */
4211 if (type
== ISIS_SUBTLV_PREFIX_SID
4212 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
4213 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
4219 if (!last_len
) /* strange, not a single item fit */
4221 /* drop last tlv, otherwise, its too long */
4222 stream_set_endp(s
, len_pos
+ 1 + last_len
);
4228 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
4233 stream_putc_at(s
, len_pos
, len
);
4242 if (STREAM_WRITEABLE(s
) < min_len
)
4244 *fragment_tlvs
= new_fragment(new_fragment_arg
);
4247 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
4249 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
4252 dest
->tail
= &(*dest
->tail
)->next
;
4256 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
4258 struct isis_item
*item
, *prev
= NULL
, *next
;
4261 if ((dest
== NULL
) || (del
== NULL
))
4265 * TODO: delete is tricky because "dest" is a singly linked list.
4266 * We need to switch a doubly linked list.
4268 for (item
= dest
->head
; item
; item
= next
) {
4269 if (item
->next
== del
) {
4276 prev
->next
= del
->next
;
4277 if (dest
->head
== del
)
4278 dest
->head
= del
->next
;
4279 if ((struct isis_item
*)dest
->tail
== del
) {
4282 dest
->tail
= &(*dest
->tail
)->next
;
4284 dest
->tail
= &dest
->head
;
4289 static struct isis_item
*last_item(struct isis_item_list
*list
)
4291 return container_of(list
->tail
, struct isis_item
, next
);
4294 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
4295 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
4296 struct sbuf
*log
, void *dest
, int indent
)
4298 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
4300 if (ops
&& ops
->unpack_item
)
4301 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
4303 assert(!"Unknown item tlv type!");
4304 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
4308 static int unpack_tlv_with_items(enum isis_tlv_context context
,
4309 uint8_t tlv_type
, uint8_t tlv_len
,
4310 struct stream
*s
, struct sbuf
*log
, void *dest
,
4318 tlv_start
= stream_get_getp(s
);
4321 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
4323 sbuf_push(log
, indent
,
4324 "TLV is too short to contain MTID\n");
4327 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
4329 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
4330 isis_mtid2str_fake(mtid
));
4332 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
4333 mtid
= ISIS_MT_IPV4_UNICAST
;
4336 if (context
== ISIS_CONTEXT_LSP
4337 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
4338 if (tlv_len
- tlv_pos
< 1) {
4339 sbuf_push(log
, indent
,
4340 "TLV is too short for old style reach\n");
4343 stream_forward_getp(s
, 1);
4347 if (context
== ISIS_CONTEXT_LSP
4348 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
4349 struct isis_tlvs
*tlvs
= dest
;
4350 dest
= &tlvs
->oldstyle_ip_reach
;
4351 } else if (context
== ISIS_CONTEXT_LSP
4352 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
4353 struct isis_tlvs
*tlvs
= dest
;
4354 dest
= &tlvs
->oldstyle_ip_reach_ext
;
4357 if (context
== ISIS_CONTEXT_LSP
4358 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
4359 struct isis_tlvs
*tlvs
= dest
;
4360 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
4363 while (tlv_pos
< (size_t)tlv_len
) {
4364 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
4365 log
, dest
, indent
+ 2);
4369 tlv_pos
= stream_get_getp(s
) - tlv_start
;
4375 /* Functions to manipulate mt_item_lists */
4377 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
4378 const struct isis_item_list
*b
)
4380 if (a
->mtid
< b
->mtid
)
4382 if (a
->mtid
> b
->mtid
)
4387 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4388 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
4390 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
4393 struct isis_item_list
*rv
;
4395 rv
= isis_lookup_mt_items(m
, mtid
);
4397 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
4400 RB_INSERT(isis_mt_item_list
, m
, rv
);
4406 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
4409 struct isis_item_list key
= {.mtid
= mtid
};
4411 return RB_FIND(isis_mt_item_list
, m
, &key
);
4414 static void free_mt_items(enum isis_tlv_context context
,
4415 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
4417 struct isis_item_list
*n
, *nnext
;
4419 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
4420 free_items(context
, type
, n
);
4421 RB_REMOVE(isis_mt_item_list
, m
, n
);
4422 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
4426 static void format_mt_items(enum isis_tlv_context context
,
4427 enum isis_tlv_type type
,
4428 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
4429 struct json_object
*json
, int indent
)
4431 struct isis_item_list
*n
;
4433 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4434 format_items_(n
->mtid
, context
, type
, n
, buf
, json
, indent
);
4438 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4439 struct isis_mt_item_list
*m
, struct stream
*s
,
4440 struct isis_tlvs
**fragment_tlvs
,
4441 const struct pack_order_entry
*pe
,
4442 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4443 struct list
*new_fragment_arg
)
4445 struct isis_item_list
*n
;
4447 RB_FOREACH (n
, isis_mt_item_list
, m
) {
4450 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
4451 pe
, new_fragment
, new_fragment_arg
);
4459 static void copy_mt_items(enum isis_tlv_context context
,
4460 enum isis_tlv_type type
,
4461 struct isis_mt_item_list
*src
,
4462 struct isis_mt_item_list
*dest
)
4464 struct isis_item_list
*n
;
4466 RB_INIT(isis_mt_item_list
, dest
);
4468 RB_FOREACH (n
, isis_mt_item_list
, src
) {
4469 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
4473 /* Functions related to tlvs in general */
4475 struct isis_tlvs
*isis_alloc_tlvs(void)
4477 struct isis_tlvs
*result
;
4479 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
4481 init_item_list(&result
->isis_auth
);
4482 init_item_list(&result
->area_addresses
);
4483 init_item_list(&result
->mt_router_info
);
4484 init_item_list(&result
->oldstyle_reach
);
4485 init_item_list(&result
->lan_neighbor
);
4486 init_item_list(&result
->lsp_entries
);
4487 init_item_list(&result
->extended_reach
);
4488 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
4489 init_item_list(&result
->oldstyle_ip_reach
);
4490 init_item_list(&result
->oldstyle_ip_reach_ext
);
4491 init_item_list(&result
->ipv4_address
);
4492 init_item_list(&result
->ipv6_address
);
4493 init_item_list(&result
->global_ipv6_address
);
4494 init_item_list(&result
->extended_ip_reach
);
4495 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
4496 init_item_list(&result
->ipv6_reach
);
4497 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
4502 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
4504 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4506 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
4509 rv
->purge_originator
=
4510 copy_tlv_purge_originator(tlvs
->purge_originator
);
4512 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4513 &tlvs
->area_addresses
, &rv
->area_addresses
);
4515 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4516 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
4518 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
4520 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4521 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
4523 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4524 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
4526 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4529 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4530 &tlvs
->extended_reach
, &rv
->extended_reach
);
4532 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4535 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4536 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
4538 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
4539 &rv
->protocols_supported
);
4541 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4542 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
4544 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
4547 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
4550 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4551 &tlvs
->global_ipv6_address
, &rv
->global_ipv6_address
);
4553 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
4555 rv
->te_router_id_ipv6
=
4556 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4558 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4559 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
4561 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4562 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
4564 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
4566 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4569 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4570 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
4572 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4574 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
4576 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4581 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, struct json_object
*json
, int indent
)
4583 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, json
,
4586 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
4589 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, json
, indent
);
4591 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4592 &tlvs
->area_addresses
, buf
, json
, indent
);
4594 if (tlvs
->mt_router_info_empty
) {
4596 json_object_string_add(json
, "mt-router-info", "none");
4598 sbuf_push(buf
, indent
, "MT Router Info: None\n");
4600 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4601 &tlvs
->mt_router_info
, buf
, json
, indent
);
4604 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4605 &tlvs
->oldstyle_reach
, buf
, json
, indent
);
4607 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4608 &tlvs
->lan_neighbor
, buf
, json
, indent
);
4610 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
4613 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, json
, indent
);
4614 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, json
, indent
);
4615 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, buf
, json
,
4618 format_tlv_router_cap_json(tlvs
->router_cap
, json
);
4620 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
4622 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4623 &tlvs
->extended_reach
, buf
, json
, indent
);
4625 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
4628 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4629 &tlvs
->oldstyle_ip_reach
, buf
, json
, indent
);
4631 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4632 &tlvs
->oldstyle_ip_reach_ext
, buf
, json
, indent
);
4634 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4635 &tlvs
->ipv4_address
, buf
, json
, indent
);
4637 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4638 &tlvs
->ipv6_address
, buf
, json
, indent
);
4640 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4641 &tlvs
->global_ipv6_address
, buf
, json
, indent
);
4643 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4644 &tlvs
->extended_ip_reach
, buf
, json
, indent
);
4646 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4647 &tlvs
->mt_ip_reach
, buf
, json
, indent
);
4649 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
4652 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4653 &tlvs
->mt_ipv6_reach
, buf
, json
, indent
);
4655 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, json
, indent
);
4657 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, json
, indent
);
4660 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
, struct json_object
*json
)
4663 format_tlvs(tlvs
, NULL
, json
, 0);
4666 static struct sbuf buf
;
4668 if (!sbuf_buf(&buf
))
4669 sbuf_init(&buf
, NULL
, 0);
4672 format_tlvs(tlvs
, &buf
, NULL
, 0);
4673 return sbuf_buf(&buf
);
4677 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
4682 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4683 free_tlv_purge_originator(tlvs
->purge_originator
);
4684 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4685 &tlvs
->area_addresses
);
4686 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4687 &tlvs
->mt_router_info
);
4688 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
4689 &tlvs
->oldstyle_reach
);
4690 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
4691 &tlvs
->lan_neighbor
);
4692 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
4693 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
4694 &tlvs
->extended_reach
);
4695 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
4696 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
4697 &tlvs
->oldstyle_ip_reach
);
4698 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
4699 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
4700 &tlvs
->oldstyle_ip_reach_ext
);
4701 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
4702 &tlvs
->ipv4_address
);
4703 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
4704 &tlvs
->ipv6_address
);
4705 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
4706 &tlvs
->global_ipv6_address
);
4707 free_tlv_te_router_id(tlvs
->te_router_id
);
4708 free_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4709 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
4710 &tlvs
->extended_ip_reach
);
4711 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
4712 &tlvs
->mt_ip_reach
);
4713 free_tlv_dynamic_hostname(tlvs
->hostname
);
4714 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
4715 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
4716 &tlvs
->mt_ipv6_reach
);
4717 free_tlv_threeway_adj(tlvs
->threeway_adj
);
4718 free_tlv_router_cap(tlvs
->router_cap
);
4719 free_tlv_spine_leaf(tlvs
->spine_leaf
);
4721 XFREE(MTYPE_ISIS_TLV
, tlvs
);
4724 static void add_padding(struct stream
*s
)
4726 while (STREAM_WRITEABLE(s
)) {
4727 if (STREAM_WRITEABLE(s
) == 1)
4729 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
4731 if (padding_len
> 255) {
4732 if (padding_len
== 256)
4738 stream_putc(s
, ISIS_TLV_PADDING
);
4739 stream_putc(s
, padding_len
);
4740 stream_put(s
, NULL
, padding_len
);
4744 #define LSP_REM_LIFETIME_OFF 10
4745 #define LSP_CHECKSUM_OFF 24
4746 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
4747 uint16_t *rem_lifetime
)
4749 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
4750 sizeof(*rem_lifetime
));
4751 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
4752 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
4753 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
4756 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
4757 uint16_t rem_lifetime
)
4759 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
4760 sizeof(rem_lifetime
));
4761 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
4764 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
4768 uint16_t checksum
, rem_lifetime
;
4771 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
4773 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
4774 #ifdef CRYPTO_OPENSSL
4775 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
4776 auth
->plength
, STREAM_DATA(s
),
4777 stream_get_endp(s
), NULL
, NULL
);
4779 memcpy(digest
, result
, 16);
4780 #elif CRYPTO_INTERNAL
4781 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
4782 auth
->plength
, digest
);
4784 memcpy(auth
->value
, digest
, 16);
4785 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
4788 restore_auth_md5(s
, checksum
, rem_lifetime
);
4791 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
4793 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4795 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
4796 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
4797 update_auth_hmac_md5(auth
, s
, is_lsp
);
4801 static int handle_pack_entry(const struct pack_order_entry
*pe
,
4802 struct isis_tlvs
*tlvs
, struct stream
*stream
,
4803 struct isis_tlvs
**fragment_tlvs
,
4804 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4805 struct list
*new_fragment_arg
)
4809 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4810 struct isis_item_list
*l
;
4811 l
= (struct isis_item_list
*)(((char *)tlvs
)
4812 + pe
->what_to_pack
);
4813 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
4814 pe
, new_fragment
, new_fragment_arg
);
4816 struct isis_mt_item_list
*l
;
4817 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
4818 + pe
->what_to_pack
);
4819 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
4820 fragment_tlvs
, pe
, new_fragment
,
4827 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4828 struct isis_tlvs
*fragment_tlvs
,
4829 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
4830 struct list
*new_fragment_arg
)
4834 /* When fragmenting, don't add auth as it's already accounted for in the
4835 * size we are given. */
4836 if (!fragment_tlvs
) {
4837 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
4838 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
4844 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
4847 if (fragment_tlvs
) {
4848 fragment_tlvs
->purge_originator
=
4849 copy_tlv_purge_originator(tlvs
->purge_originator
);
4852 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
4855 if (fragment_tlvs
) {
4856 copy_tlv_protocols_supported(
4857 &tlvs
->protocols_supported
,
4858 &fragment_tlvs
->protocols_supported
);
4861 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4862 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
4865 if (fragment_tlvs
) {
4866 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
4867 &tlvs
->area_addresses
,
4868 &fragment_tlvs
->area_addresses
);
4872 if (tlvs
->mt_router_info_empty
) {
4873 if (STREAM_WRITEABLE(stream
) < 2)
4875 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
4876 stream_putc(stream
, 0);
4878 fragment_tlvs
->mt_router_info_empty
= true;
4880 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4881 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
4885 if (fragment_tlvs
) {
4886 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4887 &tlvs
->mt_router_info
,
4888 &fragment_tlvs
->mt_router_info
);
4892 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
4896 fragment_tlvs
->hostname
=
4897 copy_tlv_dynamic_hostname(tlvs
->hostname
);
4899 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
4902 if (fragment_tlvs
) {
4903 fragment_tlvs
->router_cap
=
4904 copy_tlv_router_cap(tlvs
->router_cap
);
4907 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
4910 if (fragment_tlvs
) {
4911 fragment_tlvs
->te_router_id
=
4912 copy_tlv_te_router_id(tlvs
->te_router_id
);
4915 rv
= pack_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, stream
);
4918 if (fragment_tlvs
) {
4919 fragment_tlvs
->te_router_id_ipv6
=
4920 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
4923 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
4926 if (fragment_tlvs
) {
4927 fragment_tlvs
->threeway_adj
=
4928 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4931 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
4934 if (fragment_tlvs
) {
4935 fragment_tlvs
->spine_leaf
=
4936 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4939 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
4941 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
4942 fragment_tlvs
? &fragment_tlvs
: NULL
,
4943 new_fragment
, new_fragment_arg
);
4952 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4953 size_t len_pointer
, bool pad
, bool is_lsp
)
4957 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
4962 add_padding(stream
);
4964 if (len_pointer
!= (size_t)-1) {
4965 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
4968 update_auth(tlvs
, stream
, is_lsp
);
4973 static struct isis_tlvs
*new_fragment(struct list
*l
)
4975 struct isis_tlvs
*rv
= isis_alloc_tlvs();
4977 listnode_add(l
, rv
);
4981 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
4983 struct stream
*dummy_stream
= stream_new(size
);
4984 struct list
*rv
= list_new();
4985 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
4987 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
4988 struct listnode
*node
;
4989 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
4990 isis_free_tlvs(fragment_tlvs
);
4994 stream_free(dummy_stream
);
4998 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
4999 uint8_t tlv_len
, struct stream
*s
,
5000 struct sbuf
*log
, int indent
)
5002 stream_forward_getp(s
, tlv_len
);
5003 sbuf_push(log
, indent
,
5004 "Skipping unknown TLV %hhu (%hhu bytes)\n",
5009 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
5010 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5011 int indent
, bool *unpacked_known_tlvs
)
5013 uint8_t tlv_type
, tlv_len
;
5014 const struct tlv_ops
*ops
;
5016 sbuf_push(log
, indent
, "Unpacking TLV...\n");
5018 if (avail_len
< 2) {
5021 "Available data %zu too short to contain a TLV header.\n",
5026 tlv_type
= stream_getc(stream
);
5027 tlv_len
= stream_getc(stream
);
5029 sbuf_push(log
, indent
+ 2,
5030 "Found TLV of type %hhu and len %hhu.\n",
5033 if (avail_len
< ((size_t)tlv_len
) + 2) {
5034 sbuf_push(log
, indent
+ 2,
5035 "Available data %zu too short for claimed TLV len %hhu.\n",
5036 avail_len
- 2, tlv_len
);
5040 ops
= tlv_table
[context
][tlv_type
];
5041 if (ops
&& ops
->unpack
) {
5042 if (unpacked_known_tlvs
)
5043 *unpacked_known_tlvs
= true;
5044 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
5048 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
5052 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
5053 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5054 int indent
, bool *unpacked_known_tlvs
)
5057 size_t tlv_start
, tlv_pos
;
5059 tlv_start
= stream_get_getp(stream
);
5062 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
5063 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
5065 while (tlv_pos
< avail_len
) {
5066 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
5067 indent
+ 2, unpacked_known_tlvs
);
5071 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
5077 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
5078 struct isis_tlvs
**dest
, const char **log
)
5080 static struct sbuf logbuf
;
5083 struct isis_tlvs
*result
;
5085 if (!sbuf_buf(&logbuf
))
5086 sbuf_init(&logbuf
, NULL
, 0);
5088 sbuf_reset(&logbuf
);
5089 if (avail_len
> STREAM_READABLE(stream
)) {
5090 sbuf_push(&logbuf
, indent
,
5091 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5092 avail_len
, STREAM_READABLE(stream
));
5096 result
= isis_alloc_tlvs();
5097 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
5100 *log
= sbuf_buf(&logbuf
);
5106 #define TLV_OPS(_name_, _desc_) \
5107 static const struct tlv_ops tlv_##_name_##_ops = { \
5108 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5111 #define ITEM_TLV_OPS(_name_, _desc_) \
5112 static const struct tlv_ops tlv_##_name_##_ops = { \
5114 .unpack = unpack_tlv_with_items, \
5116 .pack_item = pack_item_##_name_, \
5117 .free_item = free_item_##_name_, \
5118 .unpack_item = unpack_item_##_name_, \
5119 .format_item = format_item_##_name_, \
5120 .copy_item = copy_item_##_name_}
5122 #define SUBTLV_OPS(_name_, _desc_) \
5123 static const struct tlv_ops subtlv_##_name_##_ops = { \
5124 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5127 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5128 ITEM_TLV_OPS(_name_, _desc_)
5130 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
5131 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
5132 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
5133 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
5134 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
5135 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
5136 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
5137 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
5138 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
5139 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
5140 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
5141 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
5142 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
5143 TLV_OPS(te_router_id_ipv6
, "TLV 140 IPv6 TE Router ID");
5144 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
5145 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
5146 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
5147 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
5148 ITEM_TLV_OPS(global_ipv6_address
, "TLV 233 Global IPv6 Interface Address");
5149 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
5150 TLV_OPS(router_cap
, "TLV 242 Router Capability");
5152 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
5153 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
5155 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
5156 [ISIS_CONTEXT_LSP
] = {
5157 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
5158 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
5159 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
5160 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
5161 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
5162 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
5163 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
5164 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
5165 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
5166 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
5167 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
5168 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
5169 [ISIS_TLV_TE_ROUTER_ID_IPV6
] = &tlv_te_router_id_ipv6_ops
,
5170 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5171 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
5172 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
5173 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
5174 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
5175 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
5176 [ISIS_TLV_GLOBAL_IPV6_ADDRESS
] = &tlv_global_ipv6_address_ops
,
5177 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
5178 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5179 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
5180 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
5181 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
5183 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
5184 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
5185 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5187 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
5188 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
5189 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
5193 /* Accessor functions */
5195 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
5197 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
5198 init_item_list(&tlvs
->isis_auth
);
5200 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
5203 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
5205 auth
->type
= passwd
->type
;
5207 auth
->plength
= passwd
->len
;
5208 memcpy(auth
->passwd
, passwd
->passwd
,
5209 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
5211 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
5212 auth
->length
= passwd
->len
;
5213 memcpy(auth
->value
, passwd
->passwd
,
5214 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
5217 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
5220 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
5221 struct list
*addresses
)
5223 struct listnode
*node
;
5224 struct area_addr
*area_addr
;
5226 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
5227 struct isis_area_address
*a
=
5228 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5230 a
->len
= area_addr
->addr_len
;
5231 memcpy(a
->addr
, area_addr
->area_addr
, 20);
5232 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
5236 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
5238 struct listnode
*node
;
5241 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
5242 struct isis_lan_neighbor
*n
=
5243 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
5245 memcpy(n
->mac
, snpa
, 6);
5246 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
5250 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
5251 struct nlpids
*nlpids
)
5253 tlvs
->protocols_supported
.count
= nlpids
->count
;
5254 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
5255 if (nlpids
->count
) {
5256 tlvs
->protocols_supported
.protocols
=
5257 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
5258 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
5261 tlvs
->protocols_supported
.protocols
= NULL
;
5265 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5266 bool overload
, bool attached
)
5268 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
5270 i
->overload
= overload
;
5271 i
->attached
= attached
;
5273 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
5276 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
5278 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5280 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
5284 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
5285 struct list
*addresses
)
5287 struct listnode
*node
;
5288 struct prefix_ipv4
*ip_addr
;
5289 unsigned int addr_count
= 0;
5291 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5292 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
5294 if (addr_count
>= 63)
5299 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
5300 struct list
*addresses
)
5302 struct listnode
*node
;
5303 struct prefix_ipv6
*ip_addr
;
5304 unsigned int addr_count
= 0;
5306 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5307 if (addr_count
>= 15)
5310 struct isis_ipv6_address
*a
=
5311 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5313 a
->addr
= ip_addr
->prefix
;
5314 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
5319 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs
*tlvs
,
5320 struct list
*addresses
)
5322 struct listnode
*node
;
5323 struct prefix_ipv6
*ip_addr
;
5324 unsigned int addr_count
= 0;
5326 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
5327 if (addr_count
>= 15)
5330 struct isis_ipv6_address
*a
=
5331 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
5333 a
->addr
= ip_addr
->prefix
;
5334 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)a
);
5339 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
5340 struct stream
*stream
,
5341 struct isis_auth
*auth
, bool is_lsp
);
5343 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
5344 struct stream
*stream
,
5345 struct isis_auth
*auth
, bool is_lsp
)
5347 return (auth
->length
== passwd
->len
5348 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
5351 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
5352 struct stream
*stream
,
5353 struct isis_auth
*auth
, bool is_lsp
)
5357 uint16_t rem_lifetime
;
5360 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
5362 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
5363 #ifdef CRYPTO_OPENSSL
5364 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
5365 passwd
->len
, STREAM_DATA(stream
),
5366 stream_get_endp(stream
), NULL
, NULL
);
5368 memcpy(digest
, result
, 16);
5369 #elif CRYPTO_INTERNAL
5370 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
5371 passwd
->len
, digest
);
5373 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
5375 bool rv
= !memcmp(digest
, auth
->value
, 16);
5378 restore_auth_md5(stream
, checksum
, rem_lifetime
);
5383 static const auth_validator_func auth_validators
[] = {
5384 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
5385 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
5388 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
5389 struct stream
*stream
, bool is_lsp
)
5391 /* If no auth is set, always pass authentication */
5393 return ISIS_AUTH_OK
;
5395 /* If we don't known how to validate the auth, return invalid */
5396 if (passwd
->type
>= array_size(auth_validators
)
5397 || !auth_validators
[passwd
->type
])
5398 return ISIS_AUTH_NO_VALIDATOR
;
5400 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
5401 struct isis_auth
*auth
;
5402 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
5403 if (auth
->type
== passwd
->type
)
5407 /* If matching auth TLV could not be found, return invalid */
5409 return ISIS_AUTH_TYPE_FAILURE
;
5412 /* Perform validation and return result */
5413 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
5414 return ISIS_AUTH_OK
;
5416 return ISIS_AUTH_FAILURE
;
5419 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
5420 struct list
*addresses
)
5422 struct isis_area_address
*addr_head
;
5424 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
5425 for (struct isis_area_address
*addr
= addr_head
; addr
;
5426 addr
= addr
->next
) {
5427 struct listnode
*node
;
5428 struct area_addr
*a
;
5430 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
5431 if (a
->addr_len
== addr
->len
5432 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
5440 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
5441 struct isis_adjacency
*adj
,
5444 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
5445 uint32_t oc
= adj
->area_address_count
;
5448 adj
->area_address_count
= tlvs
->area_addresses
.count
;
5449 adj
->area_addresses
= XREALLOC(
5450 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
5451 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
5453 for (; oc
< adj
->area_address_count
; oc
++) {
5454 adj
->area_addresses
[oc
].addr_len
= 0;
5455 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
5456 sizeof(adj
->area_addresses
[oc
].area_addr
));
5460 struct isis_area_address
*addr
= NULL
;
5461 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
5463 addr
= (struct isis_area_address
*)
5464 tlvs
->area_addresses
.head
;
5468 if (adj
->area_addresses
[i
].addr_len
== addr
->len
5469 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
5475 adj
->area_addresses
[i
].addr_len
= addr
->len
;
5476 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
5480 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
5481 struct isis_adjacency
*adj
,
5484 bool ipv4_supported
= false, ipv6_supported
= false;
5486 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
5487 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
5488 ipv4_supported
= true;
5489 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
5490 ipv6_supported
= true;
5493 struct nlpids reduced
= {};
5495 if (ipv4_supported
&& ipv6_supported
) {
5497 reduced
.nlpids
[0] = NLPID_IP
;
5498 reduced
.nlpids
[1] = NLPID_IPV6
;
5499 } else if (ipv4_supported
) {
5501 reduced
.nlpids
[0] = NLPID_IP
;
5502 } else if (ipv6_supported
) {
5504 reduced
.nlpids
[0] = NLPID_IPV6
;
5509 if (adj
->nlpids
.count
== reduced
.count
5510 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
5514 adj
->nlpids
.count
= reduced
.count
;
5515 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
5518 DEFINE_HOOK(isis_adj_ip_enabled_hook
,
5519 (struct isis_adjacency
* adj
, int family
, bool global
),
5520 (adj
, family
, global
));
5521 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
5522 (struct isis_adjacency
* adj
, int family
, bool global
),
5523 (adj
, family
, global
));
5525 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
5526 struct isis_adjacency
*adj
,
5529 bool ipv4_enabled
= false;
5531 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
5532 ipv4_enabled
= true;
5533 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
5534 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
, false);
5536 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
5537 uint32_t oc
= adj
->ipv4_address_count
;
5540 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
5541 adj
->ipv4_addresses
= XREALLOC(
5542 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
5543 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
5545 for (; oc
< adj
->ipv4_address_count
; oc
++) {
5546 memset(&adj
->ipv4_addresses
[oc
], 0,
5547 sizeof(adj
->ipv4_addresses
[oc
]));
5551 struct isis_ipv4_address
*addr
= NULL
;
5552 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
5554 addr
= (struct isis_ipv4_address
*)
5555 tlvs
->ipv4_address
.head
;
5559 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
5560 sizeof(addr
->addr
)))
5564 adj
->ipv4_addresses
[i
] = addr
->addr
;
5568 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
, false);
5571 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5572 struct isis_adjacency
*adj
,
5575 bool ipv6_enabled
= false;
5577 if (adj
->ll_ipv6_count
== 0 && tlvs
->ipv6_address
.count
> 0)
5578 ipv6_enabled
= true;
5579 else if (adj
->ll_ipv6_count
> 0 && tlvs
->ipv6_address
.count
== 0)
5580 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, false);
5582 if (adj
->ll_ipv6_count
!= tlvs
->ipv6_address
.count
) {
5583 uint32_t oc
= adj
->ll_ipv6_count
;
5586 adj
->ll_ipv6_count
= tlvs
->ipv6_address
.count
;
5587 adj
->ll_ipv6_addrs
= XREALLOC(
5588 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
,
5589 adj
->ll_ipv6_count
* sizeof(*adj
->ll_ipv6_addrs
));
5591 for (; oc
< adj
->ll_ipv6_count
; oc
++) {
5592 memset(&adj
->ll_ipv6_addrs
[oc
], 0,
5593 sizeof(adj
->ll_ipv6_addrs
[oc
]));
5597 struct isis_ipv6_address
*addr
= NULL
;
5598 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
5600 addr
= (struct isis_ipv6_address
*)
5601 tlvs
->ipv6_address
.head
;
5605 if (!memcmp(&adj
->ll_ipv6_addrs
[i
], &addr
->addr
,
5606 sizeof(addr
->addr
)))
5610 adj
->ll_ipv6_addrs
[i
] = addr
->addr
;
5614 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, false);
5618 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
5619 struct isis_adjacency
*adj
,
5622 bool global_ipv6_enabled
= false;
5624 if (adj
->global_ipv6_count
== 0 && tlvs
->global_ipv6_address
.count
> 0)
5625 global_ipv6_enabled
= true;
5626 else if (adj
->global_ipv6_count
> 0
5627 && tlvs
->global_ipv6_address
.count
== 0)
5628 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, true);
5630 if (adj
->global_ipv6_count
!= tlvs
->global_ipv6_address
.count
) {
5631 uint32_t oc
= adj
->global_ipv6_count
;
5634 adj
->global_ipv6_count
= tlvs
->global_ipv6_address
.count
;
5635 adj
->global_ipv6_addrs
= XREALLOC(
5636 MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
,
5637 adj
->global_ipv6_count
5638 * sizeof(*adj
->global_ipv6_addrs
));
5640 for (; oc
< adj
->global_ipv6_count
; oc
++) {
5641 memset(&adj
->global_ipv6_addrs
[oc
], 0,
5642 sizeof(adj
->global_ipv6_addrs
[oc
]));
5646 struct isis_ipv6_address
*addr
= NULL
;
5647 for (unsigned int i
= 0; i
< tlvs
->global_ipv6_address
.count
; i
++) {
5649 addr
= (struct isis_ipv6_address
*)
5650 tlvs
->global_ipv6_address
.head
;
5654 if (!memcmp(&adj
->global_ipv6_addrs
[i
], &addr
->addr
,
5655 sizeof(addr
->addr
)))
5659 adj
->global_ipv6_addrs
[i
] = addr
->addr
;
5662 if (global_ipv6_enabled
)
5663 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, true);
5666 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
5671 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
5672 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
5673 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
5674 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5675 tlvs_global_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
5678 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
5680 struct isis_lan_neighbor
*ne_head
;
5682 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
5683 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
5684 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
5691 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
5693 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
5695 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
5696 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
5697 entry
->checksum
= lsp
->hdr
.checksum
;
5698 entry
->seqno
= lsp
->hdr
.seqno
;
5701 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
5704 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
5705 uint8_t *stop_id
, uint16_t num_lsps
,
5706 struct lspdb_head
*head
,
5707 struct isis_lsp
**last_lsp
)
5709 struct isis_lsp searchfor
;
5710 struct isis_lsp
*first
, *lsp
;
5712 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
5713 first
= lspdb_find_gteq(head
, &searchfor
);
5717 frr_each_from (lspdb
, head
, lsp
, first
) {
5718 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
5719 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
5722 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
5727 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
5728 const char *hostname
)
5730 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
5732 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
5735 /* Set Router Capability TLV parameters */
5736 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
5737 const struct isis_router_cap
*cap
)
5739 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
5743 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
5744 *tlvs
->router_cap
= *cap
;
5747 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
5748 const struct in_addr
*id
)
5750 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
5753 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5754 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
5757 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs
*tlvs
,
5758 const struct in6_addr
*id
)
5760 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id_ipv6
);
5763 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
5764 memcpy(tlvs
->te_router_id_ipv6
, id
, sizeof(*id
));
5767 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
5768 struct prefix_ipv4
*dest
, uint8_t metric
)
5770 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5773 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5774 apply_mask_ipv4(&r
->prefix
);
5775 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
5778 /* Add IS-IS SR Adjacency-SID subTLVs */
5779 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
5780 struct isis_adj_sid
*adj
)
5782 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5783 SET_SUBTLV(exts
, EXT_ADJ_SID
);
5786 /* Delete IS-IS SR Adjacency-SID subTLVs */
5787 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
5788 struct isis_adj_sid
*adj
)
5790 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
5791 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
5792 if (exts
->adj_sid
.count
== 0)
5793 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
5796 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
5797 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5798 struct isis_lan_adj_sid
*lan
)
5800 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5801 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5804 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
5805 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
5806 struct isis_lan_adj_sid
*lan
)
5808 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
5809 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
5810 if (exts
->lan_sid
.count
== 0)
5811 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
5814 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
5815 struct prefix_ipv4
*dest
, uint32_t metric
,
5816 bool external
, struct sr_prefix_cfg
*pcfg
)
5818 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5821 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5822 apply_mask_ipv4(&r
->prefix
);
5824 struct isis_prefix_sid
*psid
=
5825 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5827 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5828 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5829 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5831 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
5834 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5835 struct prefix_ipv6
*dest
, uint32_t metric
,
5836 bool external
, struct sr_prefix_cfg
*pcfg
)
5838 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5841 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
5842 apply_mask_ipv6(&r
->prefix
);
5844 struct isis_prefix_sid
*psid
=
5845 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
5847 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
5848 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
5849 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
5852 struct isis_item_list
*l
;
5853 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
5855 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
5856 append_item(l
, (struct isis_item
*)r
);
5859 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5860 struct prefix_ipv6
*dest
,
5861 struct prefix_ipv6
*src
,
5864 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
5865 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
5868 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
5869 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
5870 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
5871 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
5874 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
5877 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5880 memcpy(r
->id
, id
, sizeof(r
->id
));
5881 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
5884 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
5885 uint8_t *id
, uint32_t metric
,
5886 struct isis_ext_subtlvs
*exts
)
5888 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
5890 memcpy(r
->id
, id
, sizeof(r
->id
));
5893 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
5895 struct isis_item_list
*l
;
5896 if ((mtid
== ISIS_MT_IPV4_UNICAST
) || (mtid
== ISIS_MT_DISABLE
))
5897 l
= &tlvs
->extended_reach
;
5899 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
5900 append_item(l
, (struct isis_item
*)r
);
5903 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
5904 enum isis_threeway_state state
,
5905 uint32_t local_circuit_id
,
5906 const uint8_t *neighbor_id
,
5907 uint32_t neighbor_circuit_id
)
5909 assert(!tlvs
->threeway_adj
);
5911 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
5912 tlvs
->threeway_adj
->state
= state
;
5913 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
5916 tlvs
->threeway_adj
->neighbor_set
= true;
5917 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
5918 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
5922 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
5923 bool has_tier
, bool is_leaf
, bool is_spine
,
5926 assert(!tlvs
->spine_leaf
);
5928 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
5931 tlvs
->spine_leaf
->tier
= tier
;
5934 tlvs
->spine_leaf
->has_tier
= has_tier
;
5935 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
5936 tlvs
->spine_leaf
->is_spine
= is_spine
;
5937 tlvs
->spine_leaf
->is_backup
= is_backup
;
5940 struct isis_mt_router_info
*
5941 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
5943 if (!tlvs
|| tlvs
->mt_router_info_empty
)
5946 struct isis_mt_router_info
*rv
;
5947 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
5949 if (rv
->mtid
== mtid
)
5956 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
5957 const uint8_t *generator
,
5958 const uint8_t *sender
)
5960 assert(!tlvs
->purge_originator
);
5962 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
5963 sizeof(*tlvs
->purge_originator
));
5964 memcpy(tlvs
->purge_originator
->generator
, generator
,
5965 sizeof(tlvs
->purge_originator
->generator
));
5967 tlvs
->purge_originator
->sender_set
= true;
5968 memcpy(tlvs
->purge_originator
->sender
, sender
,
5969 sizeof(tlvs
->purge_originator
->sender
));