1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS TLV Serializer/Deserializer
5 * Copyright (C) 2015,2017 Christian Franke
7 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
11 #include <json-c/json_object.h>
13 #ifdef CRYPTO_INTERNAL
21 #include "isisd/isisd.h"
22 #include "isisd/isis_tlvs.h"
23 #include "isisd/isis_common.h"
24 #include "isisd/isis_mt.h"
25 #include "isisd/isis_misc.h"
26 #include "isisd/isis_adjacency.h"
27 #include "isisd/isis_circuit.h"
28 #include "isisd/isis_pdu.h"
29 #include "isisd/isis_lsp.h"
30 #include "isisd/isis_te.h"
31 #include "isisd/isis_sr.h"
32 #include "isisd/isis_flex_algo.h"
34 #define TLV_SIZE_MISMATCH(log, indent, target) \
35 sbuf_push(log, indent, \
36 "TLV size does not match expected size for " target "!\n")
38 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs");
39 DEFINE_MTYPE(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs");
40 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SUBSUBTLV
, "ISIS Sub-Sub-TLVs");
41 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists");
43 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
44 uint8_t tlv_len
, struct stream
*s
,
45 struct sbuf
*log
, void *dest
, int indent
);
46 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
,
48 typedef void (*free_item_func
)(struct isis_item
*i
);
49 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
50 struct sbuf
*log
, void *dest
, int indent
);
51 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
52 struct sbuf
*buf
, struct json_object
*json
,
54 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
58 unpack_tlv_func unpack
;
60 pack_item_func pack_item
;
61 free_item_func free_item
;
62 unpack_item_func unpack_item
;
63 format_item_func format_item
;
64 copy_item_func copy_item
;
72 struct pack_order_entry
{
73 enum isis_tlv_context context
;
74 enum isis_tlv_type type
;
75 enum how_to_pack how_to_pack
;
78 #define PACK_ENTRY(t, h, w) \
80 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
82 .what_to_pack = offsetof(struct isis_tlvs, w), \
85 static const struct pack_order_entry pack_order
[] = {
86 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
87 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
88 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
89 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
90 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
91 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
92 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
93 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
94 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
95 PACK_ENTRY(GLOBAL_IPV6_ADDRESS
, ISIS_ITEMS
, global_ipv6_address
),
96 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
97 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
98 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
99 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)
102 /* This is a forward definition. The table is actually initialized
103 * in at the bottom. */
104 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
106 /* End of _ops forward definition. */
109 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
110 static void init_item_list(struct isis_item_list
*items
);
112 /* For tests/isisd, TLV text requires ipv4-unicast instead of standard */
113 static const char *isis_mtid2str_fake(uint16_t mtid
)
115 if (mtid
== ISIS_MT_STANDARD
)
116 return "ipv4-unicast";
117 return isis_mtid2str(mtid
);
120 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
121 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
123 struct isis_ext_subtlvs
*ext
;
125 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
126 init_item_list(&ext
->adj_sid
);
127 init_item_list(&ext
->lan_sid
);
128 ext
->aslas
= list_new();
130 admin_group_init(&ext
->ext_admin_group
);
135 void isis_del_ext_subtlvs(struct isis_ext_subtlvs
*ext
)
137 struct isis_item
*item
, *next_item
;
138 struct listnode
*node
, *nnode
;
139 struct isis_asla_subtlvs
*asla
;
144 /* First, free Adj SID and LAN Adj SID list if needed */
145 for (item
= ext
->adj_sid
.head
; item
; item
= next_item
) {
146 next_item
= item
->next
;
147 XFREE(MTYPE_ISIS_SUBTLV
, item
);
149 for (item
= ext
->lan_sid
.head
; item
; item
= next_item
) {
150 next_item
= item
->next
;
151 XFREE(MTYPE_ISIS_SUBTLV
, item
);
154 for (ALL_LIST_ELEMENTS(ext
->aslas
, node
, nnode
, asla
))
155 isis_tlvs_del_asla_flex_algo(ext
, asla
);
157 list_delete(&ext
->aslas
);
159 admin_group_term(&ext
->ext_admin_group
);
161 XFREE(MTYPE_ISIS_SUBTLV
, ext
);
165 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
166 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
167 * that MT is disabled i.e. IS-IS is working with a Single Topology.
169 static struct isis_ext_subtlvs
*
170 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, uint16_t mtid
)
172 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
173 struct isis_adj_sid
*adj
;
174 struct isis_lan_adj_sid
*lan
;
175 struct listnode
*node
, *nnode
;
176 struct isis_asla_subtlvs
*new_asla
, *asla
;
178 /* Copy the Extended IS main part */
179 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
181 /* Disable IPv4 / IPv6 advertisement in function of MTID */
182 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
183 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR6
);
184 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR6
);
186 if (mtid
== ISIS_MT_IPV6_UNICAST
) {
187 UNSET_SUBTLV(rv
, EXT_LOCAL_ADDR
);
188 UNSET_SUBTLV(rv
, EXT_NEIGH_ADDR
);
191 /* Prepare (LAN)-Adjacency Segment Routing ID*/
192 init_item_list(&rv
->adj_sid
);
193 init_item_list(&rv
->lan_sid
);
195 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
196 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
198 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
199 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
201 if ((mtid
!= ISIS_MT_DISABLE
)
202 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
203 && (adj
->family
!= AF_INET
))
204 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
205 && (adj
->family
!= AF_INET6
))))
208 struct isis_adj_sid
*new;
210 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
211 new->family
= adj
->family
;
212 new->flags
= adj
->flags
;
213 new->weight
= adj
->weight
;
215 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
216 SET_SUBTLV(rv
, EXT_ADJ_SID
);
219 /* Same for LAN Adj SID */
220 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
222 if ((mtid
!= ISIS_MT_DISABLE
)
223 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
224 && (lan
->family
!= AF_INET
))
225 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
226 && (lan
->family
!= AF_INET6
))))
229 struct isis_lan_adj_sid
*new;
231 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
232 new->family
= lan
->family
;
233 new->flags
= lan
->flags
;
234 new->weight
= lan
->weight
;
235 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
237 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
238 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
241 rv
->aslas
= list_new();
243 for (ALL_LIST_ELEMENTS(exts
->aslas
, node
, nnode
, asla
)) {
244 new_asla
= XCALLOC(MTYPE_ISIS_SUBTLV
,
245 sizeof(struct isis_asla_subtlvs
));
246 memcpy(new_asla
, asla
, sizeof(struct isis_asla_subtlvs
));
248 new_asla
->ext_admin_group
.bitmap
.data
= NULL
;
249 admin_group_copy(&new_asla
->ext_admin_group
,
250 &asla
->ext_admin_group
);
252 listnode_add(rv
->aslas
, new_asla
);
255 rv
->ext_admin_group
.bitmap
.data
= NULL
;
256 admin_group_copy(&rv
->ext_admin_group
, &exts
->ext_admin_group
);
261 static void format_item_asla_subtlvs(struct isis_asla_subtlvs
*asla
,
262 struct sbuf
*buf
, int indent
)
264 char admin_group_buf
[ADMIN_GROUP_PRINT_MAX_SIZE
];
266 sbuf_push(buf
, indent
, "Application Specific Link Attributes:\n");
267 sbuf_push(buf
, indent
+ 2,
268 "L flag: %u, SA-Length: %u, UDA-Length: %u\n", asla
->legacy
,
269 asla
->standard_apps_length
, asla
->user_def_apps_length
);
270 sbuf_push(buf
, indent
+ 2, "Standard Applications: 0x%02x",
271 asla
->standard_apps
);
272 if (asla
->standard_apps
) {
273 uint8_t bit
= asla
->standard_apps
;
274 if (bit
& ISIS_SABM_FLAG_R
)
275 sbuf_push(buf
, 0, " RSVP-TE");
276 if (bit
& ISIS_SABM_FLAG_S
)
277 sbuf_push(buf
, 0, " SR-Policy");
278 if (bit
& ISIS_SABM_FLAG_L
)
279 sbuf_push(buf
, 0, " Loop-Free-Alternate");
280 if (bit
& ISIS_SABM_FLAG_X
)
281 sbuf_push(buf
, 0, " Flex-Algo");
283 sbuf_push(buf
, 0, "\n");
284 sbuf_push(buf
, indent
+ 2, "User Defined Applications: 0x%02x\n",
285 asla
->user_def_apps
);
287 if (IS_SUBTLV(asla
, EXT_ADM_GRP
)) {
288 sbuf_push(buf
, indent
+ 2, "Admin Group: 0x%08x\n",
290 sbuf_push(buf
, indent
+ 4, "Bit positions: %s\n",
291 admin_group_standard_print(
293 indent
+ 2 + strlen("Admin Group: "),
296 if (IS_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
) &&
297 admin_group_nb_words(&asla
->ext_admin_group
) != 0) {
298 sbuf_push(buf
, indent
+ 2, "Ext Admin Group: %s\n",
300 admin_group_buf
, ADMIN_GROUP_PRINT_MAX_SIZE
,
301 indent
+ 2 + strlen("Ext Admin Group: "),
302 &asla
->ext_admin_group
));
303 admin_group_print(admin_group_buf
,
304 indent
+ 2 + strlen("Ext Admin Group: "),
305 &asla
->ext_admin_group
);
306 if (admin_group_buf
[0] != '\0' &&
307 (buf
->pos
+ strlen(admin_group_buf
) +
308 SBUF_DEFAULT_SIZE
/ 2) < buf
->size
)
309 sbuf_push(buf
, indent
+ 4, "Bit positions: %s\n",
312 if (IS_SUBTLV(asla
, EXT_MAX_BW
))
313 sbuf_push(buf
, indent
+ 2,
314 "Maximum Bandwidth: %g (Bytes/sec)\n", asla
->max_bw
);
315 if (IS_SUBTLV(asla
, EXT_MAX_RSV_BW
))
316 sbuf_push(buf
, indent
+ 2,
317 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
319 if (IS_SUBTLV(asla
, EXT_UNRSV_BW
)) {
320 sbuf_push(buf
, indent
+ 2, "Unreserved Bandwidth:\n");
321 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
324 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
325 j
, asla
->unrsv_bw
[j
], j
+ 1,
326 asla
->unrsv_bw
[j
+ 1]);
329 if (IS_SUBTLV(asla
, EXT_TE_METRIC
))
330 sbuf_push(buf
, indent
+ 2, "Traffic Engineering Metric: %u\n",
332 /* Extended metrics */
333 if (IS_SUBTLV(asla
, EXT_DELAY
))
334 sbuf_push(buf
, indent
+ 2,
335 "%s Average Link Delay: %u (micro-sec)\n",
336 IS_ANORMAL(asla
->delay
) ? "Anomalous" : "Normal",
338 if (IS_SUBTLV(asla
, EXT_MM_DELAY
)) {
339 sbuf_push(buf
, indent
+ 2,
340 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
341 IS_ANORMAL(asla
->min_delay
) ? "Anomalous" : "Normal",
342 asla
->min_delay
& TE_EXT_MASK
,
343 asla
->max_delay
& TE_EXT_MASK
);
345 if (IS_SUBTLV(asla
, EXT_DELAY_VAR
)) {
346 sbuf_push(buf
, indent
+ 2, "Delay Variation: %u (micro-sec)\n",
347 asla
->delay_var
& TE_EXT_MASK
);
349 if (IS_SUBTLV(asla
, EXT_PKT_LOSS
))
350 sbuf_push(buf
, indent
+ 2, "%s Link Packet Loss: %g (%%)\n",
351 IS_ANORMAL(asla
->pkt_loss
) ? "Anomalous" : "Normal",
352 (float)((asla
->pkt_loss
& TE_EXT_MASK
) *
354 if (IS_SUBTLV(asla
, EXT_RES_BW
))
355 sbuf_push(buf
, indent
+ 2,
356 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
358 if (IS_SUBTLV(asla
, EXT_AVA_BW
))
359 sbuf_push(buf
, indent
+ 2,
360 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
362 if (IS_SUBTLV(asla
, EXT_USE_BW
))
363 sbuf_push(buf
, indent
+ 2,
364 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
368 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
369 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
370 struct sbuf
*buf
, struct json_object
*json
,
371 int indent
, uint16_t mtid
)
373 char admin_group_buf
[ADMIN_GROUP_PRINT_MAX_SIZE
];
376 struct isis_asla_subtlvs
*asla
;
377 struct listnode
*node
;
379 /* Standard metrics */
380 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
382 snprintfrr(aux_buf
, sizeof(aux_buf
), "0x%x",
384 json_object_string_add(json
, "adm-group", aux_buf
);
386 sbuf_push(buf
, indent
, "Admin Group: 0x%08x\n",
388 sbuf_push(buf
, indent
+ 2, "Bit positions: %s\n",
389 admin_group_standard_print(
391 indent
+ strlen("Admin Group: "),
396 if (IS_SUBTLV(exts
, EXT_EXTEND_ADM_GRP
) &&
397 admin_group_nb_words(&exts
->ext_admin_group
) != 0) {
399 /* TODO json after fix show database detail json */
400 sbuf_push(buf
, indent
, "Ext Admin Group: %s\n",
403 ADMIN_GROUP_PRINT_MAX_SIZE
,
404 indent
+ strlen("Ext Admin Group: "),
405 &exts
->ext_admin_group
));
406 admin_group_print(admin_group_buf
,
407 indent
+ strlen("Ext Admin Group: "),
408 &exts
->ext_admin_group
);
409 if (admin_group_buf
[0] != '\0' &&
410 (buf
->pos
+ strlen(admin_group_buf
) +
411 SBUF_DEFAULT_SIZE
/ 2) < buf
->size
)
412 sbuf_push(buf
, indent
+ 2,
413 "Bit positions: %s\n",
417 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
419 json_object_int_add(json
, "link-local-id",
421 json_object_int_add(json
, "link-remote-id",
424 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
426 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
430 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
432 inet_ntop(AF_INET
, &exts
->local_addr
, aux_buf
,
434 json_object_string_add(json
, "local-iface-ip", aux_buf
);
436 sbuf_push(buf
, indent
,
437 "Local Interface IP Address(es): %pI4\n",
440 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
442 inet_ntop(AF_INET
, &exts
->neigh_addr
, aux_buf
,
444 json_object_string_add(json
, "remote-iface-ip",
447 sbuf_push(buf
, indent
,
448 "Remote Interface IP Address(es): %pI4\n",
451 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
453 inet_ntop(AF_INET6
, &exts
->local_addr6
, aux_buf
,
455 json_object_string_add(json
, "local-iface-ipv6",
458 sbuf_push(buf
, indent
,
459 "Local Interface IPv6 Address(es): %pI6\n",
462 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
464 inet_ntop(AF_INET6
, &exts
->neigh_addr6
, aux_buf
,
466 json_object_string_add(json
, "remote-iface-ipv6",
469 sbuf_push(buf
, indent
,
470 "Remote Interface IPv6 Address(es): %pI6\n",
473 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
475 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
477 json_object_string_add(json
, "max-bandwith-bytes-sec",
480 sbuf_push(buf
, indent
,
481 "Maximum Bandwidth: %g (Bytes/sec)\n",
484 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
486 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
488 json_object_string_add(
489 json
, "max-res-bandwith-bytes-sec", aux_buf
);
493 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
496 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
498 struct json_object
*unrsv_json
;
499 unrsv_json
= json_object_new_object();
500 json_object_object_add(json
, "unrsv-bandwith-bytes-sec",
502 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 1) {
503 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d", j
);
504 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
506 json_object_string_add(unrsv_json
, cnt_buf
,
510 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
511 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
514 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
515 j
, exts
->unrsv_bw
[j
], j
+ 1,
516 exts
->unrsv_bw
[j
+ 1]);
520 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
522 json_object_int_add(json
, "te-metric", exts
->te_metric
);
524 sbuf_push(buf
, indent
,
525 "Traffic Engineering Metric: %u\n",
528 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
530 json_object_int_add(json
, "inter-as-te-remote-as",
533 sbuf_push(buf
, indent
,
534 "Inter-AS TE Remote AS number: %u\n",
537 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
539 inet_ntop(AF_INET6
, &exts
->remote_ip
, aux_buf
,
541 json_object_string_add(
542 json
, "inter-as-te-remote-asbr-ip", aux_buf
);
544 sbuf_push(buf
, indent
,
545 "Inter-AS TE Remote ASBR IP address: %pI4\n",
548 /* Extended metrics */
549 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
551 struct json_object
*avg_json
;
552 avg_json
= json_object_new_object();
553 json_object_object_add(json
, "avg-delay", avg_json
);
554 json_object_string_add(avg_json
, "delay",
555 IS_ANORMAL(exts
->delay
)
558 json_object_int_add(avg_json
, "micro-sec", exts
->delay
);
560 sbuf_push(buf
, indent
,
561 "%s Average Link Delay: %u (micro-sec)\n",
562 IS_ANORMAL(exts
->delay
) ? "Anomalous"
564 exts
->delay
& TE_EXT_MASK
);
566 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
568 struct json_object
*avg_json
;
569 avg_json
= json_object_new_object();
570 json_object_object_add(json
, "max-min-delay", avg_json
);
571 json_object_string_add(avg_json
, "delay",
572 IS_ANORMAL(exts
->min_delay
)
575 snprintfrr(aux_buf
, sizeof(aux_buf
), "%u / %u",
576 exts
->min_delay
& TE_EXT_MASK
,
577 exts
->max_delay
& TE_EXT_MASK
);
578 json_object_string_add(avg_json
, "micro-sec", aux_buf
);
583 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
584 IS_ANORMAL(exts
->min_delay
) ? "Anomalous"
586 exts
->min_delay
& TE_EXT_MASK
,
587 exts
->max_delay
& TE_EXT_MASK
);
589 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
591 json_object_int_add(json
, "delay-variation-micro-sec",
592 exts
->delay_var
& TE_EXT_MASK
);
594 sbuf_push(buf
, indent
,
595 "Delay Variation: %u (micro-sec)\n",
596 exts
->delay_var
& TE_EXT_MASK
);
598 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
600 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
601 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
603 struct json_object
*link_json
;
604 link_json
= json_object_new_object();
605 json_object_object_add(json
, "link-packet-loss",
607 json_object_string_add(link_json
, "loss",
608 IS_ANORMAL(exts
->pkt_loss
)
611 json_object_string_add(link_json
, "percentaje",
614 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
615 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous"
617 (float)((exts
->pkt_loss
& TE_EXT_MASK
) *
620 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
622 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
624 json_object_string_add(json
,
625 "unidir-residual-band-bytes-sec",
630 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
633 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
635 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
637 json_object_string_add(
638 json
, "unidir-available-band-bytes-sec",
643 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
646 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
648 snprintfrr(aux_buf
, sizeof(aux_buf
), "%g",
650 json_object_string_add(json
,
651 "unidir-utilized-band-bytes-sec",
656 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
659 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
660 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
661 struct isis_adj_sid
*adj
;
664 struct json_object
*arr_adj_json
, *flags_json
;
665 arr_adj_json
= json_object_new_array();
666 json_object_object_add(json
, "adj-sid", arr_adj_json
);
667 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
668 adj
; adj
= adj
->next
) {
669 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
671 flags_json
= json_object_new_object();
672 json_object_int_add(flags_json
, "sid",
674 json_object_int_add(flags_json
, "weight",
676 json_object_string_add(
677 flags_json
, "flag-f",
678 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
681 json_object_string_add(
682 flags_json
, "flag-b",
683 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
686 json_object_string_add(
687 flags_json
, "flag-v",
688 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
691 json_object_string_add(
692 flags_json
, "flag-l",
693 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
696 json_object_string_add(
697 flags_json
, "flag-s",
698 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
701 json_object_string_add(
702 flags_json
, "flag-p",
703 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
706 json_object_array_add(arr_adj_json
, flags_json
);
709 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
;
710 adj
; adj
= adj
->next
) {
713 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
714 adj
->sid
, adj
->weight
,
715 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
718 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
721 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
724 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
727 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
730 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
735 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
736 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
737 struct isis_lan_adj_sid
*lan
;
739 struct json_object
*arr_adj_json
, *flags_json
;
740 arr_adj_json
= json_object_new_array();
741 json_object_object_add(json
, "lan-adj-sid",
743 for (lan
= (struct isis_lan_adj_sid
*)
745 lan
; lan
= lan
->next
) {
746 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
747 (lan
->family
!= AF_INET
)) ||
748 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
749 (lan
->family
!= AF_INET6
)))
751 snprintfrr(cnt_buf
, sizeof(cnt_buf
), "%d",
753 flags_json
= json_object_new_object();
754 json_object_int_add(flags_json
, "sid",
756 json_object_int_add(flags_json
, "weight",
758 json_object_string_add(
759 flags_json
, "flag-f",
760 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
763 json_object_string_add(
764 flags_json
, "flag-b",
765 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
768 json_object_string_add(
769 flags_json
, "flag-v",
770 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
773 json_object_string_add(
774 flags_json
, "flag-l",
775 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
778 json_object_string_add(
779 flags_json
, "flag-s",
780 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
783 json_object_string_add(
784 flags_json
, "flag-p",
785 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
788 json_object_array_add(arr_adj_json
, flags_json
);
792 for (lan
= (struct isis_lan_adj_sid
*)
794 lan
; lan
= lan
->next
) {
795 if (((mtid
== ISIS_MT_IPV4_UNICAST
) &&
796 (lan
->family
!= AF_INET
)) ||
797 ((mtid
== ISIS_MT_IPV6_UNICAST
) &&
798 (lan
->family
!= AF_INET6
)))
802 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
803 " Neighbor-ID: %pSY\n",
804 lan
->sid
, lan
->weight
,
805 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
808 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
811 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
814 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
817 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
820 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
826 for (ALL_LIST_ELEMENTS_RO(exts
->aslas
, node
, asla
))
827 format_item_asla_subtlvs(asla
, buf
, indent
);
830 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
832 isis_del_ext_subtlvs(exts
);
835 static int pack_item_ext_subtlv_asla(struct isis_asla_subtlvs
*asla
,
836 struct stream
*s
, size_t *min_len
)
839 size_t subtlv_len_pos
;
842 stream_putc(s
, ISIS_SUBTLV_ASLA
);
844 subtlv_len_pos
= stream_get_endp(s
);
845 stream_putc(s
, 0); /* length will be filled later */
847 /* SABM Flag/Length */
849 stream_putc(s
, ASLA_LEGACY_FLAG
| asla
->standard_apps_length
);
851 stream_putc(s
, asla
->standard_apps_length
);
852 stream_putc(s
, asla
->user_def_apps_length
); /* UDABM Flag/Length */
853 stream_putc(s
, asla
->standard_apps
);
854 stream_putc(s
, asla
->user_def_apps
);
856 /* Administrative Group */
857 if (IS_SUBTLV(asla
, EXT_ADM_GRP
)) {
858 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
859 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
860 stream_putl(s
, asla
->admin_group
);
863 /* Extended Administrative Group */
864 if (IS_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
) &&
865 admin_group_nb_words(&asla
->ext_admin_group
) != 0) {
867 size_t ag_length_pos
;
868 struct admin_group
*ag
;
870 stream_putc(s
, ISIS_SUBTLV_EXT_ADMIN_GRP
);
871 ag_length_pos
= stream_get_endp(s
);
872 stream_putc(s
, 0); /* length will be filled later*/
874 ag
= &asla
->ext_admin_group
;
875 for (size_t i
= 0; i
< admin_group_nb_words(ag
); i
++)
876 stream_putl(s
, ag
->bitmap
.data
[i
]);
878 ag_length
= stream_get_endp(s
) - ag_length_pos
- 1;
879 stream_putc_at(s
, ag_length_pos
, ag_length
);
882 if (IS_SUBTLV(asla
, EXT_MAX_BW
)) {
883 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
884 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
885 stream_putf(s
, asla
->max_bw
);
887 if (IS_SUBTLV(asla
, EXT_MAX_RSV_BW
)) {
888 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
889 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
890 stream_putf(s
, asla
->max_rsv_bw
);
892 if (IS_SUBTLV(asla
, EXT_UNRSV_BW
)) {
893 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
894 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
895 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
896 stream_putf(s
, asla
->unrsv_bw
[j
]);
898 if (IS_SUBTLV(asla
, EXT_TE_METRIC
)) {
899 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
900 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
901 stream_put3(s
, asla
->te_metric
);
903 if (IS_SUBTLV(asla
, EXT_DELAY
)) {
904 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
905 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
906 stream_putl(s
, asla
->delay
);
908 if (IS_SUBTLV(asla
, EXT_MM_DELAY
)) {
909 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
910 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
911 stream_putl(s
, asla
->min_delay
);
912 stream_putl(s
, asla
->max_delay
);
914 if (IS_SUBTLV(asla
, EXT_DELAY_VAR
)) {
915 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
916 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
917 stream_putl(s
, asla
->delay_var
);
919 if (IS_SUBTLV(asla
, EXT_PKT_LOSS
)) {
920 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
921 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
922 stream_putl(s
, asla
->pkt_loss
);
924 if (IS_SUBTLV(asla
, EXT_RES_BW
)) {
925 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
926 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
927 stream_putf(s
, asla
->res_bw
);
929 if (IS_SUBTLV(asla
, EXT_AVA_BW
)) {
930 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
931 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
932 stream_putf(s
, asla
->ava_bw
);
934 if (IS_SUBTLV(asla
, EXT_USE_BW
)) {
935 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
936 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
937 stream_putf(s
, asla
->use_bw
);
940 subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
941 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
946 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
947 struct stream
*s
, size_t *min_len
)
949 struct isis_asla_subtlvs
*asla
;
950 struct listnode
*node
;
954 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
955 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
959 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
960 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
961 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
962 stream_putl(s
, exts
->adm_group
);
964 if (IS_SUBTLV(exts
, EXT_EXTEND_ADM_GRP
) &&
965 admin_group_nb_words(&exts
->ext_admin_group
) != 0) {
966 /* Extended Administrative Group */
968 size_t ag_length_pos
;
969 struct admin_group
*ag
;
971 stream_putc(s
, ISIS_SUBTLV_EXT_ADMIN_GRP
);
972 ag_length_pos
= stream_get_endp(s
);
973 stream_putc(s
, 0); /* length will be filled later*/
975 ag
= &exts
->ext_admin_group
;
976 for (size_t i
= 0; i
< admin_group_nb_words(ag
); i
++)
977 stream_putl(s
, ag
->bitmap
.data
[i
]);
979 ag_length
= stream_get_endp(s
) - ag_length_pos
- 1;
980 stream_putc_at(s
, ag_length_pos
, ag_length
);
982 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
983 stream_putc(s
, ISIS_SUBTLV_LLRI
);
984 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
985 stream_putl(s
, exts
->local_llri
);
986 stream_putl(s
, exts
->remote_llri
);
988 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
989 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
990 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
991 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
993 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
994 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
995 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
996 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
998 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
999 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
1000 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
1001 stream_put(s
, &exts
->local_addr6
, 16);
1003 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
1004 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
1005 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
1006 stream_put(s
, &exts
->neigh_addr6
, 16);
1008 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
1009 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
1010 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1011 stream_putf(s
, exts
->max_bw
);
1013 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
1014 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
1015 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1016 stream_putf(s
, exts
->max_rsv_bw
);
1018 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
1019 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
1020 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
1021 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
1022 stream_putf(s
, exts
->unrsv_bw
[j
]);
1024 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
1025 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
1026 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
1027 stream_put3(s
, exts
->te_metric
);
1029 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
1030 stream_putc(s
, ISIS_SUBTLV_RAS
);
1031 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1032 stream_putl(s
, exts
->remote_as
);
1034 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
1035 stream_putc(s
, ISIS_SUBTLV_RIP
);
1036 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1037 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
1039 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
1040 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
1041 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1042 stream_putl(s
, exts
->delay
);
1044 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
1045 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
1046 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
1047 stream_putl(s
, exts
->min_delay
);
1048 stream_putl(s
, exts
->max_delay
);
1050 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
1051 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
1052 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1053 stream_putl(s
, exts
->delay_var
);
1055 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
1056 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
1057 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1058 stream_putl(s
, exts
->pkt_loss
);
1060 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
1061 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
1062 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1063 stream_putf(s
, exts
->res_bw
);
1065 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
1066 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
1067 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1068 stream_putf(s
, exts
->ava_bw
);
1070 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
1071 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
1072 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
1073 stream_putf(s
, exts
->use_bw
);
1075 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1076 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
1077 struct isis_adj_sid
*adj
;
1079 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
1081 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
1082 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
1083 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
1085 stream_putc(s
, size
);
1086 stream_putc(s
, adj
->flags
);
1087 stream_putc(s
, adj
->weight
);
1088 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1089 stream_put3(s
, adj
->sid
);
1091 stream_putl(s
, adj
->sid
);
1095 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
1096 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
1097 struct isis_lan_adj_sid
*lan
;
1099 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
1101 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
1102 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
1103 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
1105 stream_putc(s
, size
);
1106 stream_putc(s
, lan
->flags
);
1107 stream_putc(s
, lan
->weight
);
1108 stream_put(s
, lan
->neighbor_id
, 6);
1109 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1110 stream_put3(s
, lan
->sid
);
1112 stream_putl(s
, lan
->sid
);
1116 for (ALL_LIST_ELEMENTS_RO(exts
->aslas
, node
, asla
)) {
1117 ret
= pack_item_ext_subtlv_asla(asla
, s
, min_len
);
1125 static int unpack_item_ext_subtlv_asla(uint16_t mtid
, uint8_t subtlv_len
,
1126 struct stream
*s
, struct sbuf
*log
,
1128 struct isis_ext_subtlvs
*exts
)
1130 /* Standard App Identifier Bit Flags/Length */
1131 uint8_t sabm_flag_len
;
1132 /* User-defined App Identifier Bit Flags/Length */
1133 uint8_t uabm_flag_len
;
1134 uint8_t sabm
[ASLA_APP_IDENTIFIER_BIT_LENGTH
] = {0};
1135 uint8_t uabm
[ASLA_APP_IDENTIFIER_BIT_LENGTH
] = {0};
1137 uint8_t subsubtlv_type
;
1138 uint8_t subsubtlv_len
;
1140 struct isis_asla_subtlvs
*asla
;
1142 if (subtlv_len
< ISIS_SUBSUBTLV_HDR_SIZE
) {
1143 TLV_SIZE_MISMATCH(log
, indent
, "ASLA");
1148 asla
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*asla
));
1150 admin_group_init(&asla
->ext_admin_group
);
1153 sabm_flag_len
= stream_getc(s
);
1154 uabm_flag_len
= stream_getc(s
);
1155 asla
->legacy
= CHECK_FLAG(sabm_flag_len
, ASLA_LEGACY_FLAG
);
1156 asla
->standard_apps_length
= ASLA_APPS_LENGTH_MASK
& sabm_flag_len
;
1157 asla
->user_def_apps_length
= ASLA_APPS_LENGTH_MASK
& uabm_flag_len
;
1159 for (int i
= 0; i
< asla
->standard_apps_length
; i
++)
1160 sabm
[i
] = stream_getc(s
);
1161 for (int i
= 0; i
< asla
->user_def_apps_length
; i
++)
1162 uabm
[i
] = stream_getc(s
);
1164 asla
->standard_apps
= sabm
[0];
1165 asla
->user_def_apps
= uabm
[0];
1167 readable
= subtlv_len
- 4;
1168 while (readable
> 0) {
1169 if (readable
< ISIS_SUBSUBTLV_HDR_SIZE
) {
1170 TLV_SIZE_MISMATCH(log
, indent
, "ASLA Sub TLV");
1174 subsubtlv_type
= stream_getc(s
);
1175 subsubtlv_len
= stream_getc(s
);
1176 readable
-= ISIS_SUBSUBTLV_HDR_SIZE
;
1179 switch (subsubtlv_type
) {
1180 case ISIS_SUBTLV_ADMIN_GRP
:
1181 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1182 TLV_SIZE_MISMATCH(log
, indent
,
1184 stream_forward_getp(s
, subsubtlv_len
);
1186 asla
->admin_group
= stream_getl(s
);
1187 SET_SUBTLV(asla
, EXT_ADM_GRP
);
1191 case ISIS_SUBTLV_EXT_ADMIN_GRP
:
1192 nb_groups
= subsubtlv_len
/ sizeof(uint32_t);
1193 for (size_t i
= 0; i
< nb_groups
; i
++) {
1194 uint32_t val
= stream_getl(s
);
1196 admin_group_bulk_set(&asla
->ext_admin_group
,
1199 SET_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
);
1201 case ISIS_SUBTLV_MAX_BW
:
1202 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1203 TLV_SIZE_MISMATCH(log
, indent
,
1204 "Maximum Bandwidth");
1205 stream_forward_getp(s
, subsubtlv_len
);
1207 asla
->max_bw
= stream_getf(s
);
1208 SET_SUBTLV(asla
, EXT_MAX_BW
);
1211 case ISIS_SUBTLV_MAX_RSV_BW
:
1212 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1215 "Maximum Reservable Bandwidth");
1216 stream_forward_getp(s
, subsubtlv_len
);
1218 asla
->max_rsv_bw
= stream_getf(s
);
1219 SET_SUBTLV(asla
, EXT_MAX_RSV_BW
);
1222 case ISIS_SUBTLV_UNRSV_BW
:
1223 if (subsubtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
1224 TLV_SIZE_MISMATCH(log
, indent
,
1225 "Unreserved Bandwidth");
1226 stream_forward_getp(s
, subsubtlv_len
);
1228 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
1229 asla
->unrsv_bw
[i
] = stream_getf(s
);
1230 SET_SUBTLV(asla
, EXT_UNRSV_BW
);
1233 case ISIS_SUBTLV_TE_METRIC
:
1234 if (subsubtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
1235 TLV_SIZE_MISMATCH(log
, indent
,
1236 "Traffic Engineering Metric");
1237 stream_forward_getp(s
, subsubtlv_len
);
1239 asla
->te_metric
= stream_get3(s
);
1240 SET_SUBTLV(asla
, EXT_TE_METRIC
);
1243 /* Extended Metrics as defined in RFC 7810 */
1244 case ISIS_SUBTLV_AV_DELAY
:
1245 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1246 TLV_SIZE_MISMATCH(log
, indent
,
1247 "Average Link Delay");
1248 stream_forward_getp(s
, subsubtlv_len
);
1250 asla
->delay
= stream_getl(s
);
1251 SET_SUBTLV(asla
, EXT_DELAY
);
1254 case ISIS_SUBTLV_MM_DELAY
:
1255 if (subsubtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
1256 TLV_SIZE_MISMATCH(log
, indent
,
1257 "Min/Max Link Delay");
1258 stream_forward_getp(s
, subsubtlv_len
);
1260 asla
->min_delay
= stream_getl(s
);
1261 asla
->max_delay
= stream_getl(s
);
1262 SET_SUBTLV(asla
, EXT_MM_DELAY
);
1265 case ISIS_SUBTLV_DELAY_VAR
:
1266 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1267 TLV_SIZE_MISMATCH(log
, indent
,
1269 stream_forward_getp(s
, subsubtlv_len
);
1271 asla
->delay_var
= stream_getl(s
);
1272 SET_SUBTLV(asla
, EXT_DELAY_VAR
);
1275 case ISIS_SUBTLV_PKT_LOSS
:
1276 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1277 TLV_SIZE_MISMATCH(log
, indent
,
1278 "Link Packet Loss");
1279 stream_forward_getp(s
, subsubtlv_len
);
1281 asla
->pkt_loss
= stream_getl(s
);
1282 SET_SUBTLV(asla
, EXT_PKT_LOSS
);
1285 case ISIS_SUBTLV_RES_BW
:
1286 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1289 "Unidirectional Residual Bandwidth");
1290 stream_forward_getp(s
, subsubtlv_len
);
1292 asla
->res_bw
= stream_getf(s
);
1293 SET_SUBTLV(asla
, EXT_RES_BW
);
1296 case ISIS_SUBTLV_AVA_BW
:
1297 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1300 "Unidirectional Available Bandwidth");
1301 stream_forward_getp(s
, subsubtlv_len
);
1303 asla
->ava_bw
= stream_getf(s
);
1304 SET_SUBTLV(asla
, EXT_AVA_BW
);
1307 case ISIS_SUBTLV_USE_BW
:
1308 if (subsubtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1311 "Unidirectional Utilized Bandwidth");
1312 stream_forward_getp(s
, subsubtlv_len
);
1314 asla
->use_bw
= stream_getf(s
);
1315 SET_SUBTLV(asla
, EXT_USE_BW
);
1319 zlog_debug("unknown (t,l)=(%u,%u)", subsubtlv_type
,
1321 stream_forward_getp(s
, subsubtlv_len
);
1324 readable
-= subsubtlv_len
;
1327 listnode_add(exts
->aslas
, asla
);
1332 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1333 struct sbuf
*log
, void *dest
, int indent
)
1336 uint8_t subtlv_type
;
1341 struct isis_extended_reach
*rv
= dest
;
1342 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
1347 * Parse subTLVs until reach subTLV length
1348 * Check that it remains at least 2 bytes: subTLV Type & Length
1350 while (len
> sum
+ 2) {
1351 /* Read SubTLV Type and Length */
1352 subtlv_type
= stream_getc(s
);
1353 subtlv_len
= stream_getc(s
);
1354 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
1357 "TLV %hhu: Available data %u is less than TLV size %u !\n",
1358 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
1363 switch (subtlv_type
) {
1364 /* Standard Metric as defined in RFC5305 */
1365 case ISIS_SUBTLV_ADMIN_GRP
:
1366 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1367 TLV_SIZE_MISMATCH(log
, indent
,
1368 "Administrative Group");
1369 stream_forward_getp(s
, subtlv_len
);
1371 exts
->adm_group
= stream_getl(s
);
1372 SET_SUBTLV(exts
, EXT_ADM_GRP
);
1375 case ISIS_SUBTLV_EXT_ADMIN_GRP
:
1376 nb_groups
= subtlv_len
/ sizeof(uint32_t);
1377 for (size_t i
= 0; i
< nb_groups
; i
++) {
1378 val
= stream_getl(s
);
1379 admin_group_bulk_set(&exts
->ext_admin_group
,
1382 SET_SUBTLV(exts
, EXT_EXTEND_ADM_GRP
);
1384 case ISIS_SUBTLV_LLRI
:
1385 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
1386 TLV_SIZE_MISMATCH(log
, indent
, "Link ID");
1387 stream_forward_getp(s
, subtlv_len
);
1389 exts
->local_llri
= stream_getl(s
);
1390 exts
->remote_llri
= stream_getl(s
);
1391 SET_SUBTLV(exts
, EXT_LLRI
);
1394 case ISIS_SUBTLV_LOCAL_IPADDR
:
1395 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1396 TLV_SIZE_MISMATCH(log
, indent
,
1397 "Local IP address");
1398 stream_forward_getp(s
, subtlv_len
);
1400 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
1401 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
1404 case ISIS_SUBTLV_RMT_IPADDR
:
1405 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1406 TLV_SIZE_MISMATCH(log
, indent
,
1407 "Remote IP address");
1408 stream_forward_getp(s
, subtlv_len
);
1410 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
1411 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
1414 case ISIS_SUBTLV_LOCAL_IPADDR6
:
1415 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
1416 TLV_SIZE_MISMATCH(log
, indent
,
1417 "Local IPv6 address");
1418 stream_forward_getp(s
, subtlv_len
);
1420 stream_get(&exts
->local_addr6
, s
, 16);
1421 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
1424 case ISIS_SUBTLV_RMT_IPADDR6
:
1425 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
1426 TLV_SIZE_MISMATCH(log
, indent
,
1427 "Remote IPv6 address");
1428 stream_forward_getp(s
, subtlv_len
);
1430 stream_get(&exts
->neigh_addr6
, s
, 16);
1431 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
1434 case ISIS_SUBTLV_MAX_BW
:
1435 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1436 TLV_SIZE_MISMATCH(log
, indent
,
1437 "Maximum Bandwidth");
1438 stream_forward_getp(s
, subtlv_len
);
1440 exts
->max_bw
= stream_getf(s
);
1441 SET_SUBTLV(exts
, EXT_MAX_BW
);
1444 case ISIS_SUBTLV_MAX_RSV_BW
:
1445 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1448 "Maximum Reservable Bandwidth");
1449 stream_forward_getp(s
, subtlv_len
);
1451 exts
->max_rsv_bw
= stream_getf(s
);
1452 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
1455 case ISIS_SUBTLV_UNRSV_BW
:
1456 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
1457 TLV_SIZE_MISMATCH(log
, indent
,
1458 "Unreserved Bandwidth");
1459 stream_forward_getp(s
, subtlv_len
);
1461 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
1462 exts
->unrsv_bw
[i
] = stream_getf(s
);
1463 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
1466 case ISIS_SUBTLV_TE_METRIC
:
1467 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
1468 TLV_SIZE_MISMATCH(log
, indent
,
1469 "Traffic Engineering Metric");
1470 stream_forward_getp(s
, subtlv_len
);
1472 exts
->te_metric
= stream_get3(s
);
1473 SET_SUBTLV(exts
, EXT_TE_METRIC
);
1476 case ISIS_SUBTLV_RAS
:
1477 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1478 TLV_SIZE_MISMATCH(log
, indent
,
1479 "Remote AS number");
1480 stream_forward_getp(s
, subtlv_len
);
1482 exts
->remote_as
= stream_getl(s
);
1483 SET_SUBTLV(exts
, EXT_RMT_AS
);
1486 case ISIS_SUBTLV_RIP
:
1487 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1488 TLV_SIZE_MISMATCH(log
, indent
,
1489 "Remote ASBR IP Address");
1490 stream_forward_getp(s
, subtlv_len
);
1492 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
1493 SET_SUBTLV(exts
, EXT_RMT_IP
);
1496 /* Extended Metrics as defined in RFC 7810 */
1497 case ISIS_SUBTLV_AV_DELAY
:
1498 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1499 TLV_SIZE_MISMATCH(log
, indent
,
1500 "Average Link Delay");
1501 stream_forward_getp(s
, subtlv_len
);
1503 exts
->delay
= stream_getl(s
);
1504 SET_SUBTLV(exts
, EXT_DELAY
);
1507 case ISIS_SUBTLV_MM_DELAY
:
1508 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
1509 TLV_SIZE_MISMATCH(log
, indent
,
1510 "Min/Max Link Delay");
1511 stream_forward_getp(s
, subtlv_len
);
1513 exts
->min_delay
= stream_getl(s
);
1514 exts
->max_delay
= stream_getl(s
);
1515 SET_SUBTLV(exts
, EXT_MM_DELAY
);
1518 case ISIS_SUBTLV_DELAY_VAR
:
1519 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1520 TLV_SIZE_MISMATCH(log
, indent
,
1522 stream_forward_getp(s
, subtlv_len
);
1524 exts
->delay_var
= stream_getl(s
);
1525 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
1528 case ISIS_SUBTLV_PKT_LOSS
:
1529 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1530 TLV_SIZE_MISMATCH(log
, indent
,
1531 "Link Packet Loss");
1532 stream_forward_getp(s
, subtlv_len
);
1534 exts
->pkt_loss
= stream_getl(s
);
1535 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
1538 case ISIS_SUBTLV_RES_BW
:
1539 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1542 "Unidirectional Residual Bandwidth");
1543 stream_forward_getp(s
, subtlv_len
);
1545 exts
->res_bw
= stream_getf(s
);
1546 SET_SUBTLV(exts
, EXT_RES_BW
);
1549 case ISIS_SUBTLV_AVA_BW
:
1550 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1553 "Unidirectional Available Bandwidth");
1554 stream_forward_getp(s
, subtlv_len
);
1556 exts
->ava_bw
= stream_getf(s
);
1557 SET_SUBTLV(exts
, EXT_AVA_BW
);
1560 case ISIS_SUBTLV_USE_BW
:
1561 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
1564 "Unidirectional Utilized Bandwidth");
1565 stream_forward_getp(s
, subtlv_len
);
1567 exts
->use_bw
= stream_getf(s
);
1568 SET_SUBTLV(exts
, EXT_USE_BW
);
1571 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1572 case ISIS_SUBTLV_ADJ_SID
:
1573 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
1574 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
1575 TLV_SIZE_MISMATCH(log
, indent
, "Adjacency SID");
1576 stream_forward_getp(s
, subtlv_len
);
1578 struct isis_adj_sid
*adj
;
1580 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1581 sizeof(struct isis_adj_sid
));
1582 adj
->flags
= stream_getc(s
);
1583 adj
->weight
= stream_getc(s
);
1584 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1585 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
1586 TLV_SIZE_MISMATCH(log
, indent
,
1588 stream_forward_getp(s
, subtlv_len
- 2);
1589 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
1593 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1595 != ISIS_SUBTLV_ADJ_SID_SIZE
1597 TLV_SIZE_MISMATCH(log
, indent
,
1599 stream_forward_getp(s
, subtlv_len
- 2);
1600 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
1604 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1605 adj
->sid
= stream_get3(s
);
1606 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
1608 adj
->sid
= stream_getl(s
);
1610 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1611 adj
->family
= AF_INET
;
1612 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1613 adj
->family
= AF_INET6
;
1614 append_item(&exts
->adj_sid
,
1615 (struct isis_item
*)adj
);
1616 SET_SUBTLV(exts
, EXT_ADJ_SID
);
1619 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1620 case ISIS_SUBTLV_LAN_ADJ_SID
:
1621 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1622 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
1623 TLV_SIZE_MISMATCH(log
, indent
,
1624 "LAN-Adjacency SID");
1625 stream_forward_getp(s
, subtlv_len
);
1627 struct isis_lan_adj_sid
*lan
;
1629 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
1630 sizeof(struct isis_lan_adj_sid
));
1631 lan
->flags
= stream_getc(s
);
1632 lan
->weight
= stream_getc(s
);
1633 stream_get(&(lan
->neighbor_id
), s
,
1636 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
1638 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
1639 TLV_SIZE_MISMATCH(log
, indent
,
1640 "LAN-Adjacency SID");
1641 stream_forward_getp(
1644 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
1648 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
1650 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1652 TLV_SIZE_MISMATCH(log
, indent
,
1653 "LAN-Adjacency SID");
1654 stream_forward_getp(
1657 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
1661 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
1662 lan
->sid
= stream_get3(s
);
1663 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
1665 lan
->sid
= stream_getl(s
);
1667 if (mtid
== ISIS_MT_IPV4_UNICAST
)
1668 lan
->family
= AF_INET
;
1669 if (mtid
== ISIS_MT_IPV6_UNICAST
)
1670 lan
->family
= AF_INET6
;
1671 append_item(&exts
->lan_sid
,
1672 (struct isis_item
*)lan
);
1673 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
1676 case ISIS_SUBTLV_ASLA
:
1677 if (unpack_item_ext_subtlv_asla(mtid
, subtlv_len
, s
,
1680 sbuf_push(log
, indent
, "TLV parse error");
1684 /* Skip unknown TLV */
1685 stream_forward_getp(s
, subtlv_len
);
1688 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
1694 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1695 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
1697 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1698 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1700 rv
->flags
= sid
->flags
;
1701 rv
->algorithm
= sid
->algorithm
;
1702 rv
->value
= sid
->value
;
1703 return (struct isis_item
*)rv
;
1706 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
1707 struct sbuf
*buf
, struct json_object
*json
,
1710 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1713 struct json_object
*sr_json
;
1714 sr_json
= json_object_new_object();
1715 json_object_object_add(json
, "sr", sr_json
);
1716 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1717 json_object_int_add(sr_json
, "label", sid
->value
);
1719 json_object_int_add(sr_json
, "index", sid
->value
);
1721 json_object_int_add(sr_json
, "alg", sid
->algorithm
);
1722 json_object_string_add(
1723 sr_json
, "readvertised",
1724 ((sid
->flags
& ISIS_PREFIX_SID_READVERTISED
) ? "yes"
1726 json_object_string_add(
1728 ((sid
->flags
& ISIS_PREFIX_SID_NODE
) ? "yes" : ""));
1729 json_object_string_add(sr_json
, "php",
1730 ((sid
->flags
& ISIS_PREFIX_SID_NO_PHP
)
1733 json_object_string_add(
1734 sr_json
, "explicit-null",
1735 ((sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
) ? "yes"
1737 json_object_string_add(
1739 ((sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? "yes" : ""));
1740 json_object_string_add(
1742 ((sid
->flags
& ISIS_PREFIX_SID_LOCAL
) ? "yes" : ""));
1745 sbuf_push(buf
, indent
, "SR Prefix-SID ");
1746 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1747 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
1749 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
1751 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
1752 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
1753 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
1756 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
1757 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP"
1759 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
1762 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
1763 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
1767 static void free_item_prefix_sid(struct isis_item
*i
)
1769 XFREE(MTYPE_ISIS_SUBTLV
, i
);
1772 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
1775 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
1777 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
1779 if (STREAM_WRITEABLE(s
) < size
) {
1784 stream_putc(s
, sid
->flags
);
1785 stream_putc(s
, sid
->algorithm
);
1787 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
1788 stream_put3(s
, sid
->value
);
1790 stream_putl(s
, sid
->value
);
1796 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1797 struct sbuf
*log
, void *dest
, int indent
)
1799 struct isis_subtlvs
*subtlvs
= dest
;
1800 struct isis_prefix_sid sid
= {
1803 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
1806 sbuf_push(log
, indent
,
1807 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1812 sid
.flags
= stream_getc(s
);
1813 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1814 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
1815 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
1819 sid
.algorithm
= stream_getc(s
);
1821 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
1822 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1823 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
1824 if (len
!= expected_size
) {
1825 sbuf_push(log
, indent
,
1826 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1827 expected_size
, len
);
1831 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
1832 sid
.value
= stream_get3(s
);
1833 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
1834 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
1839 sid
.value
= stream_getl(s
);
1842 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, NULL
, indent
+ 2);
1843 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
1847 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1849 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
1854 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1855 rv
->family
= p
->family
;
1856 rv
->prefixlen
= p
->prefixlen
;
1857 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
1861 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1863 struct json_object
*json
,
1869 char prefixbuf
[PREFIX2STR_BUFFER
];
1871 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
));
1872 json_object_string_add(json
, "ipv6-src-prefix", prefixbuf
);
1874 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1875 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1879 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1885 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1888 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1889 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1890 stream_putc(s
, p
->prefixlen
);
1891 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1895 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1896 uint8_t tlv_type
, uint8_t tlv_len
,
1897 struct stream
*s
, struct sbuf
*log
,
1898 void *dest
, int indent
)
1900 struct isis_subtlvs
*subtlvs
= dest
;
1901 struct prefix_ipv6 p
= {
1905 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1908 sbuf_push(log
, indent
,
1909 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1914 p
.prefixlen
= stream_getc(s
);
1915 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1916 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1921 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1924 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1925 1 + PSIZE(p
.prefixlen
), tlv_len
);
1929 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1931 if (subtlvs
->source_prefix
) {
1934 "WARNING: source prefix Sub-TLV present multiple times.\n");
1935 /* Ignore all but first occurrence of the source prefix Sub-TLV
1940 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1941 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1945 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1946 enum isis_tlv_type type
,
1947 struct isis_item
*item
);
1948 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1949 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1950 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1951 enum isis_tlv_type type
, struct isis_item_list
*items
,
1952 struct sbuf
*buf
, struct json_object
*json
,
1954 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1955 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1956 struct isis_item_list
*items
);
1957 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1958 enum isis_tlv_type type
, struct isis_item_list
*items
,
1959 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1960 const struct pack_order_entry
*pe
,
1961 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1962 struct list
*new_fragment_arg
);
1963 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1965 /* Functions related to subtlvs */
1967 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1969 struct isis_subtlvs
*result
;
1971 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1972 result
->context
= context
;
1974 init_item_list(&result
->prefix_sids
);
1979 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1984 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1986 rv
->context
= subtlvs
->context
;
1988 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1989 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1992 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1996 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1997 struct json_object
*json
, int indent
)
1999 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
2000 &subtlvs
->prefix_sids
, buf
, json
, indent
);
2002 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, json
, indent
);
2005 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
2010 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
2011 &subtlvs
->prefix_sids
);
2013 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
2015 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
2018 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
2021 size_t subtlv_len_pos
= stream_get_endp(s
);
2023 if (STREAM_WRITEABLE(s
) < 1)
2026 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
2028 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
2029 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
2033 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
2037 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
2038 if (subtlv_len
> 255)
2041 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
2045 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
2046 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2047 int indent
, bool *unpacked_known_tlvs
);
2049 /* Functions related to TLVs 1 Area Addresses */
2051 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
2053 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
2054 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2056 rv
->len
= addr
->len
;
2057 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
2058 return (struct isis_item
*)rv
;
2061 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
2062 struct sbuf
*buf
, struct json_object
*json
,
2065 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
2066 struct iso_address iso_addr
;
2068 memcpy(iso_addr
.area_addr
, addr
->addr
, ISO_ADDR_SIZE
);
2069 iso_addr
.addr_len
= addr
->len
;
2071 json_object_string_addf(json
, "area-addr", "%pIS", &iso_addr
);
2073 sbuf_push(buf
, indent
, "Area Address: %pIS\n", &iso_addr
);
2076 static void free_item_area_address(struct isis_item
*i
)
2078 XFREE(MTYPE_ISIS_TLV
, i
);
2081 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
2084 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
2086 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
2087 *min_len
= (unsigned)1 + addr
->len
;
2090 stream_putc(s
, addr
->len
);
2091 stream_put(s
, addr
->addr
, addr
->len
);
2095 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
2096 struct stream
*s
, struct sbuf
*log
,
2097 void *dest
, int indent
)
2099 struct isis_tlvs
*tlvs
= dest
;
2100 struct isis_area_address
*rv
= NULL
;
2102 sbuf_push(log
, indent
, "Unpack area address...\n");
2106 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
2111 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2112 rv
->len
= stream_getc(s
);
2114 if (len
< 1 + rv
->len
) {
2115 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
2120 if (rv
->len
< 1 || rv
->len
> 20) {
2121 sbuf_push(log
, indent
,
2122 "Implausible area address length %hhu\n",
2127 stream_get(rv
->addr
, s
, rv
->len
);
2129 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
2130 log
, NULL
, indent
+ 2);
2131 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
2134 XFREE(MTYPE_ISIS_TLV
, rv
);
2138 /* Functions related to TLV 2 (Old-Style) IS Reach */
2139 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
2141 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
2142 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2144 memcpy(rv
->id
, r
->id
, 7);
2145 rv
->metric
= r
->metric
;
2146 return (struct isis_item
*)rv
;
2149 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
2151 struct json_object
*json
, int indent
)
2153 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
2154 char sys_id
[ISO_SYSID_STRLEN
];
2156 snprintfrr(sys_id
, ISO_SYSID_STRLEN
, "%pPN", r
->id
);
2158 struct json_object
*old_json
;
2159 old_json
= json_object_new_object();
2160 json_object_object_add(json
, "old-reach-style", old_json
);
2161 json_object_string_add(old_json
, "is-reach", sys_id
);
2162 json_object_int_add(old_json
, "metric", r
->metric
);
2164 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
2168 static void free_item_oldstyle_reach(struct isis_item
*i
)
2170 XFREE(MTYPE_ISIS_TLV
, i
);
2173 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
2176 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
2178 if (STREAM_WRITEABLE(s
) < 11) {
2183 stream_putc(s
, r
->metric
);
2184 stream_putc(s
, 0x80); /* delay metric - unsupported */
2185 stream_putc(s
, 0x80); /* expense metric - unsupported */
2186 stream_putc(s
, 0x80); /* error metric - unsupported */
2187 stream_put(s
, r
->id
, 7);
2192 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
2193 struct stream
*s
, struct sbuf
*log
,
2194 void *dest
, int indent
)
2196 struct isis_tlvs
*tlvs
= dest
;
2198 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
2202 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
2207 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2208 rv
->metric
= stream_getc(s
);
2209 if ((rv
->metric
& 0x3f) != rv
->metric
) {
2210 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2213 stream_forward_getp(s
, 3); /* Skip other metrics */
2214 stream_get(rv
->id
, s
, 7);
2216 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2218 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
2222 /* Functions related to TLV 6 LAN Neighbors */
2223 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
2225 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
2226 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2228 memcpy(rv
->mac
, n
->mac
, 6);
2229 return (struct isis_item
*)rv
;
2232 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
2233 struct sbuf
*buf
, struct json_object
*json
,
2236 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
2237 char sys_id
[ISO_SYSID_STRLEN
];
2239 snprintfrr(sys_id
, ISO_SYSID_STRLEN
, "%pSY", n
->mac
);
2241 json_object_string_add(json
, "lan-neighbor", sys_id
);
2243 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", sys_id
);
2246 static void free_item_lan_neighbor(struct isis_item
*i
)
2248 XFREE(MTYPE_ISIS_TLV
, i
);
2251 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
2254 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
2256 if (STREAM_WRITEABLE(s
) < 6) {
2261 stream_put(s
, n
->mac
, 6);
2266 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
2267 struct stream
*s
, struct sbuf
*log
,
2268 void *dest
, int indent
)
2270 struct isis_tlvs
*tlvs
= dest
;
2272 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
2276 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
2281 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2282 stream_get(rv
->mac
, s
, 6);
2284 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2285 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
2289 /* Functions related to TLV 9 LSP Entry */
2290 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
2292 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
2293 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2295 rv
->rem_lifetime
= e
->rem_lifetime
;
2296 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
2297 rv
->seqno
= e
->seqno
;
2298 rv
->checksum
= e
->checksum
;
2300 return (struct isis_item
*)rv
;
2303 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
2304 struct sbuf
*buf
, struct json_object
*json
,
2307 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
2308 char sys_id
[ISO_SYSID_STRLEN
];
2310 snprintfrr(sys_id
, ISO_SYSID_STRLEN
, "%pLS", e
->id
);
2313 struct json_object
*lsp_json
;
2314 lsp_json
= json_object_new_object();
2315 json_object_object_add(json
, "lsp-entry", lsp_json
);
2316 json_object_string_add(lsp_json
, "id", sys_id
);
2317 snprintfrr(buf
,sizeof(buf
),"0x%08x",e
->seqno
);
2318 json_object_string_add(lsp_json
, "seq", buf
);
2319 snprintfrr(buf
,sizeof(buf
),"0x%04hx",e
->checksum
);
2320 json_object_string_add(lsp_json
, "chksum", buf
);
2321 json_object_int_add(lsp_json
, "lifetime", e
->checksum
);
2325 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
2326 sys_id
, e
->seqno
, e
->checksum
, e
->rem_lifetime
);
2329 static void free_item_lsp_entry(struct isis_item
*i
)
2331 XFREE(MTYPE_ISIS_TLV
, i
);
2334 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
2337 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
2339 if (STREAM_WRITEABLE(s
) < 16) {
2344 stream_putw(s
, e
->rem_lifetime
);
2345 stream_put(s
, e
->id
, 8);
2346 stream_putl(s
, e
->seqno
);
2347 stream_putw(s
, e
->checksum
);
2352 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
2353 struct sbuf
*log
, void *dest
, int indent
)
2355 struct isis_tlvs
*tlvs
= dest
;
2357 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
2361 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
2366 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2367 rv
->rem_lifetime
= stream_getw(s
);
2368 stream_get(rv
->id
, s
, 8);
2369 rv
->seqno
= stream_getl(s
);
2370 rv
->checksum
= stream_getw(s
);
2372 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2373 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
2377 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
2379 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
2381 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
2382 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2384 memcpy(rv
->id
, r
->id
, 7);
2385 rv
->metric
= r
->metric
;
2388 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
2390 return (struct isis_item
*)rv
;
2393 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
2395 struct json_object
*json
, int indent
)
2397 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
2398 char sys_id
[ISO_SYSID_STRLEN
];
2400 snprintfrr(sys_id
, ISO_SYSID_STRLEN
, "%pPN", r
->id
);
2402 struct json_object
*reach_json
;
2403 reach_json
= json_object_new_object();
2404 json_object_object_add(json
, "ext-reach", reach_json
);
2405 json_object_string_add(
2406 reach_json
, "mt-id",
2407 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
2408 json_object_string_add(reach_json
, "id", sys_id
);
2409 json_object_int_add(reach_json
, "metric", r
->metric
);
2410 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2411 json_object_string_add(reach_json
, "mt-name",
2412 isis_mtid2str(mtid
));
2415 format_item_ext_subtlvs(r
->subtlvs
, NULL
, json
,
2418 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
2419 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2421 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2422 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2423 sbuf_push(buf
, 0, "\n");
2426 format_item_ext_subtlvs(r
->subtlvs
, buf
, NULL
,
2431 static void free_item_extended_reach(struct isis_item
*i
)
2433 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
2435 if (item
->subtlvs
!= NULL
)
2436 free_item_ext_subtlvs(item
->subtlvs
);
2437 XFREE(MTYPE_ISIS_TLV
, item
);
2440 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
2443 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
2447 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
2448 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
2452 stream_put(s
, r
->id
, sizeof(r
->id
));
2453 stream_put3(s
, r
->metric
);
2454 len_pos
= stream_get_endp(s
);
2455 /* Real length will be adjust after adding subTLVs */
2458 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
2460 len
= stream_get_endp(s
) - len_pos
- 1;
2461 stream_putc_at(s
, len_pos
, len
);
2465 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
2466 struct stream
*s
, struct sbuf
*log
,
2467 void *dest
, int indent
)
2469 struct isis_tlvs
*tlvs
= dest
;
2470 struct isis_extended_reach
*rv
= NULL
;
2472 struct isis_item_list
*items
;
2474 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2475 items
= &tlvs
->extended_reach
;
2477 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
2480 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
2481 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2484 sbuf_push(log
, indent
,
2485 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
2490 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2491 stream_get(rv
->id
, s
, 7);
2492 rv
->metric
= stream_get3(s
);
2493 subtlv_len
= stream_getc(s
);
2495 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
2496 sbuf_push(log
, indent
,
2497 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
2498 subtlv_len
, len
- 11);
2502 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
2506 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
2512 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2514 append_item(items
, (struct isis_item
*)rv
);
2518 free_item_extended_reach((struct isis_item
*)rv
);
2523 /* Functions related to TLV 128 (Old-Style) IP Reach */
2524 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
2526 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2527 struct isis_oldstyle_ip_reach
*rv
=
2528 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2530 rv
->metric
= r
->metric
;
2531 rv
->prefix
= r
->prefix
;
2532 return (struct isis_item
*)rv
;
2535 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2537 struct json_object
*json
, int indent
)
2539 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2540 char prefixbuf
[PREFIX2STR_BUFFER
];
2543 struct json_object
*old_json
;
2544 old_json
= json_object_new_object();
2545 json_object_object_add(json
, "old-ip-reach-style", old_json
);
2546 json_object_string_add(old_json
, "prefix",
2547 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
2548 json_object_int_add(old_json
, "metric", r
->metric
);
2550 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
2551 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2555 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
2557 XFREE(MTYPE_ISIS_TLV
, i
);
2560 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
2563 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
2565 if (STREAM_WRITEABLE(s
) < 12) {
2570 stream_putc(s
, r
->metric
);
2571 stream_putc(s
, 0x80); /* delay metric - unsupported */
2572 stream_putc(s
, 0x80); /* expense metric - unsupported */
2573 stream_putc(s
, 0x80); /* error metric - unsupported */
2574 stream_put(s
, &r
->prefix
.prefix
, 4);
2576 struct in_addr mask
;
2577 masklen2ip(r
->prefix
.prefixlen
, &mask
);
2578 stream_put(s
, &mask
, sizeof(mask
));
2583 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
2584 struct stream
*s
, struct sbuf
*log
,
2585 void *dest
, int indent
)
2587 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
2591 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2596 struct isis_oldstyle_ip_reach
*rv
=
2597 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2598 rv
->metric
= stream_getc(s
);
2599 if ((rv
->metric
& 0x7f) != rv
->metric
) {
2600 sbuf_push(log
, indent
, "Metric has unplausible format\n");
2603 stream_forward_getp(s
, 3); /* Skip other metrics */
2604 rv
->prefix
.family
= AF_INET
;
2605 stream_get(&rv
->prefix
.prefix
, s
, 4);
2607 struct in_addr mask
;
2608 stream_get(&mask
, s
, 4);
2609 rv
->prefix
.prefixlen
= ip_masklen(mask
);
2611 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2613 append_item(dest
, (struct isis_item
*)rv
);
2618 /* Functions related to TLV 129 protocols supported */
2620 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
2621 struct isis_protocols_supported
*dest
)
2623 if (!src
->protocols
|| !src
->count
)
2625 dest
->count
= src
->count
;
2626 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
2627 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
2630 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2632 struct json_object
*json
, int indent
)
2634 if (!p
|| !p
->count
|| !p
->protocols
)
2638 struct json_object
*protocol_json
;
2641 protocol_json
= json_object_new_object();
2642 json_object_object_add(json
, "protocols-supported",
2644 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2645 snprintfrr(buf
, sizeof(buf
), "%d", i
);
2646 json_object_string_add(protocol_json
, buf
,
2647 nlpid2str(p
->protocols
[i
]));
2650 sbuf_push(buf
, indent
, "Protocols Supported: ");
2651 for (uint8_t i
= 0; i
< p
->count
; i
++) {
2652 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
2653 (i
+ 1 < p
->count
) ? ", " : "");
2655 sbuf_push(buf
, 0, "\n");
2659 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
2661 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
2664 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
2667 if (!p
|| !p
->count
|| !p
->protocols
)
2670 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
2673 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
2674 stream_putc(s
, p
->count
);
2675 stream_put(s
, p
->protocols
, p
->count
);
2679 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
2680 uint8_t tlv_type
, uint8_t tlv_len
,
2681 struct stream
*s
, struct sbuf
*log
,
2682 void *dest
, int indent
)
2684 struct isis_tlvs
*tlvs
= dest
;
2686 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
2688 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
2691 if (tlvs
->protocols_supported
.protocols
) {
2694 "WARNING: protocols supported TLV present multiple times.\n");
2695 stream_forward_getp(s
, tlv_len
);
2699 tlvs
->protocols_supported
.count
= tlv_len
;
2700 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
2701 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
2703 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
, NULL
,
2708 /* Functions related to TLV 132 IPv4 Interface addresses */
2709 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
2711 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2712 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2715 return (struct isis_item
*)rv
;
2718 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
2719 struct sbuf
*buf
, struct json_object
*json
,
2722 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2723 char addrbuf
[INET_ADDRSTRLEN
];
2725 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2727 json_object_string_add(json
, "ipv4", addrbuf
);
2729 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
2733 static void free_item_ipv4_address(struct isis_item
*i
)
2735 XFREE(MTYPE_ISIS_TLV
, i
);
2738 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
2741 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
2743 if (STREAM_WRITEABLE(s
) < 4) {
2748 stream_put(s
, &a
->addr
, 4);
2753 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
2754 struct stream
*s
, struct sbuf
*log
,
2755 void *dest
, int indent
)
2757 struct isis_tlvs
*tlvs
= dest
;
2759 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
2763 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2768 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2769 stream_get(&rv
->addr
, s
, 4);
2771 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2772 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
2777 /* Functions related to TLV 232 IPv6 Interface addresses */
2778 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
2780 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2781 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2784 return (struct isis_item
*)rv
;
2787 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2788 struct sbuf
*buf
, struct json_object
*json
,
2791 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2792 char addrbuf
[INET6_ADDRSTRLEN
];
2794 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2796 json_object_string_add(json
, "ipv6", addrbuf
);
2798 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
2801 static void free_item_ipv6_address(struct isis_item
*i
)
2803 XFREE(MTYPE_ISIS_TLV
, i
);
2806 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2809 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2811 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2812 *min_len
= IPV6_MAX_BYTELEN
;
2816 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2821 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
2822 struct stream
*s
, struct sbuf
*log
,
2823 void *dest
, int indent
)
2825 struct isis_tlvs
*tlvs
= dest
;
2827 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
2831 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2836 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2837 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2839 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
2840 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
2845 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2846 static struct isis_item
*copy_item_global_ipv6_address(struct isis_item
*i
)
2848 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2849 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2852 return (struct isis_item
*)rv
;
2855 static void format_item_global_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
2857 struct json_object
*json
,
2860 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2861 char addrbuf
[INET6_ADDRSTRLEN
];
2863 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
2865 json_object_string_add(json
, "global-ipv6", addrbuf
);
2867 sbuf_push(buf
, indent
, "Global IPv6 Interface Address: %s\n",
2871 static void free_item_global_ipv6_address(struct isis_item
*i
)
2873 XFREE(MTYPE_ISIS_TLV
, i
);
2876 static int pack_item_global_ipv6_address(struct isis_item
*i
, struct stream
*s
,
2879 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
2881 if (STREAM_WRITEABLE(s
) < IPV6_MAX_BYTELEN
) {
2882 *min_len
= IPV6_MAX_BYTELEN
;
2886 stream_put(s
, &a
->addr
, IPV6_MAX_BYTELEN
);
2891 static int unpack_item_global_ipv6_address(uint16_t mtid
, uint8_t len
,
2892 struct stream
*s
, struct sbuf
*log
,
2893 void *dest
, int indent
)
2895 struct isis_tlvs
*tlvs
= dest
;
2897 sbuf_push(log
, indent
, "Unpack Global IPv6 Interface address...\n");
2898 if (len
< IPV6_MAX_BYTELEN
) {
2901 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2906 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2907 stream_get(&rv
->addr
, s
, IPV6_MAX_BYTELEN
);
2909 format_item_global_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2911 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)rv
);
2915 /* Functions related to TLV 229 MT Router information */
2916 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
2918 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2919 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2921 rv
->overload
= info
->overload
;
2922 rv
->attached
= info
->attached
;
2923 rv
->mtid
= info
->mtid
;
2924 return (struct isis_item
*)rv
;
2927 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
2929 struct json_object
*json
, int indent
)
2931 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2934 struct json_object
*mt_json
;
2935 mt_json
= json_object_new_object();
2936 json_object_object_add(json
, "mt", mt_json
);
2937 json_object_int_add(mt_json
, "mtid", info
->mtid
);
2938 json_object_string_add(mt_json
, "overload", info
->overload
?"true":"false");
2939 json_object_string_add(mt_json
, "attached", info
->attached
?"true":"false");
2941 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
2942 isis_mtid2str_fake(info
->mtid
),
2943 info
->overload
? " Overload" : "",
2944 info
->attached
? " Attached" : "");
2947 static void free_item_mt_router_info(struct isis_item
*i
)
2949 XFREE(MTYPE_ISIS_TLV
, i
);
2952 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
2955 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
2957 if (STREAM_WRITEABLE(s
) < 2) {
2962 uint16_t entry
= info
->mtid
;
2965 entry
|= ISIS_MT_OL_MASK
;
2967 entry
|= ISIS_MT_AT_MASK
;
2969 stream_putw(s
, entry
);
2974 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
2975 struct stream
*s
, struct sbuf
*log
,
2976 void *dest
, int indent
)
2978 struct isis_tlvs
*tlvs
= dest
;
2980 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
2984 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2989 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2991 uint16_t entry
= stream_getw(s
);
2992 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
2993 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
2994 rv
->mtid
= entry
& ISIS_MT_MASK
;
2996 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
, NULL
,
2998 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
3002 /* Functions related to TLV 134 TE Router ID */
3004 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
3009 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3010 memcpy(rv
, id
, sizeof(*rv
));
3014 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
3015 struct json_object
*json
, int indent
)
3020 char addrbuf
[INET_ADDRSTRLEN
];
3021 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
3023 json_object_string_add(json
, "te-router-id", addrbuf
);
3025 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
3028 static void free_tlv_te_router_id(struct in_addr
*id
)
3030 XFREE(MTYPE_ISIS_TLV
, id
);
3033 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
3038 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
3041 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
3043 stream_put(s
, id
, 4);
3047 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
3048 uint8_t tlv_type
, uint8_t tlv_len
,
3049 struct stream
*s
, struct sbuf
*log
,
3050 void *dest
, int indent
)
3052 struct isis_tlvs
*tlvs
= dest
;
3054 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
3056 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
3060 if (tlvs
->te_router_id
) {
3061 sbuf_push(log
, indent
,
3062 "WARNING: TE Router ID present multiple times.\n");
3063 stream_forward_getp(s
, tlv_len
);
3067 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
3068 stream_get(tlvs
->te_router_id
, s
, 4);
3069 format_tlv_te_router_id(tlvs
->te_router_id
, log
, NULL
, indent
+ 2);
3074 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
3076 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
3078 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
3079 struct isis_extended_ip_reach
*rv
=
3080 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3082 rv
->metric
= r
->metric
;
3084 rv
->prefix
= r
->prefix
;
3085 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3087 return (struct isis_item
*)rv
;
3090 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
3092 struct json_object
*json
, int indent
)
3094 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
3095 char prefixbuf
[PREFIX2STR_BUFFER
];
3098 struct json_object
*ext_json
;
3099 ext_json
= json_object_new_object();
3100 json_object_object_add(json
, "ext-ip-reach", ext_json
);
3101 json_object_string_add(
3103 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT");
3104 json_object_string_add(
3106 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3107 json_object_int_add(json
, "ip-reach-metric", r
->metric
);
3108 json_object_string_add(json
, "down", r
->down
? "yes" : "");
3109 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3110 json_object_string_add(json
, "mt-name",
3111 isis_mtid2str(mtid
));
3113 struct json_object
*subtlv_json
;
3114 subtlv_json
= json_object_new_object();
3115 json_object_object_add(json
, "subtlvs", subtlv_json
);
3116 format_subtlvs(r
->subtlvs
, NULL
, subtlv_json
, 0);
3119 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
3120 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
3121 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3122 r
->metric
, r
->down
? " Down" : "");
3123 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3124 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3125 sbuf_push(buf
, 0, "\n");
3128 sbuf_push(buf
, indent
, " Subtlvs:\n");
3129 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3134 static void free_item_extended_ip_reach(struct isis_item
*i
)
3136 struct isis_extended_ip_reach
*item
=
3137 (struct isis_extended_ip_reach
*)i
;
3138 isis_free_subtlvs(item
->subtlvs
);
3139 XFREE(MTYPE_ISIS_TLV
, item
);
3142 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
3145 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
3148 if (STREAM_WRITEABLE(s
) < 5) {
3152 stream_putl(s
, r
->metric
);
3154 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
3155 control
|= r
->prefix
.prefixlen
;
3156 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
3158 stream_putc(s
, control
);
3160 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3161 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3164 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
3167 return pack_subtlvs(r
->subtlvs
, s
);
3171 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
3172 struct stream
*s
, struct sbuf
*log
,
3173 void *dest
, int indent
)
3175 struct isis_tlvs
*tlvs
= dest
;
3176 struct isis_extended_ip_reach
*rv
= NULL
;
3178 uint8_t control
, subtlv_len
;
3179 struct isis_item_list
*items
;
3181 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3182 items
= &tlvs
->extended_ip_reach
;
3184 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
3187 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
3188 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
3191 if (len
< consume
) {
3192 sbuf_push(log
, indent
,
3193 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
3198 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3200 rv
->metric
= stream_getl(s
);
3201 control
= stream_getc(s
);
3202 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
3203 rv
->prefix
.family
= AF_INET
;
3204 rv
->prefix
.prefixlen
= control
& 0x3f;
3205 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
3206 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
3207 rv
->prefix
.prefixlen
);
3211 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3212 if (len
< consume
) {
3213 sbuf_push(log
, indent
,
3214 "Expected %u bytes of prefix, but only %u bytes available.\n",
3215 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
3218 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3219 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
3220 apply_mask_ipv4(&rv
->prefix
);
3221 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
3222 sbuf_push(log
, indent
+ 2,
3223 "WARNING: Prefix had hostbits set.\n");
3224 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
,
3227 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
3229 if (len
< consume
) {
3230 sbuf_push(log
, indent
,
3231 "Expected 1 byte of subtlv len, but no more data present.\n");
3234 subtlv_len
= stream_getc(s
);
3237 sbuf_push(log
, indent
+ 2,
3238 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
3240 consume
+= subtlv_len
;
3241 if (len
< consume
) {
3242 sbuf_push(log
, indent
,
3243 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3245 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3249 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
3250 bool unpacked_known_tlvs
= false;
3252 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
3253 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3256 if (!unpacked_known_tlvs
) {
3257 isis_free_subtlvs(rv
->subtlvs
);
3262 append_item(items
, (struct isis_item
*)rv
);
3266 free_item_extended_ip_reach((struct isis_item
*)rv
);
3270 /* Functions related to TLV 137 Dynamic Hostname */
3272 static char *copy_tlv_dynamic_hostname(const char *hostname
)
3277 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
3280 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
3281 struct json_object
*json
, int indent
)
3287 json_object_string_add(json
, "hostname", hostname
);
3289 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
3292 static void free_tlv_dynamic_hostname(char *hostname
)
3294 XFREE(MTYPE_ISIS_TLV
, hostname
);
3297 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
3302 uint8_t name_len
= strlen(hostname
);
3304 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
3307 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
3308 stream_putc(s
, name_len
);
3309 stream_put(s
, hostname
, name_len
);
3313 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
3314 uint8_t tlv_type
, uint8_t tlv_len
,
3315 struct stream
*s
, struct sbuf
*log
,
3316 void *dest
, int indent
)
3318 struct isis_tlvs
*tlvs
= dest
;
3320 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
3322 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
3326 if (tlvs
->hostname
) {
3327 sbuf_push(log
, indent
,
3328 "WARNING: Hostname present multiple times.\n");
3329 stream_forward_getp(s
, tlv_len
);
3333 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
3334 stream_get(tlvs
->hostname
, s
, tlv_len
);
3335 tlvs
->hostname
[tlv_len
] = '\0';
3338 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
3339 if ((unsigned char)tlvs
->hostname
[i
] > 127
3340 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
3342 tlvs
->hostname
[i
] = '?';
3348 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
3354 /* Functions related to TLV 140 IPv6 TE Router ID */
3356 static struct in6_addr
*copy_tlv_te_router_id_ipv6(const struct in6_addr
*id
)
3361 struct in6_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3362 memcpy(rv
, id
, sizeof(*rv
));
3366 static void format_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
3368 struct json_object
*json
, int indent
)
3373 char addrbuf
[INET6_ADDRSTRLEN
];
3374 inet_ntop(AF_INET6
, id
, addrbuf
, sizeof(addrbuf
));
3376 json_object_string_add(json
, "ipv6-te-router-id", addrbuf
);
3378 sbuf_push(buf
, indent
, "IPv6 TE Router ID: %s\n", addrbuf
);
3381 static void free_tlv_te_router_id_ipv6(struct in6_addr
*id
)
3383 XFREE(MTYPE_ISIS_TLV
, id
);
3386 static int pack_tlv_te_router_id_ipv6(const struct in6_addr
*id
,
3392 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
3395 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID_IPV6
);
3396 stream_putc(s
, IPV6_MAX_BYTELEN
);
3397 stream_put(s
, id
, IPV6_MAX_BYTELEN
);
3401 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context
,
3402 uint8_t tlv_type
, uint8_t tlv_len
,
3403 struct stream
*s
, struct sbuf
*log
,
3404 void *dest
, int indent
)
3406 struct isis_tlvs
*tlvs
= dest
;
3408 sbuf_push(log
, indent
, "Unpacking IPv6 TE Router ID TLV...\n");
3409 if (tlv_len
!= IPV6_MAX_BYTELEN
) {
3410 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
3414 if (tlvs
->te_router_id_ipv6
) {
3417 "WARNING: IPv6 TE Router ID present multiple times.\n");
3418 stream_forward_getp(s
, tlv_len
);
3422 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, IPV6_MAX_BYTELEN
);
3423 stream_get(tlvs
->te_router_id_ipv6
, s
, IPV6_MAX_BYTELEN
);
3424 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, log
, NULL
, indent
+ 2);
3429 /* Functions related to TLV 150 Spine-Leaf-Extension */
3431 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
3432 const struct isis_spine_leaf
*spine_leaf
)
3437 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3438 memcpy(rv
, spine_leaf
, sizeof(*rv
));
3443 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
3444 struct sbuf
*buf
, struct json_object
*json
,
3453 struct json_object
*spine_json
;
3454 spine_json
= json_object_new_object();
3455 json_object_object_add(json
, "spine-leaf-extension",
3457 if (spine_leaf
->has_tier
) {
3458 snprintfrr(aux_buf
, sizeof(aux_buf
), "%hhu",
3460 json_object_string_add(
3462 (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
)
3466 json_object_string_add(spine_json
, "flag-leaf",
3467 spine_leaf
->is_leaf
? "yes" : "");
3468 json_object_string_add(spine_json
, "flag-spine",
3469 spine_leaf
->is_spine
? "yes" : "");
3470 json_object_string_add(spine_json
, "flag-backup",
3471 spine_leaf
->is_backup
? "yes" : "");
3473 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
3474 if (spine_leaf
->has_tier
) {
3475 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
3476 sbuf_push(buf
, indent
, " Tier: undefined\n");
3478 sbuf_push(buf
, indent
, " Tier: %hhu\n",
3483 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
3484 spine_leaf
->is_leaf
? " LEAF" : "",
3485 spine_leaf
->is_spine
? " SPINE" : "",
3486 spine_leaf
->is_backup
? " BACKUP" : "");
3490 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
3492 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
3495 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
3496 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
3497 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
3498 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
3500 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
3506 uint8_t tlv_len
= 2;
3508 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3511 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
3512 stream_putc(s
, tlv_len
);
3514 uint16_t spine_leaf_flags
= 0;
3516 if (spine_leaf
->has_tier
) {
3517 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
3518 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
3521 if (spine_leaf
->is_leaf
)
3522 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
3524 if (spine_leaf
->is_spine
)
3525 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
3527 if (spine_leaf
->is_backup
)
3528 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
3530 stream_putw(s
, spine_leaf_flags
);
3535 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
3536 uint8_t tlv_type
, uint8_t tlv_len
,
3537 struct stream
*s
, struct sbuf
*log
,
3538 void *dest
, int indent
)
3540 struct isis_tlvs
*tlvs
= dest
;
3542 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
3544 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3545 stream_forward_getp(s
, tlv_len
);
3549 if (tlvs
->spine_leaf
) {
3550 sbuf_push(log
, indent
,
3551 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3552 stream_forward_getp(s
, tlv_len
);
3556 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3558 uint16_t spine_leaf_flags
= stream_getw(s
);
3560 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
3561 tlvs
->spine_leaf
->has_tier
= true;
3562 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
3565 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
3566 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
3567 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
3569 stream_forward_getp(s
, tlv_len
- 2);
3573 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3575 const char *isis_threeway_state_name(enum isis_threeway_state state
)
3578 case ISIS_THREEWAY_DOWN
:
3580 case ISIS_THREEWAY_INITIALIZING
:
3581 return "Initializing";
3582 case ISIS_THREEWAY_UP
:
3589 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
3590 const struct isis_threeway_adj
*threeway_adj
)
3595 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3596 memcpy(rv
, threeway_adj
, sizeof(*rv
));
3602 format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3603 struct sbuf
*buf
, struct json_object
*json
, int indent
)
3605 char sys_id
[ISO_SYSID_STRLEN
];
3610 snprintfrr(sys_id
, ISO_SYSID_STRLEN
, "%pSY", threeway_adj
->neighbor_id
);
3612 struct json_object
*three_json
;
3613 three_json
= json_object_new_object();
3614 json_object_object_add(json
, "p2p-three-way-adj", three_json
);
3615 json_object_string_add(
3616 three_json
, "state-name",
3617 isis_threeway_state_name(threeway_adj
->state
));
3618 json_object_int_add(three_json
, "state", threeway_adj
->state
);
3619 json_object_int_add(three_json
, "ext-local-circuit-id",
3620 threeway_adj
->local_circuit_id
);
3621 if (!threeway_adj
->neighbor_set
)
3623 json_object_string_add(three_json
, "neigh-system-id", sys_id
);
3624 json_object_int_add(three_json
, "neigh-ext-circuit-id",
3625 threeway_adj
->neighbor_circuit_id
);
3627 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
3628 sbuf_push(buf
, indent
, " State: %s (%d)\n",
3629 isis_threeway_state_name(threeway_adj
->state
),
3630 threeway_adj
->state
);
3631 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
3632 threeway_adj
->local_circuit_id
);
3633 if (!threeway_adj
->neighbor_set
)
3636 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n", sys_id
);
3637 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
3638 threeway_adj
->neighbor_circuit_id
);
3642 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
3644 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
3647 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
3653 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
3655 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
3658 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
3659 stream_putc(s
, tlv_len
);
3660 stream_putc(s
, threeway_adj
->state
);
3661 stream_putl(s
, threeway_adj
->local_circuit_id
);
3663 if (threeway_adj
->neighbor_set
) {
3664 stream_put(s
, threeway_adj
->neighbor_id
, 6);
3665 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
3671 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
3672 uint8_t tlv_type
, uint8_t tlv_len
,
3673 struct stream
*s
, struct sbuf
*log
,
3674 void *dest
, int indent
)
3676 struct isis_tlvs
*tlvs
= dest
;
3678 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
3679 if (tlv_len
!= 5 && tlv_len
!= 15) {
3680 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
3681 stream_forward_getp(s
, tlv_len
);
3685 if (tlvs
->threeway_adj
) {
3686 sbuf_push(log
, indent
,
3687 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3688 stream_forward_getp(s
, tlv_len
);
3692 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3694 tlvs
->threeway_adj
->state
= stream_getc(s
);
3695 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
3697 if (tlv_len
== 15) {
3698 tlvs
->threeway_adj
->neighbor_set
= true;
3699 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
3700 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
3706 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3707 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
3709 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3710 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3712 rv
->metric
= r
->metric
;
3714 rv
->external
= r
->external
;
3715 rv
->prefix
= r
->prefix
;
3716 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
3718 return (struct isis_item
*)rv
;
3721 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
3722 struct sbuf
*buf
, struct json_object
*json
,
3725 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3726 char prefixbuf
[PREFIX2STR_BUFFER
];
3729 struct json_object
*reach_json
;
3730 reach_json
= json_object_new_object();
3731 json_object_object_add(json
, "ipv6-reach", reach_json
);
3732 json_object_string_add(reach_json
, "mt-id",
3733 (mtid
== ISIS_MT_IPV4_UNICAST
) ? ""
3735 json_object_string_add(
3736 reach_json
, "prefix",
3737 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)));
3738 json_object_int_add(reach_json
, "metric", r
->metric
);
3739 json_object_string_add(reach_json
, "down",
3740 r
->down
? "yes" : "");
3741 json_object_string_add(reach_json
, "external",
3742 r
->external
? "yes" : "");
3743 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3744 json_object_string_add(reach_json
, "mt-name",
3745 isis_mtid2str(mtid
));
3747 struct json_object
*subtlvs_json
;
3748 subtlvs_json
= json_object_new_object();
3749 json_object_object_add(json
, "subtlvs", subtlvs_json
);
3750 format_subtlvs(r
->subtlvs
, NULL
, subtlvs_json
, 0);
3753 sbuf_push(buf
, indent
,
3754 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3755 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
3756 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
3757 r
->metric
, r
->down
? " Down" : "",
3758 r
->external
? " External" : "");
3759 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
3760 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
3761 sbuf_push(buf
, 0, "\n");
3764 sbuf_push(buf
, indent
, " Subtlvs:\n");
3765 format_subtlvs(r
->subtlvs
, buf
, NULL
, indent
+ 4);
3770 static void free_item_ipv6_reach(struct isis_item
*i
)
3772 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
3774 isis_free_subtlvs(item
->subtlvs
);
3775 XFREE(MTYPE_ISIS_TLV
, item
);
3778 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
3781 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
3784 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
3785 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
3788 stream_putl(s
, r
->metric
);
3790 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
3791 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
3792 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
3794 stream_putc(s
, control
);
3795 stream_putc(s
, r
->prefix
.prefixlen
);
3797 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
3800 return pack_subtlvs(r
->subtlvs
, s
);
3805 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3806 struct sbuf
*log
, void *dest
, int indent
)
3808 struct isis_tlvs
*tlvs
= dest
;
3809 struct isis_ipv6_reach
*rv
= NULL
;
3811 uint8_t control
, subtlv_len
;
3812 struct isis_item_list
*items
;
3814 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
3815 items
= &tlvs
->ipv6_reach
;
3817 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3820 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
3821 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
3823 if (len
< consume
) {
3824 sbuf_push(log
, indent
,
3825 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3830 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3832 rv
->metric
= stream_getl(s
);
3833 control
= stream_getc(s
);
3834 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
3835 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
3837 rv
->prefix
.family
= AF_INET6
;
3838 rv
->prefix
.prefixlen
= stream_getc(s
);
3839 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
3840 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
3841 rv
->prefix
.prefixlen
);
3845 consume
+= PSIZE(rv
->prefix
.prefixlen
);
3846 if (len
< consume
) {
3847 sbuf_push(log
, indent
,
3848 "Expected %u bytes of prefix, but only %u bytes available.\n",
3849 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
3852 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
3853 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
3855 apply_mask_ipv6(&rv
->prefix
);
3856 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
3857 sbuf_push(log
, indent
+ 2,
3858 "WARNING: Prefix had hostbits set.\n");
3859 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
3861 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
3863 if (len
< consume
) {
3864 sbuf_push(log
, indent
,
3865 "Expected 1 byte of subtlv len, but no more data persent.\n");
3868 subtlv_len
= stream_getc(s
);
3871 sbuf_push(log
, indent
+ 2,
3872 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3874 consume
+= subtlv_len
;
3875 if (len
< consume
) {
3876 sbuf_push(log
, indent
,
3877 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3879 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
3883 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3884 bool unpacked_known_tlvs
= false;
3886 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
3887 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
3890 if (!unpacked_known_tlvs
) {
3891 isis_free_subtlvs(rv
->subtlvs
);
3896 append_item(items
, (struct isis_item
*)rv
);
3900 free_item_ipv6_reach((struct isis_item
*)rv
);
3904 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3905 static struct isis_router_cap
*copy_tlv_router_cap(
3906 const struct isis_router_cap
*router_cap
)
3908 struct isis_router_cap
*rv
;
3913 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3915 memcpy(rv
, router_cap
, sizeof(*rv
));
3918 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
3919 struct isis_router_cap_fad
*sc_fad
;
3920 struct isis_router_cap_fad
*rv_fad
;
3922 sc_fad
= router_cap
->fads
[i
];
3925 rv_fad
= XMALLOC(MTYPE_ISIS_TLV
,
3926 sizeof(struct isis_router_cap_fad
));
3928 rv_fad
->fad
.admin_group_exclude_any
.bitmap
.data
= NULL
;
3929 rv_fad
->fad
.admin_group_include_any
.bitmap
.data
= NULL
;
3930 rv_fad
->fad
.admin_group_include_all
.bitmap
.data
= NULL
;
3932 assert(bf_is_inited(
3933 sc_fad
->fad
.admin_group_exclude_any
.bitmap
));
3934 assert(bf_is_inited(
3935 sc_fad
->fad
.admin_group_include_any
.bitmap
));
3936 assert(bf_is_inited(
3937 sc_fad
->fad
.admin_group_include_all
.bitmap
));
3939 admin_group_copy(&rv_fad
->fad
.admin_group_exclude_any
,
3940 &sc_fad
->fad
.admin_group_exclude_any
);
3941 admin_group_copy(&rv_fad
->fad
.admin_group_include_any
,
3942 &sc_fad
->fad
.admin_group_include_any
);
3943 admin_group_copy(&rv_fad
->fad
.admin_group_include_all
,
3944 &sc_fad
->fad
.admin_group_include_all
);
3946 rv
->fads
[i
] = rv_fad
;
3948 #endif /* ifndef FABRICD */
3953 static void format_tlv_router_cap_json(const struct isis_router_cap
*router_cap
,
3954 struct json_object
*json
)
3956 char addrbuf
[INET_ADDRSTRLEN
];
3961 /* Router ID and Flags */
3962 struct json_object
*cap_json
;
3963 cap_json
= json_object_new_object();
3964 json_object_object_add(json
, "router-capability", cap_json
);
3965 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
3966 json_object_string_add(cap_json
, "id", addrbuf
);
3967 json_object_string_add(
3969 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? "1" : "0");
3970 json_object_string_add(
3972 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? "1" : "0");
3974 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3975 if (router_cap
->srgb
.range_size
!= 0) {
3976 struct json_object
*gb_json
;
3977 gb_json
= json_object_new_object();
3978 json_object_object_add(json
, "segment-routing-gb", gb_json
);
3979 json_object_string_add(gb_json
, "ipv4",
3980 IS_SR_IPV4(&router_cap
->srgb
) ? "1"
3982 json_object_string_add(gb_json
, "ipv6",
3983 IS_SR_IPV6(&router_cap
->srgb
) ? "1"
3985 json_object_int_add(gb_json
, "global-block-base",
3986 router_cap
->srgb
.lower_bound
);
3987 json_object_int_add(gb_json
, "global-block-range",
3988 router_cap
->srgb
.range_size
);
3991 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3992 if (router_cap
->srlb
.range_size
!= 0) {
3993 struct json_object
*lb_json
;
3994 lb_json
= json_object_new_object();
3995 json_object_object_add(json
, "segment-routing-lb", lb_json
);
3996 json_object_int_add(lb_json
, "global-block-base",
3997 router_cap
->srlb
.lower_bound
);
3998 json_object_int_add(lb_json
, "global-block-range",
3999 router_cap
->srlb
.range_size
);
4002 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
4003 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
4005 struct json_object
*alg_json
;
4006 alg_json
= json_object_new_object();
4007 json_object_object_add(json
, "segment-routing-algorithm",
4009 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
4010 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
) {
4011 snprintfrr(buf
, sizeof(buf
), "%d", i
);
4012 json_object_string_add(alg_json
, buf
,
4013 router_cap
->algo
[i
] == 0
4019 /* Segment Routing Node MSD as per RFC8491 section #2 */
4020 if (router_cap
->msd
!= 0)
4021 json_object_int_add(json
, "msd", router_cap
->msd
);
4024 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
4025 struct sbuf
*buf
, int indent
)
4027 char addrbuf
[INET_ADDRSTRLEN
];
4032 /* Router ID and Flags */
4033 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
4034 sbuf_push(buf
, indent
, "Router Capability:");
4035 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
4036 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
4037 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
4039 /* Segment Routing Global Block as per RFC8667 section #3.1 */
4040 if (router_cap
->srgb
.range_size
!= 0)
4043 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
4044 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
4045 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
4046 router_cap
->srgb
.lower_bound
,
4047 router_cap
->srgb
.range_size
);
4049 /* Segment Routing Local Block as per RFC8667 section #3.3 */
4050 if (router_cap
->srlb
.range_size
!= 0)
4051 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
4052 router_cap
->srlb
.lower_bound
,
4053 router_cap
->srlb
.range_size
);
4055 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
4056 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
4057 sbuf_push(buf
, indent
, " SR Algorithm:\n");
4058 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
4059 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
4060 sbuf_push(buf
, indent
, " %u: %s\n", i
,
4061 sr_algorithm_string(
4062 router_cap
->algo
[i
]));
4065 /* Segment Routing Node MSD as per RFC8491 section #2 */
4066 if (router_cap
->msd
!= 0)
4067 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
4072 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
4073 char admin_group_buf
[ADMIN_GROUP_PRINT_MAX_SIZE
];
4075 struct admin_group
*admin_group
;
4076 struct isis_router_cap_fad
*fad
;
4078 fad
= router_cap
->fads
[i
];
4082 sbuf_push(buf
, indent
, " Flex-Algo Definition: %d\n",
4083 fad
->fad
.algorithm
);
4084 sbuf_push(buf
, indent
, " Metric-Type: %d\n",
4085 fad
->fad
.metric_type
);
4086 sbuf_push(buf
, indent
, " Calc-Type: %d\n",
4087 fad
->fad
.calc_type
);
4088 sbuf_push(buf
, indent
, " Priority: %d\n", fad
->fad
.priority
);
4090 indent2
= indent
+ strlen(" Exclude-Any: ");
4091 admin_group
= &fad
->fad
.admin_group_exclude_any
;
4092 sbuf_push(buf
, indent
, " Exclude-Any: ");
4093 sbuf_push(buf
, 0, "%s\n",
4094 admin_group_string(admin_group_buf
,
4095 ADMIN_GROUP_PRINT_MAX_SIZE
,
4096 indent2
, admin_group
));
4098 indent2
= indent
+ strlen(" Include-Any: ");
4099 admin_group
= &fad
->fad
.admin_group_include_any
;
4100 sbuf_push(buf
, indent
, " Include-Any: ");
4101 sbuf_push(buf
, 0, "%s\n",
4102 admin_group_string(admin_group_buf
,
4103 ADMIN_GROUP_PRINT_MAX_SIZE
,
4104 indent2
, admin_group
));
4106 indent2
= indent
+ strlen(" Include-All: ");
4107 admin_group
= &fad
->fad
.admin_group_include_all
;
4108 sbuf_push(buf
, indent
, " Include-All: ");
4109 sbuf_push(buf
, 0, "%s\n",
4110 admin_group_string(admin_group_buf
,
4111 ADMIN_GROUP_PRINT_MAX_SIZE
,
4112 indent2
, admin_group
));
4114 sbuf_push(buf
, indent
, " M-Flag: %c\n",
4115 CHECK_FLAG(fad
->fad
.flags
, FAD_FLAG_M
) ? '1' : '0');
4117 if (fad
->fad
.flags
!= 0 && fad
->fad
.flags
!= FAD_FLAG_M
)
4118 sbuf_push(buf
, indent
, " Flags: 0x%x\n",
4120 if (fad
->fad
.exclude_srlg
)
4121 sbuf_push(buf
, indent
, " Exclude SRLG: Enabled\n");
4122 if (fad
->fad
.unsupported_subtlv
)
4123 sbuf_push(buf
, indent
,
4124 " Got an unsupported sub-TLV: Yes\n");
4126 #endif /* ifndef FABRICD */
4129 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
4135 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
4136 struct isis_router_cap_fad
*fad
;
4138 fad
= router_cap
->fads
[i
];
4141 admin_group_term(&fad
->fad
.admin_group_exclude_any
);
4142 admin_group_term(&fad
->fad
.admin_group_include_any
);
4143 admin_group_term(&fad
->fad
.admin_group_include_all
);
4144 XFREE(MTYPE_ISIS_TLV
, fad
);
4146 #endif /* ifndef FABRICD */
4148 XFREE(MTYPE_ISIS_TLV
, router_cap
);
4153 isis_router_cap_fad_sub_tlv_len(const struct isis_router_cap_fad
*fad
)
4155 size_t sz
= ISIS_SUBTLV_FAD_MIN_SIZE
;
4156 uint32_t admin_group_length
;
4158 admin_group_length
=
4159 admin_group_nb_words(&fad
->fad
.admin_group_exclude_any
);
4160 if (admin_group_length
)
4161 sz
+= sizeof(uint32_t) * admin_group_length
+ 2;
4163 admin_group_length
=
4164 admin_group_nb_words(&fad
->fad
.admin_group_include_any
);
4165 if (admin_group_length
)
4166 sz
+= sizeof(uint32_t) * admin_group_length
+ 2;
4168 admin_group_length
=
4169 admin_group_nb_words(&fad
->fad
.admin_group_include_all
);
4170 if (admin_group_length
)
4171 sz
+= sizeof(uint32_t) * admin_group_length
+ 2;
4173 if (fad
->fad
.flags
!= 0)
4174 sz
+= ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE
+ 2;
4176 /* TODO: add exclude SRLG sub-sub-TLV length when supported */
4180 #endif /* ifndef FABRICD */
4182 static size_t isis_router_cap_tlv_size(const struct isis_router_cap
*router_cap
)
4184 size_t sz
= 2 + ISIS_ROUTER_CAP_SIZE
;
4187 #endif /* ifndef FABRICD */
4190 if ((router_cap
->srgb
.range_size
!= 0) &&
4191 (router_cap
->srgb
.lower_bound
!= 0)) {
4192 sz
+= 2 + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
;
4193 sz
+= 2 + ISIS_SUBTLV_SID_LABEL_SIZE
;
4195 nb_algo
= isis_tlvs_sr_algo_count(router_cap
);
4199 if ((router_cap
->srlb
.range_size
!= 0) &&
4200 (router_cap
->srlb
.lower_bound
!= 0)) {
4201 sz
+= 2 + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
;
4202 sz
+= 2 + ISIS_SUBTLV_SID_LABEL_SIZE
;
4205 if (router_cap
->msd
!= 0)
4206 sz
+= 2 + ISIS_SUBTLV_NODE_MSD_SIZE
;
4210 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
4211 if (!router_cap
->fads
[i
])
4214 isis_router_cap_fad_sub_tlv_len(router_cap
->fads
[i
]);
4215 if (((sz
+ fad_sz
) % 256) < (sz
% 256))
4216 sz
+= 2 + ISIS_ROUTER_CAP_SIZE
+ fad_sz
;
4220 #endif /* ifndef FABRICD */
4225 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
4228 size_t tlv_len
, len_pos
;
4234 if (STREAM_WRITEABLE(s
) < isis_router_cap_tlv_size(router_cap
))
4237 /* Add Router Capability TLV 242 with Router ID and Flags */
4238 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
4239 len_pos
= stream_get_endp(s
);
4240 stream_putc(s
, 0); /* Real length will be adjusted later */
4241 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
4242 stream_putc(s
, router_cap
->flags
);
4244 /* Add SRGB if set as per RFC8667 section #3.1 */
4245 if ((router_cap
->srgb
.range_size
!= 0)
4246 && (router_cap
->srgb
.lower_bound
!= 0)) {
4247 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
4248 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
4249 stream_putc(s
, router_cap
->srgb
.flags
);
4250 stream_put3(s
, router_cap
->srgb
.range_size
);
4251 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
4252 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
4253 stream_put3(s
, router_cap
->srgb
.lower_bound
);
4255 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
4256 nb_algo
= isis_tlvs_sr_algo_count(router_cap
);
4258 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
4259 stream_putc(s
, nb_algo
);
4260 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
4261 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
4262 stream_putc(s
, router_cap
->algo
[i
]);
4265 /* Local Block if defined as per RFC8667 section #3.3 */
4266 if ((router_cap
->srlb
.range_size
!= 0)
4267 && (router_cap
->srlb
.lower_bound
!= 0)) {
4268 stream_putc(s
, ISIS_SUBTLV_SRLB
);
4269 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
4270 /* No Flags are defined for SRLB */
4272 stream_put3(s
, router_cap
->srlb
.range_size
);
4273 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
4274 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
4275 stream_put3(s
, router_cap
->srlb
.lower_bound
);
4278 /* And finish with MSD if set as per RFC8491 section #2 */
4279 if (router_cap
->msd
!= 0) {
4280 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
4281 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
4282 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
4283 stream_putc(s
, router_cap
->msd
);
4288 /* Flex Algo Definitions */
4289 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
4290 struct isis_router_cap_fad
*fad
;
4292 struct admin_group
*ag
;
4293 uint32_t admin_group_length
;
4295 fad
= router_cap
->fads
[i
];
4299 subtlv_len
= isis_router_cap_fad_sub_tlv_len(fad
);
4301 if ((stream_get_endp(s
) - len_pos
- 1) > 250) {
4302 /* Adjust TLV length which depends on subTLVs presence
4304 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
4305 stream_putc_at(s
, len_pos
, tlv_len
);
4307 /* Add Router Capability TLV 242 with Router ID and
4310 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
4311 /* Real length will be adjusted later */
4312 len_pos
= stream_get_endp(s
);
4314 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
4315 stream_putc(s
, router_cap
->flags
);
4318 stream_putc(s
, ISIS_SUBTLV_FAD
);
4319 stream_putc(s
, subtlv_len
); /* length will be filled later */
4321 stream_putc(s
, fad
->fad
.algorithm
);
4322 stream_putc(s
, fad
->fad
.metric_type
);
4323 stream_putc(s
, fad
->fad
.calc_type
);
4324 stream_putc(s
, fad
->fad
.priority
);
4326 ag
= &fad
->fad
.admin_group_exclude_any
;
4327 admin_group_length
= admin_group_nb_words(ag
);
4328 if (admin_group_length
) {
4329 stream_putc(s
, ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG
);
4330 stream_putc(s
, sizeof(uint32_t) * admin_group_length
);
4331 for (size_t i
= 0; i
< admin_group_length
; i
++)
4332 stream_putl(s
, admin_group_get_offset(ag
, i
));
4335 ag
= &fad
->fad
.admin_group_include_any
;
4336 admin_group_length
= admin_group_nb_words(ag
);
4337 if (admin_group_length
) {
4338 stream_putc(s
, ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG
);
4339 stream_putc(s
, sizeof(uint32_t) * admin_group_length
);
4340 for (size_t i
= 0; i
< admin_group_length
; i
++)
4341 stream_putl(s
, admin_group_get_offset(ag
, i
));
4344 ag
= &fad
->fad
.admin_group_include_all
;
4345 admin_group_length
= admin_group_nb_words(ag
);
4346 if (admin_group_length
) {
4347 stream_putc(s
, ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG
);
4348 stream_putc(s
, sizeof(uint32_t) * admin_group_length
);
4349 for (size_t i
= 0; i
< admin_group_length
; i
++)
4350 stream_putl(s
, admin_group_get_offset(ag
, i
));
4353 if (fad
->fad
.flags
!= 0) {
4354 stream_putc(s
, ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS
);
4355 stream_putc(s
, ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE
);
4356 stream_putc(s
, fad
->fad
.flags
);
4359 #endif /* ifndef FABRICD */
4361 /* Adjust TLV length which depends on subTLVs presence */
4362 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
4363 stream_putc_at(s
, len_pos
, tlv_len
);
4368 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
4369 uint8_t tlv_type
, uint8_t tlv_len
,
4370 struct stream
*s
, struct sbuf
*log
, void *dest
,
4373 struct isis_tlvs
*tlvs
= dest
;
4374 struct isis_router_cap
*rcap
;
4380 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
4381 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
4382 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
4383 stream_forward_getp(s
, tlv_len
);
4387 if (tlvs
->router_cap
)
4388 /* Multiple Router Capability found */
4389 rcap
= tlvs
->router_cap
;
4391 /* Allocate router cap structure and initialize SR Algorithms */
4392 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
4393 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
4394 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
4397 /* Get Router ID and Flags */
4398 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
4399 rcap
->flags
= stream_getc(s
);
4401 /* Parse remaining part of the TLV if present */
4402 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
4403 while (subtlv_len
> 2) {
4405 struct isis_router_cap_fad
*fad
;
4406 uint8_t subsubtlvs_len
;
4407 #endif /* ifndef FABRICD */
4410 type
= stream_getc(s
);
4411 length
= stream_getc(s
);
4413 if (length
> STREAM_READABLE(s
) || length
> subtlv_len
- 2) {
4416 "WARNING: Router Capability subTLV length too large compared to expected size\n");
4417 stream_forward_getp(s
, STREAM_READABLE(s
));
4418 XFREE(MTYPE_ISIS_TLV
, rcap
);
4423 case ISIS_SUBTLV_SID_LABEL_RANGE
:
4424 /* Check that SRGB is correctly formated */
4425 if (length
< SUBTLV_RANGE_LABEL_SIZE
4426 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
4427 stream_forward_getp(s
, length
);
4430 /* Only one SRGB is supported. Skip subsequent one */
4431 if (rcap
->srgb
.range_size
!= 0) {
4432 stream_forward_getp(s
, length
);
4435 rcap
->srgb
.flags
= stream_getc(s
);
4436 rcap
->srgb
.range_size
= stream_get3(s
);
4437 /* Skip Type and get Length of SID Label */
4439 size
= stream_getc(s
);
4441 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
4442 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
4443 stream_forward_getp(s
, length
- 6);
4447 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
4448 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
4449 stream_forward_getp(s
, length
- 6);
4453 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
4454 rcap
->srgb
.lower_bound
= stream_get3(s
);
4455 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
4456 rcap
->srgb
.lower_bound
= stream_getl(s
);
4458 stream_forward_getp(s
, length
- 6);
4462 /* SRGB sanity checks. */
4463 if (rcap
->srgb
.range_size
== 0
4464 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
4465 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
4466 > MPLS_LABEL_UNRESERVED_MAX
)) {
4467 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
4468 rcap
->srgb
.lower_bound
= 0;
4469 rcap
->srgb
.range_size
= 0;
4471 /* Only one range is supported. Skip subsequent one */
4472 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
4474 stream_forward_getp(s
, size
);
4477 case ISIS_SUBTLV_ALGORITHM
:
4481 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
4482 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
4484 for (int i
= 0; i
< length
; i
++) {
4487 algo
= stream_getc(s
);
4488 rcap
->algo
[algo
] = algo
;
4491 case ISIS_SUBTLV_SRLB
:
4492 /* Check that SRLB is correctly formated */
4493 if (length
< SUBTLV_RANGE_LABEL_SIZE
4494 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
4495 stream_forward_getp(s
, length
);
4498 /* RFC 8667 section #3.3: Only one SRLB is authorized */
4499 if (rcap
->srlb
.range_size
!= 0) {
4500 stream_forward_getp(s
, length
);
4503 /* Ignore Flags which are not defined */
4505 rcap
->srlb
.range_size
= stream_get3(s
);
4506 /* Skip Type and get Length of SID Label */
4508 size
= stream_getc(s
);
4510 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
4511 && length
!= SUBTLV_RANGE_LABEL_SIZE
) {
4512 stream_forward_getp(s
, length
- 6);
4516 if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
4517 && length
!= SUBTLV_RANGE_INDEX_SIZE
) {
4518 stream_forward_getp(s
, length
- 6);
4522 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
) {
4523 rcap
->srlb
.lower_bound
= stream_get3(s
);
4524 } else if (size
== ISIS_SUBTLV_SID_INDEX_SIZE
) {
4525 rcap
->srlb
.lower_bound
= stream_getl(s
);
4527 stream_forward_getp(s
, length
- 6);
4531 /* SRLB sanity checks. */
4532 if (rcap
->srlb
.range_size
== 0
4533 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
4534 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
4535 > MPLS_LABEL_UNRESERVED_MAX
)) {
4536 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
4537 rcap
->srlb
.lower_bound
= 0;
4538 rcap
->srlb
.range_size
= 0;
4540 /* Only one range is supported. Skip subsequent one */
4541 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
4543 stream_forward_getp(s
, size
);
4546 case ISIS_SUBTLV_NODE_MSD
:
4547 /* Check that MSD is correctly formated */
4548 if (length
< MSD_TLV_SIZE
) {
4549 stream_forward_getp(s
, length
);
4552 msd_type
= stream_getc(s
);
4553 rcap
->msd
= stream_getc(s
);
4554 /* Only BMI-MSD type has been defined in RFC 8491 */
4555 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
4557 /* Only one MSD is standardized. Skip others */
4558 if (length
> MSD_TLV_SIZE
)
4559 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
4562 case ISIS_SUBTLV_FAD
:
4563 fad
= XCALLOC(MTYPE_ISIS_TLV
,
4564 sizeof(struct isis_router_cap_fad
));
4565 fad
->fad
.algorithm
= stream_getc(s
);
4566 fad
->fad
.metric_type
= stream_getc(s
);
4567 fad
->fad
.calc_type
= stream_getc(s
);
4568 fad
->fad
.priority
= stream_getc(s
);
4569 rcap
->fads
[fad
->fad
.algorithm
] = fad
;
4570 admin_group_init(&fad
->fad
.admin_group_exclude_any
);
4571 admin_group_init(&fad
->fad
.admin_group_include_any
);
4572 admin_group_init(&fad
->fad
.admin_group_include_all
);
4574 subsubtlvs_len
= length
- 4;
4575 while (subsubtlvs_len
> 2) {
4576 struct admin_group
*ag
;
4577 uint8_t subsubtlv_type
;
4578 uint8_t subsubtlv_len
;
4582 subsubtlv_type
= stream_getc(s
);
4583 subsubtlv_len
= stream_getc(s
);
4585 switch (subsubtlv_type
) {
4586 case ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG
:
4587 ag
= &fad
->fad
.admin_group_exclude_any
;
4588 n_ag
= subsubtlv_len
/ sizeof(uint32_t);
4589 for (i
= 0; i
< n_ag
; i
++) {
4591 admin_group_bulk_set(ag
, v
, i
);
4594 case ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG
:
4595 ag
= &fad
->fad
.admin_group_include_any
;
4596 n_ag
= subsubtlv_len
/ sizeof(uint32_t);
4597 for (i
= 0; i
< n_ag
; i
++) {
4599 admin_group_bulk_set(ag
, v
, i
);
4602 case ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG
:
4603 ag
= &fad
->fad
.admin_group_include_all
;
4604 n_ag
= subsubtlv_len
/ sizeof(uint32_t);
4605 for (i
= 0; i
< n_ag
; i
++) {
4607 admin_group_bulk_set(ag
, v
, i
);
4610 case ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS
:
4611 if (subsubtlv_len
== 0)
4614 fad
->fad
.flags
= stream_getc(s
);
4615 for (i
= subsubtlv_len
- 1; i
> 0; --i
)
4618 case ISIS_SUBTLV_FAD_SUBSUBTLV_ESRLG
:
4619 fad
->fad
.exclude_srlg
= true;
4620 stream_forward_getp(s
, subsubtlv_len
);
4625 "Received an unsupported Flex-Algo sub-TLV type %u\n",
4627 fad
->fad
.unsupported_subtlv
= true;
4628 stream_forward_getp(s
, subsubtlv_len
);
4631 subsubtlvs_len
-= 2 + subsubtlv_len
;
4634 #endif /* ifndef FABRICD */
4636 stream_forward_getp(s
, length
);
4639 subtlv_len
= subtlv_len
- length
- 2;
4641 tlvs
->router_cap
= rcap
;
4645 /* Functions related to TLV 10 Authentication */
4646 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
4648 struct isis_auth
*auth
= (struct isis_auth
*)i
;
4649 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4651 rv
->type
= auth
->type
;
4652 rv
->length
= auth
->length
;
4653 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
4654 return (struct isis_item
*)rv
;
4657 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
4658 struct sbuf
*buf
, struct json_object
*json
,
4661 struct isis_auth
*auth
= (struct isis_auth
*)i
;
4665 json_object_string_add(json
, "test-auth", "ok");
4667 sbuf_push(buf
, indent
, "Authentication:\n");
4668 switch (auth
->type
) {
4669 case ISIS_PASSWD_TYPE_CLEARTXT
:
4670 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
4672 json_object_string_add(json
, "auth-pass", obuf
);
4674 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
4676 case ISIS_PASSWD_TYPE_HMAC_MD5
:
4677 for (unsigned int j
= 0; j
< 16; j
++) {
4678 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
, "%02hhx",
4682 json_object_string_add(json
, "auth-hmac-md5", obuf
);
4684 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
4688 json_object_int_add(json
, "auth-unknown", auth
->type
);
4690 sbuf_push(buf
, indent
, " Unknown (%hhu)\n",
4696 static void free_item_auth(struct isis_item
*i
)
4698 XFREE(MTYPE_ISIS_TLV
, i
);
4701 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
4704 struct isis_auth
*auth
= (struct isis_auth
*)i
;
4706 if (STREAM_WRITEABLE(s
) < 1) {
4710 stream_putc(s
, auth
->type
);
4712 switch (auth
->type
) {
4713 case ISIS_PASSWD_TYPE_CLEARTXT
:
4714 if (STREAM_WRITEABLE(s
) < auth
->length
) {
4715 *min_len
= 1 + auth
->length
;
4718 stream_put(s
, auth
->passwd
, auth
->length
);
4720 case ISIS_PASSWD_TYPE_HMAC_MD5
:
4721 if (STREAM_WRITEABLE(s
) < 16) {
4725 auth
->offset
= stream_get_endp(s
);
4726 stream_put(s
, NULL
, 16);
4735 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
4736 struct sbuf
*log
, void *dest
, int indent
)
4738 struct isis_tlvs
*tlvs
= dest
;
4740 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
4744 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
4749 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4751 rv
->type
= stream_getc(s
);
4752 rv
->length
= len
- 1;
4754 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
4757 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
4759 XFREE(MTYPE_ISIS_TLV
, rv
);
4763 rv
->offset
= stream_get_getp(s
);
4764 stream_get(rv
->value
, s
, rv
->length
);
4765 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, NULL
, indent
+ 2);
4766 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
4770 /* Functions related to TLV 13 Purge Originator */
4772 static struct isis_purge_originator
*copy_tlv_purge_originator(
4773 struct isis_purge_originator
*poi
)
4778 struct isis_purge_originator
*rv
;
4780 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
4781 rv
->sender_set
= poi
->sender_set
;
4782 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
4783 if (poi
->sender_set
)
4784 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
4788 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
4790 struct json_object
*json
, int indent
)
4792 char sen_id
[ISO_SYSID_STRLEN
];
4793 char gen_id
[ISO_SYSID_STRLEN
];
4798 snprintfrr(gen_id
, ISO_SYSID_STRLEN
, "%pSY", poi
->generator
);
4799 if (poi
->sender_set
)
4800 snprintfrr(sen_id
, ISO_SYSID_STRLEN
, "%pSY", poi
->sender
);
4803 struct json_object
*purge_json
;
4804 purge_json
= json_object_new_object();
4805 json_object_object_add(json
, "purge_originator", purge_json
);
4807 json_object_string_add(purge_json
, "id", gen_id
);
4808 if (poi
->sender_set
)
4809 json_object_string_add(purge_json
, "rec-from", sen_id
);
4811 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
4812 sbuf_push(buf
, indent
, " Generator: %s\n", gen_id
);
4813 if (poi
->sender_set
)
4814 sbuf_push(buf
, indent
, " Received-From: %s\n", sen_id
);
4818 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
4820 XFREE(MTYPE_ISIS_TLV
, poi
);
4823 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
4829 uint8_t data_len
= 1 + sizeof(poi
->generator
);
4831 if (poi
->sender_set
)
4832 data_len
+= sizeof(poi
->sender
);
4834 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
4837 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
4838 stream_putc(s
, data_len
);
4839 stream_putc(s
, poi
->sender_set
? 2 : 1);
4840 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
4841 if (poi
->sender_set
)
4842 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
4846 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
4847 uint8_t tlv_type
, uint8_t tlv_len
,
4848 struct stream
*s
, struct sbuf
*log
,
4849 void *dest
, int indent
)
4851 struct isis_tlvs
*tlvs
= dest
;
4852 struct isis_purge_originator poi
= {};
4854 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
4856 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
4860 uint8_t number_of_ids
= stream_getc(s
);
4862 if (number_of_ids
== 1) {
4863 poi
.sender_set
= false;
4864 } else if (number_of_ids
== 2) {
4865 poi
.sender_set
= true;
4867 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
4871 if (tlv_len
!= 1 + 6 * number_of_ids
) {
4872 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
4876 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
4878 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
4880 if (tlvs
->purge_originator
) {
4881 sbuf_push(log
, indent
,
4882 "WARNING: Purge originator present multiple times, ignoring.\n");
4886 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
4891 /* Functions relating to item TLVs */
4893 static void init_item_list(struct isis_item_list
*items
)
4896 items
->tail
= &items
->head
;
4900 static struct isis_item
*copy_item(enum isis_tlv_context context
,
4901 enum isis_tlv_type type
,
4902 struct isis_item
*item
)
4904 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4906 if (ops
&& ops
->copy_item
)
4907 return ops
->copy_item(item
);
4909 assert(!"Unknown item tlv type!");
4913 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4914 struct isis_item_list
*src
, struct isis_item_list
*dest
)
4916 struct isis_item
*item
;
4918 init_item_list(dest
);
4920 for (item
= src
->head
; item
; item
= item
->next
) {
4921 append_item(dest
, copy_item(context
, type
, item
));
4925 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
4926 enum isis_tlv_type type
, struct isis_item
*i
,
4927 struct sbuf
*buf
, struct json_object
*json
, int indent
)
4929 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4931 if (ops
&& ops
->format_item
) {
4932 ops
->format_item(mtid
, i
, buf
, json
, indent
);
4936 assert(!"Unknown item tlv type!");
4939 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
4940 enum isis_tlv_type type
, struct isis_item_list
*items
,
4941 struct sbuf
*buf
, struct json_object
*json
,
4944 struct isis_item
*i
;
4946 for (i
= items
->head
; i
; i
= i
->next
)
4947 format_item(mtid
, context
, type
, i
, buf
, json
, indent
);
4950 static void free_item(enum isis_tlv_context tlv_context
,
4951 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
4953 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
4955 if (ops
&& ops
->free_item
) {
4956 ops
->free_item(item
);
4960 assert(!"Unknown item tlv type!");
4963 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
4964 struct isis_item_list
*items
)
4966 struct isis_item
*item
, *next_item
;
4968 for (item
= items
->head
; item
; item
= next_item
) {
4969 next_item
= item
->next
;
4970 free_item(context
, type
, item
);
4974 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
4975 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
4976 struct isis_tlvs
**fragment_tlvs
,
4977 const struct pack_order_entry
*pe
, uint16_t mtid
)
4979 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
4981 if (ops
&& ops
->pack_item
) {
4982 return ops
->pack_item(i
, s
, min_len
);
4985 assert(!"Unknown item tlv type!");
4989 static void add_item_to_fragment(struct isis_item
*i
,
4990 const struct pack_order_entry
*pe
,
4991 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
4993 struct isis_item_list
*l
;
4995 if (pe
->how_to_pack
== ISIS_ITEMS
) {
4996 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
4998 struct isis_mt_item_list
*m
;
4999 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
5000 l
= isis_get_mt_items(m
, mtid
);
5003 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
5006 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
5007 enum isis_tlv_type type
, struct isis_item_list
*items
,
5008 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
5009 const struct pack_order_entry
*pe
,
5010 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
5011 struct list
*new_fragment_arg
)
5013 size_t len_pos
, last_len
, len
;
5014 struct isis_item
*item
= NULL
;
5022 if (STREAM_WRITEABLE(s
) < 2)
5025 stream_putc(s
, type
);
5026 len_pos
= stream_get_endp(s
);
5027 stream_putc(s
, 0); /* Put 0 as length for now */
5029 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
5030 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
5031 if (STREAM_WRITEABLE(s
) < 2)
5033 stream_putw(s
, mtid
);
5036 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
5037 if (STREAM_WRITEABLE(s
) < 1)
5039 stream_putc(s
, 0); /* Virtual flag is set to 0 */
5043 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
5044 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
5049 len
= stream_get_endp(s
) - len_pos
- 1;
5051 /* Multiple auths don't go into one TLV, so always break */
5052 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
5057 /* Multiple prefix-sids don't go into one TLV, so always break */
5058 if (type
== ISIS_SUBTLV_PREFIX_SID
5059 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
5060 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
5066 if (!last_len
) /* strange, not a single item fit */
5068 /* drop last tlv, otherwise, its too long */
5069 stream_set_endp(s
, len_pos
+ 1 + last_len
);
5075 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
5080 stream_putc_at(s
, len_pos
, len
);
5089 if (STREAM_WRITEABLE(s
) < min_len
)
5091 *fragment_tlvs
= new_fragment(new_fragment_arg
);
5094 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
5096 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
5099 dest
->tail
= &(*dest
->tail
)->next
;
5103 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
5105 struct isis_item
*item
, *prev
= NULL
, *next
;
5108 if ((dest
== NULL
) || (del
== NULL
))
5112 * TODO: delete is tricky because "dest" is a singly linked list.
5113 * We need to switch a doubly linked list.
5115 for (item
= dest
->head
; item
; item
= next
) {
5116 if (item
->next
== del
) {
5123 prev
->next
= del
->next
;
5124 if (dest
->head
== del
)
5125 dest
->head
= del
->next
;
5126 if ((struct isis_item
*)dest
->tail
== del
) {
5129 dest
->tail
= &(*dest
->tail
)->next
;
5131 dest
->tail
= &dest
->head
;
5136 static struct isis_item
*last_item(struct isis_item_list
*list
)
5138 return container_of(list
->tail
, struct isis_item
, next
);
5141 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
5142 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
5143 struct sbuf
*log
, void *dest
, int indent
)
5145 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
5147 if (ops
&& ops
->unpack_item
)
5148 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
5150 assert(!"Unknown item tlv type!");
5151 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
5155 static int unpack_tlv_with_items(enum isis_tlv_context context
,
5156 uint8_t tlv_type
, uint8_t tlv_len
,
5157 struct stream
*s
, struct sbuf
*log
, void *dest
,
5165 tlv_start
= stream_get_getp(s
);
5168 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
5170 sbuf_push(log
, indent
,
5171 "TLV is too short to contain MTID\n");
5174 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
5176 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
5177 isis_mtid2str_fake(mtid
));
5179 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
5180 mtid
= ISIS_MT_IPV4_UNICAST
;
5183 if (context
== ISIS_CONTEXT_LSP
5184 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
5185 if (tlv_len
- tlv_pos
< 1) {
5186 sbuf_push(log
, indent
,
5187 "TLV is too short for old style reach\n");
5190 stream_forward_getp(s
, 1);
5194 if (context
== ISIS_CONTEXT_LSP
5195 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
5196 struct isis_tlvs
*tlvs
= dest
;
5197 dest
= &tlvs
->oldstyle_ip_reach
;
5198 } else if (context
== ISIS_CONTEXT_LSP
5199 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
5200 struct isis_tlvs
*tlvs
= dest
;
5201 dest
= &tlvs
->oldstyle_ip_reach_ext
;
5204 if (context
== ISIS_CONTEXT_LSP
5205 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
5206 struct isis_tlvs
*tlvs
= dest
;
5207 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
5210 while (tlv_pos
< (size_t)tlv_len
) {
5211 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
5212 log
, dest
, indent
+ 2);
5216 tlv_pos
= stream_get_getp(s
) - tlv_start
;
5222 /* Functions to manipulate mt_item_lists */
5224 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
5225 const struct isis_item_list
*b
)
5227 if (a
->mtid
< b
->mtid
)
5229 if (a
->mtid
> b
->mtid
)
5234 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
5235 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
5237 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
5240 struct isis_item_list
*rv
;
5242 rv
= isis_lookup_mt_items(m
, mtid
);
5244 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
5247 RB_INSERT(isis_mt_item_list
, m
, rv
);
5253 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
5256 struct isis_item_list key
= {.mtid
= mtid
};
5258 return RB_FIND(isis_mt_item_list
, m
, &key
);
5261 static void free_mt_items(enum isis_tlv_context context
,
5262 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
5264 struct isis_item_list
*n
, *nnext
;
5266 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
5267 free_items(context
, type
, n
);
5268 RB_REMOVE(isis_mt_item_list
, m
, n
);
5269 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
5273 static void format_mt_items(enum isis_tlv_context context
,
5274 enum isis_tlv_type type
,
5275 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
5276 struct json_object
*json
, int indent
)
5278 struct isis_item_list
*n
;
5280 RB_FOREACH (n
, isis_mt_item_list
, m
) {
5281 format_items_(n
->mtid
, context
, type
, n
, buf
, json
, indent
);
5285 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
5286 struct isis_mt_item_list
*m
, struct stream
*s
,
5287 struct isis_tlvs
**fragment_tlvs
,
5288 const struct pack_order_entry
*pe
,
5289 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
5290 struct list
*new_fragment_arg
)
5292 struct isis_item_list
*n
;
5294 RB_FOREACH (n
, isis_mt_item_list
, m
) {
5297 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
5298 pe
, new_fragment
, new_fragment_arg
);
5306 static void copy_mt_items(enum isis_tlv_context context
,
5307 enum isis_tlv_type type
,
5308 struct isis_mt_item_list
*src
,
5309 struct isis_mt_item_list
*dest
)
5311 struct isis_item_list
*n
;
5313 RB_INIT(isis_mt_item_list
, dest
);
5315 RB_FOREACH (n
, isis_mt_item_list
, src
) {
5316 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
5320 /* Functions related to tlvs in general */
5322 struct isis_tlvs
*isis_alloc_tlvs(void)
5324 struct isis_tlvs
*result
;
5326 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
5328 init_item_list(&result
->isis_auth
);
5329 init_item_list(&result
->area_addresses
);
5330 init_item_list(&result
->mt_router_info
);
5331 init_item_list(&result
->oldstyle_reach
);
5332 init_item_list(&result
->lan_neighbor
);
5333 init_item_list(&result
->lsp_entries
);
5334 init_item_list(&result
->extended_reach
);
5335 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
5336 init_item_list(&result
->oldstyle_ip_reach
);
5337 init_item_list(&result
->oldstyle_ip_reach_ext
);
5338 init_item_list(&result
->ipv4_address
);
5339 init_item_list(&result
->ipv6_address
);
5340 init_item_list(&result
->global_ipv6_address
);
5341 init_item_list(&result
->extended_ip_reach
);
5342 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
5343 init_item_list(&result
->ipv6_reach
);
5344 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
5349 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
5351 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
5353 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
5356 rv
->purge_originator
=
5357 copy_tlv_purge_originator(tlvs
->purge_originator
);
5359 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
5360 &tlvs
->area_addresses
, &rv
->area_addresses
);
5362 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
5363 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
5365 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
5367 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
5368 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
5370 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
5371 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
5373 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
5376 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
5377 &tlvs
->extended_reach
, &rv
->extended_reach
);
5379 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
5382 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
5383 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
5385 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
5386 &rv
->protocols_supported
);
5388 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
5389 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
5391 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
5394 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
5397 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
5398 &tlvs
->global_ipv6_address
, &rv
->global_ipv6_address
);
5400 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
5402 rv
->te_router_id_ipv6
=
5403 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
5405 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
5406 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
5408 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
5409 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
5411 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
5413 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
5416 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
5417 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
5419 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
5421 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
5423 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
5428 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, struct json_object
*json
, int indent
)
5430 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, json
,
5433 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
5436 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, json
, indent
);
5438 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
5439 &tlvs
->area_addresses
, buf
, json
, indent
);
5441 if (tlvs
->mt_router_info_empty
) {
5443 json_object_string_add(json
, "mt-router-info", "none");
5445 sbuf_push(buf
, indent
, "MT Router Info: None\n");
5447 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
5448 &tlvs
->mt_router_info
, buf
, json
, indent
);
5451 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
5452 &tlvs
->oldstyle_reach
, buf
, json
, indent
);
5454 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
5455 &tlvs
->lan_neighbor
, buf
, json
, indent
);
5457 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
5460 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, json
, indent
);
5461 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, json
, indent
);
5462 format_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, buf
, json
,
5465 format_tlv_router_cap_json(tlvs
->router_cap
, json
);
5467 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
5469 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
5470 &tlvs
->extended_reach
, buf
, json
, indent
);
5472 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
5475 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
5476 &tlvs
->oldstyle_ip_reach
, buf
, json
, indent
);
5478 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
5479 &tlvs
->oldstyle_ip_reach_ext
, buf
, json
, indent
);
5481 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
5482 &tlvs
->ipv4_address
, buf
, json
, indent
);
5484 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
5485 &tlvs
->ipv6_address
, buf
, json
, indent
);
5487 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
5488 &tlvs
->global_ipv6_address
, buf
, json
, indent
);
5490 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
5491 &tlvs
->extended_ip_reach
, buf
, json
, indent
);
5493 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
5494 &tlvs
->mt_ip_reach
, buf
, json
, indent
);
5496 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
5499 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
5500 &tlvs
->mt_ipv6_reach
, buf
, json
, indent
);
5502 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, json
, indent
);
5504 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, json
, indent
);
5507 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
, struct json_object
*json
)
5510 format_tlvs(tlvs
, NULL
, json
, 0);
5513 static struct sbuf buf
;
5515 if (!sbuf_buf(&buf
))
5516 sbuf_init(&buf
, NULL
, 0);
5519 format_tlvs(tlvs
, &buf
, NULL
, 0);
5520 return sbuf_buf(&buf
);
5524 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
5529 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
5530 free_tlv_purge_originator(tlvs
->purge_originator
);
5531 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
5532 &tlvs
->area_addresses
);
5533 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
5534 &tlvs
->mt_router_info
);
5535 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
5536 &tlvs
->oldstyle_reach
);
5537 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
5538 &tlvs
->lan_neighbor
);
5539 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
5540 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
5541 &tlvs
->extended_reach
);
5542 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
5543 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
5544 &tlvs
->oldstyle_ip_reach
);
5545 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
5546 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
5547 &tlvs
->oldstyle_ip_reach_ext
);
5548 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
5549 &tlvs
->ipv4_address
);
5550 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
5551 &tlvs
->ipv6_address
);
5552 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_GLOBAL_IPV6_ADDRESS
,
5553 &tlvs
->global_ipv6_address
);
5554 free_tlv_te_router_id(tlvs
->te_router_id
);
5555 free_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
5556 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
5557 &tlvs
->extended_ip_reach
);
5558 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
5559 &tlvs
->mt_ip_reach
);
5560 free_tlv_dynamic_hostname(tlvs
->hostname
);
5561 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
5562 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
5563 &tlvs
->mt_ipv6_reach
);
5564 free_tlv_threeway_adj(tlvs
->threeway_adj
);
5565 free_tlv_router_cap(tlvs
->router_cap
);
5566 free_tlv_spine_leaf(tlvs
->spine_leaf
);
5568 XFREE(MTYPE_ISIS_TLV
, tlvs
);
5571 static void add_padding(struct stream
*s
)
5573 while (STREAM_WRITEABLE(s
)) {
5574 if (STREAM_WRITEABLE(s
) == 1)
5576 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
5578 if (padding_len
> 255) {
5579 if (padding_len
== 256)
5585 stream_putc(s
, ISIS_TLV_PADDING
);
5586 stream_putc(s
, padding_len
);
5587 stream_put(s
, NULL
, padding_len
);
5591 #define LSP_REM_LIFETIME_OFF 10
5592 #define LSP_CHECKSUM_OFF 24
5593 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
5594 uint16_t *rem_lifetime
)
5596 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
5597 sizeof(*rem_lifetime
));
5598 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
5599 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
5600 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
5603 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
5604 uint16_t rem_lifetime
)
5606 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
5607 sizeof(rem_lifetime
));
5608 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
5611 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
5615 uint16_t checksum
, rem_lifetime
;
5618 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
5620 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
5621 #ifdef CRYPTO_OPENSSL
5622 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
5623 auth
->plength
, STREAM_DATA(s
),
5624 stream_get_endp(s
), NULL
, NULL
);
5626 memcpy(digest
, result
, 16);
5627 #elif CRYPTO_INTERNAL
5628 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
5629 auth
->plength
, digest
);
5631 memcpy(auth
->value
, digest
, 16);
5632 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
5635 restore_auth_md5(s
, checksum
, rem_lifetime
);
5638 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
5640 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
5642 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
5643 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
5644 update_auth_hmac_md5(auth
, s
, is_lsp
);
5648 static int handle_pack_entry(const struct pack_order_entry
*pe
,
5649 struct isis_tlvs
*tlvs
, struct stream
*stream
,
5650 struct isis_tlvs
**fragment_tlvs
,
5651 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
5652 struct list
*new_fragment_arg
)
5656 if (pe
->how_to_pack
== ISIS_ITEMS
) {
5657 struct isis_item_list
*l
;
5658 l
= (struct isis_item_list
*)(((char *)tlvs
)
5659 + pe
->what_to_pack
);
5660 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
5661 pe
, new_fragment
, new_fragment_arg
);
5663 struct isis_mt_item_list
*l
;
5664 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
5665 + pe
->what_to_pack
);
5666 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
5667 fragment_tlvs
, pe
, new_fragment
,
5674 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
5675 struct isis_tlvs
*fragment_tlvs
,
5676 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
5677 struct list
*new_fragment_arg
)
5681 /* When fragmenting, don't add auth as it's already accounted for in the
5682 * size we are given. */
5683 if (!fragment_tlvs
) {
5684 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
5685 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
5691 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
5694 if (fragment_tlvs
) {
5695 fragment_tlvs
->purge_originator
=
5696 copy_tlv_purge_originator(tlvs
->purge_originator
);
5699 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
5702 if (fragment_tlvs
) {
5703 copy_tlv_protocols_supported(
5704 &tlvs
->protocols_supported
,
5705 &fragment_tlvs
->protocols_supported
);
5708 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
5709 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
5712 if (fragment_tlvs
) {
5713 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
5714 &tlvs
->area_addresses
,
5715 &fragment_tlvs
->area_addresses
);
5719 if (tlvs
->mt_router_info_empty
) {
5720 if (STREAM_WRITEABLE(stream
) < 2)
5722 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
5723 stream_putc(stream
, 0);
5725 fragment_tlvs
->mt_router_info_empty
= true;
5727 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
5728 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
5732 if (fragment_tlvs
) {
5733 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
5734 &tlvs
->mt_router_info
,
5735 &fragment_tlvs
->mt_router_info
);
5739 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
5743 fragment_tlvs
->hostname
=
5744 copy_tlv_dynamic_hostname(tlvs
->hostname
);
5746 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
5749 if (fragment_tlvs
) {
5750 fragment_tlvs
->router_cap
=
5751 copy_tlv_router_cap(tlvs
->router_cap
);
5754 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
5757 if (fragment_tlvs
) {
5758 fragment_tlvs
->te_router_id
=
5759 copy_tlv_te_router_id(tlvs
->te_router_id
);
5762 rv
= pack_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
, stream
);
5765 if (fragment_tlvs
) {
5766 fragment_tlvs
->te_router_id_ipv6
=
5767 copy_tlv_te_router_id_ipv6(tlvs
->te_router_id_ipv6
);
5770 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
5773 if (fragment_tlvs
) {
5774 fragment_tlvs
->threeway_adj
=
5775 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
5778 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
5781 if (fragment_tlvs
) {
5782 fragment_tlvs
->spine_leaf
=
5783 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
5786 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
5788 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
5789 fragment_tlvs
? &fragment_tlvs
: NULL
,
5790 new_fragment
, new_fragment_arg
);
5799 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
5800 size_t len_pointer
, bool pad
, bool is_lsp
)
5804 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
5809 add_padding(stream
);
5811 if (len_pointer
!= (size_t)-1) {
5812 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
5815 update_auth(tlvs
, stream
, is_lsp
);
5820 static struct isis_tlvs
*new_fragment(struct list
*l
)
5822 struct isis_tlvs
*rv
= isis_alloc_tlvs();
5824 listnode_add(l
, rv
);
5828 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
5830 struct stream
*dummy_stream
= stream_new(size
);
5831 struct list
*rv
= list_new();
5832 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
5834 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
5835 struct listnode
*node
;
5836 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
5837 isis_free_tlvs(fragment_tlvs
);
5841 stream_free(dummy_stream
);
5845 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
5846 uint8_t tlv_len
, struct stream
*s
,
5847 struct sbuf
*log
, int indent
)
5849 stream_forward_getp(s
, tlv_len
);
5850 sbuf_push(log
, indent
,
5851 "Skipping unknown TLV %hhu (%hhu bytes)\n",
5856 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
5857 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5858 int indent
, bool *unpacked_known_tlvs
)
5860 uint8_t tlv_type
, tlv_len
;
5861 const struct tlv_ops
*ops
;
5863 sbuf_push(log
, indent
, "Unpacking TLV...\n");
5865 if (avail_len
< 2) {
5868 "Available data %zu too short to contain a TLV header.\n",
5873 tlv_type
= stream_getc(stream
);
5874 tlv_len
= stream_getc(stream
);
5876 sbuf_push(log
, indent
+ 2,
5877 "Found TLV of type %hhu and len %hhu.\n",
5880 if (avail_len
< ((size_t)tlv_len
) + 2) {
5881 sbuf_push(log
, indent
+ 2,
5882 "Available data %zu too short for claimed TLV len %hhu.\n",
5883 avail_len
- 2, tlv_len
);
5887 ops
= tlv_table
[context
][tlv_type
];
5888 if (ops
&& ops
->unpack
) {
5889 if (unpacked_known_tlvs
)
5890 *unpacked_known_tlvs
= true;
5891 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
5895 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
5899 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
5900 struct stream
*stream
, struct sbuf
*log
, void *dest
,
5901 int indent
, bool *unpacked_known_tlvs
)
5904 size_t tlv_start
, tlv_pos
;
5906 tlv_start
= stream_get_getp(stream
);
5909 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
5910 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
5912 while (tlv_pos
< avail_len
) {
5913 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
5914 indent
+ 2, unpacked_known_tlvs
);
5918 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
5924 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
5925 struct isis_tlvs
**dest
, const char **log
)
5927 static struct sbuf logbuf
;
5930 struct isis_tlvs
*result
;
5932 if (!sbuf_buf(&logbuf
))
5933 sbuf_init(&logbuf
, NULL
, 0);
5935 sbuf_reset(&logbuf
);
5936 if (avail_len
> STREAM_READABLE(stream
)) {
5937 sbuf_push(&logbuf
, indent
,
5938 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5939 avail_len
, STREAM_READABLE(stream
));
5943 result
= isis_alloc_tlvs();
5944 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
5947 *log
= sbuf_buf(&logbuf
);
5953 #define TLV_OPS(_name_, _desc_) \
5954 static const struct tlv_ops tlv_##_name_##_ops = { \
5955 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5958 #define ITEM_TLV_OPS(_name_, _desc_) \
5959 static const struct tlv_ops tlv_##_name_##_ops = { \
5961 .unpack = unpack_tlv_with_items, \
5963 .pack_item = pack_item_##_name_, \
5964 .free_item = free_item_##_name_, \
5965 .unpack_item = unpack_item_##_name_, \
5966 .format_item = format_item_##_name_, \
5967 .copy_item = copy_item_##_name_}
5969 #define SUBTLV_OPS(_name_, _desc_) \
5970 static const struct tlv_ops subtlv_##_name_##_ops = { \
5971 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5974 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5975 ITEM_TLV_OPS(_name_, _desc_)
5977 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
5978 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
5979 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
5980 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
5981 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
5982 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
5983 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
5984 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
5985 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
5986 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
5987 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
5988 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
5989 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
5990 TLV_OPS(te_router_id_ipv6
, "TLV 140 IPv6 TE Router ID");
5991 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
5992 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
5993 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
5994 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
5995 ITEM_TLV_OPS(global_ipv6_address
, "TLV 233 Global IPv6 Interface Address");
5996 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
5997 TLV_OPS(router_cap
, "TLV 242 Router Capability");
5999 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
6000 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
6002 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
6003 [ISIS_CONTEXT_LSP
] = {
6004 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
6005 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
6006 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
6007 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
6008 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
6009 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
6010 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
6011 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
6012 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
6013 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
6014 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
6015 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
6016 [ISIS_TLV_TE_ROUTER_ID_IPV6
] = &tlv_te_router_id_ipv6_ops
,
6017 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
6018 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
6019 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
6020 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
6021 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
6022 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
6023 [ISIS_TLV_GLOBAL_IPV6_ADDRESS
] = &tlv_global_ipv6_address_ops
,
6024 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
6025 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
6026 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
6027 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
6028 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
6030 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
6031 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
6032 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
6034 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
6035 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
6036 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
6040 /* Accessor functions */
6042 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
6044 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
6045 init_item_list(&tlvs
->isis_auth
);
6047 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
6050 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
6052 auth
->type
= passwd
->type
;
6054 auth
->plength
= passwd
->len
;
6055 memcpy(auth
->passwd
, passwd
->passwd
,
6056 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
6058 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
6059 auth
->length
= passwd
->len
;
6060 memcpy(auth
->value
, passwd
->passwd
,
6061 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
6064 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
6067 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
6068 struct list
*addresses
)
6070 struct listnode
*node
;
6071 struct iso_address
*area_addr
;
6073 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
6074 struct isis_area_address
*a
=
6075 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
6077 a
->len
= area_addr
->addr_len
;
6078 memcpy(a
->addr
, area_addr
->area_addr
, ISO_ADDR_SIZE
);
6079 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
6083 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
6085 struct listnode
*node
;
6088 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
6089 struct isis_lan_neighbor
*n
=
6090 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
6092 memcpy(n
->mac
, snpa
, 6);
6093 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
6097 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
6098 struct nlpids
*nlpids
)
6100 tlvs
->protocols_supported
.count
= nlpids
->count
;
6101 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
6102 if (nlpids
->count
) {
6103 tlvs
->protocols_supported
.protocols
=
6104 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
6105 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
6108 tlvs
->protocols_supported
.protocols
= NULL
;
6112 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
6113 bool overload
, bool attached
)
6115 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
6117 i
->overload
= overload
;
6118 i
->attached
= attached
;
6120 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
6123 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
6125 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
6127 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
6131 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
6132 struct list
*addresses
)
6134 struct listnode
*node
;
6135 struct prefix_ipv4
*ip_addr
;
6136 unsigned int addr_count
= 0;
6138 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
6139 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
6141 if (addr_count
>= 63)
6146 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
6147 struct list
*addresses
)
6149 struct listnode
*node
;
6150 struct prefix_ipv6
*ip_addr
;
6151 unsigned int addr_count
= 0;
6153 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
6154 if (addr_count
>= 15)
6157 struct isis_ipv6_address
*a
=
6158 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
6160 a
->addr
= ip_addr
->prefix
;
6161 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
6166 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs
*tlvs
,
6167 struct list
*addresses
)
6169 struct listnode
*node
;
6170 struct prefix_ipv6
*ip_addr
;
6171 unsigned int addr_count
= 0;
6173 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
6174 if (addr_count
>= 15)
6177 struct isis_ipv6_address
*a
=
6178 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
6180 a
->addr
= ip_addr
->prefix
;
6181 append_item(&tlvs
->global_ipv6_address
, (struct isis_item
*)a
);
6186 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
6187 struct stream
*stream
,
6188 struct isis_auth
*auth
, bool is_lsp
);
6190 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
6191 struct stream
*stream
,
6192 struct isis_auth
*auth
, bool is_lsp
)
6194 return (auth
->length
== passwd
->len
6195 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
6198 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
6199 struct stream
*stream
,
6200 struct isis_auth
*auth
, bool is_lsp
)
6204 uint16_t rem_lifetime
;
6207 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
6209 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
6210 #ifdef CRYPTO_OPENSSL
6211 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
6212 passwd
->len
, STREAM_DATA(stream
),
6213 stream_get_endp(stream
), NULL
, NULL
);
6215 memcpy(digest
, result
, 16);
6216 #elif CRYPTO_INTERNAL
6217 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
6218 passwd
->len
, digest
);
6220 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
6222 bool rv
= !memcmp(digest
, auth
->value
, 16);
6225 restore_auth_md5(stream
, checksum
, rem_lifetime
);
6230 static const auth_validator_func auth_validators
[] = {
6231 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
6232 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
6235 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
6236 struct stream
*stream
, bool is_lsp
)
6238 /* If no auth is set, always pass authentication */
6240 return ISIS_AUTH_OK
;
6242 /* If we don't known how to validate the auth, return invalid */
6243 if (passwd
->type
>= array_size(auth_validators
)
6244 || !auth_validators
[passwd
->type
])
6245 return ISIS_AUTH_NO_VALIDATOR
;
6247 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
6248 struct isis_auth
*auth
;
6249 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
6250 if (auth
->type
== passwd
->type
)
6254 /* If matching auth TLV could not be found, return invalid */
6256 return ISIS_AUTH_TYPE_FAILURE
;
6259 /* Perform validation and return result */
6260 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
6261 return ISIS_AUTH_OK
;
6263 return ISIS_AUTH_FAILURE
;
6266 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
6267 struct list
*addresses
)
6269 struct isis_area_address
*addr_head
;
6271 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
6272 for (struct isis_area_address
*addr
= addr_head
; addr
;
6273 addr
= addr
->next
) {
6274 struct listnode
*node
;
6275 struct iso_address
*a
;
6277 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
6278 if (a
->addr_len
== addr
->len
6279 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
6287 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
6288 struct isis_adjacency
*adj
,
6291 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
6292 uint32_t oc
= adj
->area_address_count
;
6295 adj
->area_address_count
= tlvs
->area_addresses
.count
;
6296 adj
->area_addresses
= XREALLOC(
6297 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
6298 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
6300 for (; oc
< adj
->area_address_count
; oc
++) {
6301 adj
->area_addresses
[oc
].addr_len
= 0;
6302 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
6303 sizeof(adj
->area_addresses
[oc
].area_addr
));
6307 struct isis_area_address
*addr
= NULL
;
6308 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
6310 addr
= (struct isis_area_address
*)
6311 tlvs
->area_addresses
.head
;
6315 if (adj
->area_addresses
[i
].addr_len
== addr
->len
6316 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
6322 adj
->area_addresses
[i
].addr_len
= addr
->len
;
6323 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
6327 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
6328 struct isis_adjacency
*adj
,
6331 bool ipv4_supported
= false, ipv6_supported
= false;
6333 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
6334 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
6335 ipv4_supported
= true;
6336 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
6337 ipv6_supported
= true;
6340 struct nlpids reduced
= {};
6342 if (ipv4_supported
&& ipv6_supported
) {
6344 reduced
.nlpids
[0] = NLPID_IP
;
6345 reduced
.nlpids
[1] = NLPID_IPV6
;
6346 } else if (ipv4_supported
) {
6348 reduced
.nlpids
[0] = NLPID_IP
;
6349 } else if (ipv6_supported
) {
6351 reduced
.nlpids
[0] = NLPID_IPV6
;
6356 if (adj
->nlpids
.count
== reduced
.count
6357 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
6361 adj
->nlpids
.count
= reduced
.count
;
6362 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
6365 DEFINE_HOOK(isis_adj_ip_enabled_hook
,
6366 (struct isis_adjacency
* adj
, int family
, bool global
),
6367 (adj
, family
, global
));
6368 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
6369 (struct isis_adjacency
* adj
, int family
, bool global
),
6370 (adj
, family
, global
));
6372 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
6373 struct isis_adjacency
*adj
,
6376 bool ipv4_enabled
= false;
6378 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
6379 ipv4_enabled
= true;
6380 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
6381 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
, false);
6383 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
6384 uint32_t oc
= adj
->ipv4_address_count
;
6387 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
6388 adj
->ipv4_addresses
= XREALLOC(
6389 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
6390 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
6392 for (; oc
< adj
->ipv4_address_count
; oc
++) {
6393 memset(&adj
->ipv4_addresses
[oc
], 0,
6394 sizeof(adj
->ipv4_addresses
[oc
]));
6398 struct isis_ipv4_address
*addr
= NULL
;
6399 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
6401 addr
= (struct isis_ipv4_address
*)
6402 tlvs
->ipv4_address
.head
;
6406 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
6407 sizeof(addr
->addr
)))
6411 adj
->ipv4_addresses
[i
] = addr
->addr
;
6415 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
, false);
6418 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
6419 struct isis_adjacency
*adj
,
6422 bool ipv6_enabled
= false;
6424 if (adj
->ll_ipv6_count
== 0 && tlvs
->ipv6_address
.count
> 0)
6425 ipv6_enabled
= true;
6426 else if (adj
->ll_ipv6_count
> 0 && tlvs
->ipv6_address
.count
== 0)
6427 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, false);
6429 if (adj
->ll_ipv6_count
!= tlvs
->ipv6_address
.count
) {
6430 uint32_t oc
= adj
->ll_ipv6_count
;
6433 adj
->ll_ipv6_count
= tlvs
->ipv6_address
.count
;
6434 adj
->ll_ipv6_addrs
= XREALLOC(
6435 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
,
6436 adj
->ll_ipv6_count
* sizeof(*adj
->ll_ipv6_addrs
));
6438 for (; oc
< adj
->ll_ipv6_count
; oc
++) {
6439 memset(&adj
->ll_ipv6_addrs
[oc
], 0,
6440 sizeof(adj
->ll_ipv6_addrs
[oc
]));
6444 struct isis_ipv6_address
*addr
= NULL
;
6445 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
6447 addr
= (struct isis_ipv6_address
*)
6448 tlvs
->ipv6_address
.head
;
6452 if (!memcmp(&adj
->ll_ipv6_addrs
[i
], &addr
->addr
,
6453 sizeof(addr
->addr
)))
6457 adj
->ll_ipv6_addrs
[i
] = addr
->addr
;
6461 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, false);
6465 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
6466 struct isis_adjacency
*adj
,
6469 bool global_ipv6_enabled
= false;
6471 if (adj
->global_ipv6_count
== 0 && tlvs
->global_ipv6_address
.count
> 0)
6472 global_ipv6_enabled
= true;
6473 else if (adj
->global_ipv6_count
> 0
6474 && tlvs
->global_ipv6_address
.count
== 0)
6475 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
, true);
6477 if (adj
->global_ipv6_count
!= tlvs
->global_ipv6_address
.count
) {
6478 uint32_t oc
= adj
->global_ipv6_count
;
6481 adj
->global_ipv6_count
= tlvs
->global_ipv6_address
.count
;
6482 adj
->global_ipv6_addrs
= XREALLOC(
6483 MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
,
6484 adj
->global_ipv6_count
6485 * sizeof(*adj
->global_ipv6_addrs
));
6487 for (; oc
< adj
->global_ipv6_count
; oc
++) {
6488 memset(&adj
->global_ipv6_addrs
[oc
], 0,
6489 sizeof(adj
->global_ipv6_addrs
[oc
]));
6493 struct isis_ipv6_address
*addr
= NULL
;
6494 for (unsigned int i
= 0; i
< tlvs
->global_ipv6_address
.count
; i
++) {
6496 addr
= (struct isis_ipv6_address
*)
6497 tlvs
->global_ipv6_address
.head
;
6501 if (!memcmp(&adj
->global_ipv6_addrs
[i
], &addr
->addr
,
6502 sizeof(addr
->addr
)))
6506 adj
->global_ipv6_addrs
[i
] = addr
->addr
;
6509 if (global_ipv6_enabled
)
6510 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
, true);
6513 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
6518 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
6519 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
6520 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
6521 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
6522 tlvs_global_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
6525 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
6527 struct isis_lan_neighbor
*ne_head
;
6529 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
6530 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
6531 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
6538 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
6540 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
6542 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
6543 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
6544 entry
->checksum
= lsp
->hdr
.checksum
;
6545 entry
->seqno
= lsp
->hdr
.seqno
;
6548 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
6551 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
6552 uint8_t *stop_id
, uint16_t num_lsps
,
6553 struct lspdb_head
*head
,
6554 struct isis_lsp
**last_lsp
)
6556 struct isis_lsp searchfor
;
6557 struct isis_lsp
*first
, *lsp
;
6559 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
6560 first
= lspdb_find_gteq(head
, &searchfor
);
6564 frr_each_from (lspdb
, head
, lsp
, first
) {
6565 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
6566 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
6569 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
6574 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
6575 const char *hostname
)
6577 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
6579 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
6582 /* Init Router Capability TLV parameters */
6583 struct isis_router_cap
*isis_tlvs_init_router_capability(struct isis_tlvs
*tlvs
)
6585 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
6587 /* init SR algo list content to the default value */
6588 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
6589 tlvs
->router_cap
->algo
[i
] = SR_ALGORITHM_UNSET
;
6591 return tlvs
->router_cap
;
6595 void isis_tlvs_set_router_capability_fad(struct isis_tlvs
*tlvs
,
6596 struct flex_algo
*fa
, int algorithm
,
6599 struct isis_router_cap_fad
*rcap_fad
;
6601 assert(tlvs
->router_cap
);
6603 rcap_fad
= tlvs
->router_cap
->fads
[algorithm
];
6606 rcap_fad
= XCALLOC(MTYPE_ISIS_TLV
,
6607 sizeof(struct isis_router_cap_fad
));
6609 memset(rcap_fad
->sysid
, 0, ISIS_SYS_ID_LEN
+ 2);
6610 memcpy(rcap_fad
->sysid
, sysid
, ISIS_SYS_ID_LEN
);
6612 memcpy(&rcap_fad
->fad
, fa
, sizeof(struct flex_algo
));
6614 rcap_fad
->fad
.admin_group_exclude_any
.bitmap
.data
= NULL
;
6615 rcap_fad
->fad
.admin_group_include_any
.bitmap
.data
= NULL
;
6616 rcap_fad
->fad
.admin_group_include_all
.bitmap
.data
= NULL
;
6618 admin_group_copy(&rcap_fad
->fad
.admin_group_exclude_any
,
6619 &fa
->admin_group_exclude_any
);
6620 admin_group_copy(&rcap_fad
->fad
.admin_group_include_any
,
6621 &fa
->admin_group_include_any
);
6622 admin_group_copy(&rcap_fad
->fad
.admin_group_include_all
,
6623 &fa
->admin_group_include_all
);
6625 tlvs
->router_cap
->fads
[algorithm
] = rcap_fad
;
6627 #endif /* ifndef FABRICD */
6629 int isis_tlvs_sr_algo_count(const struct isis_router_cap
*cap
)
6633 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
6634 if (cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
6639 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
6640 const struct in_addr
*id
)
6642 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
6645 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
6646 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
6649 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs
*tlvs
,
6650 const struct in6_addr
*id
)
6652 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id_ipv6
);
6655 tlvs
->te_router_id_ipv6
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
6656 memcpy(tlvs
->te_router_id_ipv6
, id
, sizeof(*id
));
6659 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
6660 struct prefix_ipv4
*dest
, uint8_t metric
)
6662 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
6665 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
6666 apply_mask_ipv4(&r
->prefix
);
6667 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
6670 /* Add IS-IS SR Adjacency-SID subTLVs */
6671 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
6672 struct isis_adj_sid
*adj
)
6674 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
6675 SET_SUBTLV(exts
, EXT_ADJ_SID
);
6678 /* Delete IS-IS SR Adjacency-SID subTLVs */
6679 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
6680 struct isis_adj_sid
*adj
)
6682 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
6683 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
6684 if (exts
->adj_sid
.count
== 0)
6685 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
6688 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
6689 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
6690 struct isis_lan_adj_sid
*lan
)
6692 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
6693 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
6696 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
6697 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
6698 struct isis_lan_adj_sid
*lan
)
6700 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
6701 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
6702 if (exts
->lan_sid
.count
== 0)
6703 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
6706 void isis_tlvs_del_asla_flex_algo(struct isis_ext_subtlvs
*ext
,
6707 struct isis_asla_subtlvs
*asla
)
6709 admin_group_term(&asla
->ext_admin_group
);
6710 listnode_delete(ext
->aslas
, asla
);
6711 XFREE(MTYPE_ISIS_SUBTLV
, asla
);
6714 struct isis_asla_subtlvs
*
6715 isis_tlvs_find_alloc_asla(struct isis_ext_subtlvs
*ext
, uint8_t standard_apps
)
6717 struct isis_asla_subtlvs
*asla
;
6718 struct listnode
*node
;
6720 if (!list_isempty(ext
->aslas
)) {
6721 for (ALL_LIST_ELEMENTS_RO(ext
->aslas
, node
, asla
)) {
6722 if (CHECK_FLAG(asla
->standard_apps
, standard_apps
))
6727 asla
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_asla_subtlvs
));
6728 admin_group_init(&asla
->ext_admin_group
);
6729 SET_FLAG(asla
->standard_apps
, standard_apps
);
6730 SET_FLAG(asla
->user_def_apps
, standard_apps
);
6731 asla
->standard_apps_length
= ASLA_APP_IDENTIFIER_BIT_LENGTH
;
6732 asla
->user_def_apps_length
= ASLA_APP_IDENTIFIER_BIT_LENGTH
;
6734 listnode_add(ext
->aslas
, asla
);
6738 void isis_tlvs_free_asla(struct isis_ext_subtlvs
*ext
, uint8_t standard_apps
)
6740 struct isis_asla_subtlvs
*asla
;
6741 struct listnode
*node
;
6746 for (ALL_LIST_ELEMENTS_RO(ext
->aslas
, node
, asla
)) {
6747 if (!CHECK_FLAG(asla
->standard_apps
, standard_apps
))
6749 isis_tlvs_del_asla_flex_algo(ext
, asla
);
6754 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
6755 struct prefix_ipv4
*dest
, uint32_t metric
,
6757 struct sr_prefix_cfg
**pcfgs
)
6759 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
6762 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
6763 apply_mask_ipv4(&r
->prefix
);
6766 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
6767 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
6768 struct isis_prefix_sid
*psid
;
6769 struct sr_prefix_cfg
*pcfg
= pcfgs
[i
];
6774 psid
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
6775 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
6776 append_item(&r
->subtlvs
->prefix_sids
,
6777 (struct isis_item
*)psid
);
6781 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
6784 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
6785 struct prefix_ipv6
*dest
, uint32_t metric
,
6786 bool external
, struct sr_prefix_cfg
**pcfgs
)
6788 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
6791 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
6792 apply_mask_ipv6(&r
->prefix
);
6794 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
6795 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
6796 struct isis_prefix_sid
*psid
;
6797 struct sr_prefix_cfg
*pcfg
= pcfgs
[i
];
6802 psid
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
6803 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
6804 append_item(&r
->subtlvs
->prefix_sids
,
6805 (struct isis_item
*)psid
);
6809 struct isis_item_list
*l
;
6810 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
6812 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
6813 append_item(l
, (struct isis_item
*)r
);
6816 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
6817 struct prefix_ipv6
*dest
,
6818 struct prefix_ipv6
*src
,
6821 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
6822 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
6825 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
6826 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
6827 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
6828 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
6831 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
6834 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
6837 memcpy(r
->id
, id
, sizeof(r
->id
));
6838 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
6841 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
6842 uint8_t *id
, uint32_t metric
,
6843 struct isis_ext_subtlvs
*exts
)
6845 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
6847 memcpy(r
->id
, id
, sizeof(r
->id
));
6850 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
6852 struct isis_item_list
*l
;
6853 if ((mtid
== ISIS_MT_IPV4_UNICAST
) || (mtid
== ISIS_MT_DISABLE
))
6854 l
= &tlvs
->extended_reach
;
6856 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
6857 append_item(l
, (struct isis_item
*)r
);
6860 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
6861 enum isis_threeway_state state
,
6862 uint32_t local_circuit_id
,
6863 const uint8_t *neighbor_id
,
6864 uint32_t neighbor_circuit_id
)
6866 assert(!tlvs
->threeway_adj
);
6868 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
6869 tlvs
->threeway_adj
->state
= state
;
6870 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
6873 tlvs
->threeway_adj
->neighbor_set
= true;
6874 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
6875 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
6879 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
6880 bool has_tier
, bool is_leaf
, bool is_spine
,
6883 assert(!tlvs
->spine_leaf
);
6885 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
6888 tlvs
->spine_leaf
->tier
= tier
;
6891 tlvs
->spine_leaf
->has_tier
= has_tier
;
6892 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
6893 tlvs
->spine_leaf
->is_spine
= is_spine
;
6894 tlvs
->spine_leaf
->is_backup
= is_backup
;
6897 struct isis_mt_router_info
*
6898 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
6900 if (!tlvs
|| tlvs
->mt_router_info_empty
)
6903 struct isis_mt_router_info
*rv
;
6904 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
6906 if (rv
->mtid
== mtid
)
6913 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
6914 const uint8_t *generator
,
6915 const uint8_t *sender
)
6917 assert(!tlvs
->purge_originator
);
6919 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
6920 sizeof(*tlvs
->purge_originator
));
6921 memcpy(tlvs
->purge_originator
->generator
, generator
,
6922 sizeof(tlvs
->purge_originator
->generator
));
6924 tlvs
->purge_originator
->sender_set
= true;
6925 memcpy(tlvs
->purge_originator
->sender
, sender
,
6926 sizeof(tlvs
->purge_originator
->sender
));