2 * IS-IS TLV Serializer/Deserializer
4 * Copyright (C) 2015,2017 Christian Franke
6 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
8 * This file is part of FRR.
10 * FRR is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FRR; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #ifdef CRYPTO_INTERNAL
35 #include "isisd/isisd.h"
36 #include "isisd/isis_memory.h"
37 #include "isisd/isis_tlvs.h"
38 #include "isisd/isis_common.h"
39 #include "isisd/isis_mt.h"
40 #include "isisd/isis_misc.h"
41 #include "isisd/isis_adjacency.h"
42 #include "isisd/isis_circuit.h"
43 #include "isisd/isis_pdu.h"
44 #include "isisd/isis_lsp.h"
45 #include "isisd/isis_te.h"
46 #include "isisd/isis_sr.h"
48 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs")
49 DEFINE_MTYPE(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs")
50 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists")
52 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
53 uint8_t tlv_len
, struct stream
*s
,
54 struct sbuf
*log
, void *dest
, int indent
);
55 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
);
56 typedef void (*free_item_func
)(struct isis_item
*i
);
57 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
58 struct sbuf
*log
, void *dest
, int indent
);
59 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
60 struct sbuf
*buf
, int indent
);
61 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
65 unpack_tlv_func unpack
;
67 pack_item_func pack_item
;
68 free_item_func free_item
;
69 unpack_item_func unpack_item
;
70 format_item_func format_item
;
71 copy_item_func copy_item
;
79 struct pack_order_entry
{
80 enum isis_tlv_context context
;
81 enum isis_tlv_type type
;
82 enum how_to_pack how_to_pack
;
85 #define PACK_ENTRY(t, h, w) \
87 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
89 .what_to_pack = offsetof(struct isis_tlvs, w), \
92 static const struct pack_order_entry pack_order
[] = {
93 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
94 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
95 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
96 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
97 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
98 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
99 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
100 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
101 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
102 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
103 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
104 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
105 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)
108 /* This is a forward definition. The table is actually initialized
109 * in at the bottom. */
110 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
112 /* End of _ops forward definition. */
115 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
116 static void init_item_list(struct isis_item_list
*items
);
118 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
119 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
121 struct isis_ext_subtlvs
*ext
;
123 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
124 init_item_list(&ext
->adj_sid
);
125 init_item_list(&ext
->lan_sid
);
131 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
132 * A negative value could be used to skip copy of Adjacency SID.
134 static struct isis_ext_subtlvs
*
135 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, int16_t mtid
)
137 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
138 struct isis_adj_sid
*adj
;
139 struct isis_lan_adj_sid
*lan
;
141 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
142 init_item_list(&rv
->adj_sid
);
143 init_item_list(&rv
->lan_sid
);
145 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
146 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
148 /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
149 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
152 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
153 && (adj
->family
!= AF_INET
))
154 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
155 && (adj
->family
!= AF_INET6
))))
158 struct isis_adj_sid
*new;
160 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
161 new->family
= adj
->family
;
162 new->flags
= adj
->flags
;
163 new->weight
= adj
->weight
;
165 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
166 SET_SUBTLV(rv
, EXT_ADJ_SID
);
169 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
172 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
173 && (lan
->family
!= AF_INET
))
174 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
175 && (lan
->family
!= AF_INET6
))))
178 struct isis_lan_adj_sid
*new;
180 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
181 new->family
= lan
->family
;
182 new->flags
= lan
->flags
;
183 new->weight
= lan
->weight
;
184 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
186 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
187 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
193 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
194 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
195 struct sbuf
*buf
, int indent
,
199 char ibuf
[PREFIX2STR_BUFFER
];
201 /* Standard metrics */
202 if (IS_SUBTLV(exts
, EXT_ADM_GRP
))
203 sbuf_push(buf
, indent
, "Administrative Group: 0x%" PRIx32
"\n",
205 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
206 sbuf_push(buf
, indent
, "Link Local ID: %" PRIu32
"\n",
208 sbuf_push(buf
, indent
, "Link Remote ID: %" PRIu32
"\n",
211 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
))
212 sbuf_push(buf
, indent
, "Local Interface IP Address(es): %s\n",
213 inet_ntoa(exts
->local_addr
));
214 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
))
215 sbuf_push(buf
, indent
, "Remote Interface IP Address(es): %s\n",
216 inet_ntoa(exts
->neigh_addr
));
217 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
))
218 sbuf_push(buf
, indent
, "Local Interface IPv6 Address(es): %s\n",
219 inet_ntop(AF_INET6
, &exts
->local_addr6
, ibuf
,
221 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
))
222 sbuf_push(buf
, indent
, "Remote Interface IPv6 Address(es): %s\n",
223 inet_ntop(AF_INET6
, &exts
->local_addr6
, ibuf
,
225 if (IS_SUBTLV(exts
, EXT_MAX_BW
))
226 sbuf_push(buf
, indent
, "Maximum Bandwidth: %g (Bytes/sec)\n",
228 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
))
229 sbuf_push(buf
, indent
,
230 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
232 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
233 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
234 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
235 sbuf_push(buf
, indent
+ 2,
236 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
237 j
, exts
->unrsv_bw
[j
],
238 j
+ 1, exts
->unrsv_bw
[j
+ 1]);
241 if (IS_SUBTLV(exts
, EXT_TE_METRIC
))
242 sbuf_push(buf
, indent
, "Traffic Engineering Metric: %u\n",
244 if (IS_SUBTLV(exts
, EXT_RMT_AS
))
245 sbuf_push(buf
, indent
,
246 "Inter-AS TE Remote AS number: %" PRIu32
"\n",
248 if (IS_SUBTLV(exts
, EXT_RMT_IP
))
249 sbuf_push(buf
, indent
,
250 "Inter-AS TE Remote ASBR IP address: %s\n",
251 inet_ntoa(exts
->remote_ip
));
252 /* Extended metrics */
253 if (IS_SUBTLV(exts
, EXT_DELAY
))
254 sbuf_push(buf
, indent
,
255 "%s Average Link Delay: %" PRIu32
" (micro-sec)\n",
256 IS_ANORMAL(exts
->delay
) ? "Anomalous" : "Normal",
258 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
259 sbuf_push(buf
, indent
, "%s Min/Max Link Delay: %" PRIu32
" / %"
260 PRIu32
" (micro-sec)\n",
261 IS_ANORMAL(exts
->min_delay
) ? "Anomalous" : "Normal",
262 exts
->min_delay
& TE_EXT_MASK
,
263 exts
->max_delay
& TE_EXT_MASK
);
265 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
266 sbuf_push(buf
, indent
,
267 "Delay Variation: %" PRIu32
" (micro-sec)\n",
268 exts
->delay_var
& TE_EXT_MASK
);
270 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
))
271 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
272 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous" : "Normal",
273 (float)((exts
->pkt_loss
& TE_EXT_MASK
)
275 if (IS_SUBTLV(exts
, EXT_RES_BW
))
276 sbuf_push(buf
, indent
,
277 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
279 if (IS_SUBTLV(exts
, EXT_AVA_BW
))
280 sbuf_push(buf
, indent
,
281 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
283 if (IS_SUBTLV(exts
, EXT_USE_BW
))
284 sbuf_push(buf
, indent
,
285 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
287 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
288 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
289 struct isis_adj_sid
*adj
;
291 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
293 if (((mtid
== ISIS_MT_IPV4_UNICAST
)
294 && (adj
->family
!= AF_INET
))
295 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
296 && (adj
->family
!= AF_INET6
)))
300 "Adjacency-SID: %" PRIu32
", Weight: %" PRIu8
301 ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
302 adj
->sid
, adj
->weight
,
303 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? '1'
305 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? '1'
307 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
? '1'
309 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
? '1'
311 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
? '1'
313 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
318 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
319 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
320 struct isis_lan_adj_sid
*lan
;
322 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
;
323 lan
; lan
= lan
->next
) {
324 if (((mtid
== ISIS_MT_IPV4_UNICAST
)
325 && (lan
->family
!= AF_INET
))
326 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
327 && (lan
->family
!= AF_INET6
)))
329 sbuf_push(buf
, indent
,
330 "Lan-Adjacency-SID: %" PRIu32
332 ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
333 " Neighbor-ID: %s\n",
334 lan
->sid
, lan
->weight
,
335 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
338 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
341 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
344 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
347 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
350 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
353 isis_format_id(lan
->neighbor_id
, 6));
358 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
360 struct isis_item
*item
, *next_item
;
362 /* First, free Adj SID and LAN Adj SID list if needed */
363 for (item
= exts
->adj_sid
.head
; item
; item
= next_item
) {
364 next_item
= item
->next
;
365 XFREE(MTYPE_ISIS_SUBTLV
, item
);
367 for (item
= exts
->lan_sid
.head
; item
; item
= next_item
) {
368 next_item
= item
->next
;
369 XFREE(MTYPE_ISIS_SUBTLV
, item
);
371 XFREE(MTYPE_ISIS_SUBTLV
, exts
);
374 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
379 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
)
382 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
383 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
384 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
385 stream_putl(s
, exts
->adm_group
);
387 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
388 stream_putc(s
, ISIS_SUBTLV_LLRI
);
389 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
390 stream_putl(s
, exts
->local_llri
);
391 stream_putl(s
, exts
->remote_llri
);
393 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
394 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
395 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
396 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
398 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
399 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
400 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
401 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
403 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
404 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
405 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
406 stream_put(s
, &exts
->local_addr6
, 16);
408 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
409 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
410 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
411 stream_put(s
, &exts
->neigh_addr6
, 16);
413 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
414 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
415 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
416 stream_putf(s
, exts
->max_bw
);
418 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
419 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
420 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
421 stream_putf(s
, exts
->max_rsv_bw
);
423 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
424 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
425 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
426 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
427 stream_putf(s
, exts
->unrsv_bw
[j
]);
429 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
430 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
431 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
432 stream_put3(s
, exts
->te_metric
);
434 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
435 stream_putc(s
, ISIS_SUBTLV_RAS
);
436 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
437 stream_putl(s
, exts
->remote_as
);
439 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
440 stream_putc(s
, ISIS_SUBTLV_RIP
);
441 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
442 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
444 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
445 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
446 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
447 stream_putl(s
, exts
->delay
);
449 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
450 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
451 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
452 stream_putl(s
, exts
->min_delay
);
453 stream_putl(s
, exts
->max_delay
);
455 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
456 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
457 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
458 stream_putl(s
, exts
->delay_var
);
460 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
461 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
462 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
463 stream_putl(s
, exts
->pkt_loss
);
465 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
466 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
467 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
468 stream_putf(s
, exts
->res_bw
);
470 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
471 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
472 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
473 stream_putf(s
, exts
->ava_bw
);
475 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
476 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
477 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
478 stream_putf(s
, exts
->use_bw
);
480 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
481 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
482 struct isis_adj_sid
*adj
;
484 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
486 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
487 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
488 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
490 stream_putc(s
, size
);
491 stream_putc(s
, adj
->flags
);
492 stream_putc(s
, adj
->weight
);
493 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
494 stream_put3(s
, adj
->sid
);
496 stream_putl(s
, adj
->sid
);
500 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
501 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
502 struct isis_lan_adj_sid
*lan
;
504 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
506 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
507 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
508 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
510 stream_putc(s
, size
);
511 stream_putc(s
, lan
->flags
);
512 stream_putc(s
, lan
->weight
);
513 stream_put(s
, lan
->neighbor_id
, 6);
514 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
515 stream_put3(s
, lan
->sid
);
517 stream_putl(s
, lan
->sid
);
524 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
525 struct sbuf
*log
, void *dest
, int indent
)
531 struct isis_extended_reach
*rv
= dest
;
532 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
537 * Parse subTLVs until reach subTLV length
538 * Check that it remains at least 2 bytes: subTLV Type & Length
540 while (len
> sum
+ 2) {
541 /* Read SubTLV Type and Length */
542 subtlv_type
= stream_getc(s
);
543 subtlv_len
= stream_getc(s
);
544 if (subtlv_len
> len
- sum
) {
545 sbuf_push(log
, indent
, "TLV %" PRIu8
": Available data %" PRIu8
" is less than TLV size %u !\n",
546 subtlv_type
, len
- sum
, subtlv_len
);
550 switch (subtlv_type
) {
551 /* Standard Metric as defined in RFC5305 */
552 case ISIS_SUBTLV_ADMIN_GRP
:
553 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
554 sbuf_push(log
, indent
,
555 "TLV size does not match expected size for Administrative Group!\n");
557 exts
->adm_group
= stream_getl(s
);
558 SET_SUBTLV(exts
, EXT_ADM_GRP
);
561 case ISIS_SUBTLV_LLRI
:
562 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
563 sbuf_push(log
, indent
,
564 "TLV size does not match expected size for Link ID!\n");
566 exts
->local_llri
= stream_getl(s
);
567 exts
->remote_llri
= stream_getl(s
);
568 SET_SUBTLV(exts
, EXT_LLRI
);
571 case ISIS_SUBTLV_LOCAL_IPADDR
:
572 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
573 sbuf_push(log
, indent
,
574 "TLV size does not match expected size for Local IP address!\n");
576 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
577 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
580 case ISIS_SUBTLV_RMT_IPADDR
:
581 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
582 sbuf_push(log
, indent
,
583 "TLV size does not match expected size for Remote IP address!\n");
585 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
586 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
589 case ISIS_SUBTLV_LOCAL_IPADDR6
:
590 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
591 sbuf_push(log
, indent
,
592 "TLV size does not match expected size for Local IPv6 address!\n");
594 stream_get(&exts
->local_addr6
, s
, 16);
595 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
598 case ISIS_SUBTLV_RMT_IPADDR6
:
599 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
600 sbuf_push(log
, indent
,
601 "TLV size does not match expected size for Remote IPv6 address!\n");
603 stream_get(&exts
->neigh_addr6
, s
, 16);
604 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
607 case ISIS_SUBTLV_MAX_BW
:
608 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
609 sbuf_push(log
, indent
,
610 "TLV size does not match expected size for Maximum Bandwidth!\n");
612 exts
->max_bw
= stream_getf(s
);
613 SET_SUBTLV(exts
, EXT_MAX_BW
);
616 case ISIS_SUBTLV_MAX_RSV_BW
:
617 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
618 sbuf_push(log
, indent
,
619 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
621 exts
->max_rsv_bw
= stream_getf(s
);
622 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
625 case ISIS_SUBTLV_UNRSV_BW
:
626 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
627 sbuf_push(log
, indent
,
628 "TLV size does not match expected size for Unreserved Bandwidth!\n");
630 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
631 exts
->unrsv_bw
[i
] = stream_getf(s
);
632 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
635 case ISIS_SUBTLV_TE_METRIC
:
636 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
637 sbuf_push(log
, indent
,
638 "TLV size does not match expected size for Traffic Engineering Metric!\n");
640 exts
->te_metric
= stream_get3(s
);
641 SET_SUBTLV(exts
, EXT_TE_METRIC
);
644 case ISIS_SUBTLV_RAS
:
645 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
646 sbuf_push(log
, indent
,
647 "TLV size does not match expected size for Remote AS number!\n");
649 exts
->remote_as
= stream_getl(s
);
650 SET_SUBTLV(exts
, EXT_RMT_AS
);
653 case ISIS_SUBTLV_RIP
:
654 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
655 sbuf_push(log
, indent
,
656 "TLV size does not match expected size for Remote ASBR IP Address!\n");
658 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
659 SET_SUBTLV(exts
, EXT_RMT_IP
);
662 /* Extended Metrics as defined in RFC 7810 */
663 case ISIS_SUBTLV_AV_DELAY
:
664 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
665 sbuf_push(log
, indent
,
666 "TLV size does not match expected size for Average Link Delay!\n");
668 exts
->delay
= stream_getl(s
);
669 SET_SUBTLV(exts
, EXT_DELAY
);
672 case ISIS_SUBTLV_MM_DELAY
:
673 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
674 sbuf_push(log
, indent
,
675 "TLV size does not match expected size for Min/Max Link Delay!\n");
677 exts
->min_delay
= stream_getl(s
);
678 exts
->max_delay
= stream_getl(s
);
679 SET_SUBTLV(exts
, EXT_MM_DELAY
);
682 case ISIS_SUBTLV_DELAY_VAR
:
683 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
684 sbuf_push(log
, indent
,
685 "TLV size does not match expected size for Delay Variation!\n");
687 exts
->delay_var
= stream_getl(s
);
688 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
691 case ISIS_SUBTLV_PKT_LOSS
:
692 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
693 sbuf_push(log
, indent
,
694 "TLV size does not match expected size for Link Packet Loss!\n");
696 exts
->pkt_loss
= stream_getl(s
);
697 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
700 case ISIS_SUBTLV_RES_BW
:
701 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
702 sbuf_push(log
, indent
,
703 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
705 exts
->res_bw
= stream_getf(s
);
706 SET_SUBTLV(exts
, EXT_RES_BW
);
709 case ISIS_SUBTLV_AVA_BW
:
710 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
711 sbuf_push(log
, indent
,
712 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
714 exts
->ava_bw
= stream_getf(s
);
715 SET_SUBTLV(exts
, EXT_AVA_BW
);
718 case ISIS_SUBTLV_USE_BW
:
719 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
720 sbuf_push(log
, indent
,
721 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
723 exts
->use_bw
= stream_getf(s
);
724 SET_SUBTLV(exts
, EXT_USE_BW
);
727 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
728 case ISIS_SUBTLV_ADJ_SID
:
729 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
730 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
731 sbuf_push(log
, indent
,
732 "TLV size does not match expected size for Adjacency SID!\n");
734 struct isis_adj_sid
*adj
;
736 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
737 sizeof(struct isis_adj_sid
));
738 adj
->flags
= stream_getc(s
);
739 adj
->weight
= stream_getc(s
);
740 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
741 adj
->sid
= stream_get3(s
);
742 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
744 adj
->sid
= stream_getl(s
);
746 if (mtid
== ISIS_MT_IPV4_UNICAST
)
747 adj
->family
= AF_INET
;
748 if (mtid
== ISIS_MT_IPV6_UNICAST
)
749 adj
->family
= AF_INET6
;
750 append_item(&exts
->adj_sid
,
751 (struct isis_item
*)adj
);
752 SET_SUBTLV(exts
, EXT_ADJ_SID
);
755 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
756 case ISIS_SUBTLV_LAN_ADJ_SID
:
757 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
758 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
759 sbuf_push(log
, indent
,
760 "TLV size does not match expected size for LAN-Adjacency SID!\n");
762 struct isis_lan_adj_sid
*lan
;
764 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
765 sizeof(struct isis_lan_adj_sid
));
766 lan
->flags
= stream_getc(s
);
767 lan
->weight
= stream_getc(s
);
768 stream_get(&(lan
->neighbor_id
), s
,
770 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
771 lan
->sid
= stream_get3(s
);
772 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
774 lan
->sid
= stream_getl(s
);
776 if (mtid
== ISIS_MT_IPV4_UNICAST
)
777 lan
->family
= AF_INET
;
778 if (mtid
== ISIS_MT_IPV6_UNICAST
)
779 lan
->family
= AF_INET6
;
780 append_item(&exts
->lan_sid
,
781 (struct isis_item
*)lan
);
782 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
786 /* Skip unknown TLV */
787 stream_forward_getp(s
, subtlv_len
);
790 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
796 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
797 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
799 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
800 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
802 rv
->flags
= sid
->flags
;
803 rv
->algorithm
= sid
->algorithm
;
804 rv
->value
= sid
->value
;
805 return (struct isis_item
*)rv
;
808 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
809 struct sbuf
*buf
, int indent
)
811 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
813 sbuf_push(buf
, indent
, "SR Prefix-SID ");
814 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
815 sbuf_push(buf
, 0, "Label: %" PRIu32
", ", sid
->value
);
817 sbuf_push(buf
, 0, "Index: %" PRIu32
", ", sid
->value
);
819 sbuf_push(buf
, 0, "Algorithm: %" PRIu8
", ", sid
->algorithm
);
820 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
821 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
? " READVERTISED"
823 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
824 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP" : " PHP",
825 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
? " EXPLICIT-NULL"
827 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
828 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
831 static void free_item_prefix_sid(struct isis_item
*i
)
833 XFREE(MTYPE_ISIS_SUBTLV
, i
);
836 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
)
838 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
840 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
842 if (STREAM_WRITEABLE(s
) < size
)
845 stream_putc(s
, sid
->flags
);
846 stream_putc(s
, sid
->algorithm
);
848 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
849 stream_put3(s
, sid
->value
);
851 stream_putl(s
, sid
->value
);
857 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
858 struct sbuf
*log
, void *dest
, int indent
)
860 struct isis_subtlvs
*subtlvs
= dest
;
861 struct isis_prefix_sid sid
= {
864 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
867 sbuf_push(log
, indent
,
868 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
873 sid
.flags
= stream_getc(s
);
874 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
875 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
876 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
880 sid
.algorithm
= stream_getc(s
);
882 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
883 ? ISIS_SUBTLV_PREFIX_SID_SIZE
884 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
885 if (len
!= expected_size
) {
886 sbuf_push(log
, indent
,
887 "TLV size differs from expected size. "
888 "(expected %u but got %" PRIu8
")\n",
893 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
894 sid
.value
= stream_get3(s
);
895 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
896 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
901 sid
.value
= stream_getl(s
);
904 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, indent
+ 2);
905 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
909 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
911 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
916 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
917 rv
->family
= p
->family
;
918 rv
->prefixlen
= p
->prefixlen
;
919 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
923 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
924 struct sbuf
*buf
, int indent
)
929 char prefixbuf
[PREFIX2STR_BUFFER
];
930 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
931 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
934 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
940 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
943 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
944 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
945 stream_putc(s
, p
->prefixlen
);
946 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
950 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
951 uint8_t tlv_type
, uint8_t tlv_len
,
952 struct stream
*s
, struct sbuf
*log
,
953 void *dest
, int indent
)
955 struct isis_subtlvs
*subtlvs
= dest
;
956 struct prefix_ipv6 p
= {
960 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
963 sbuf_push(log
, indent
,
964 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
")\n",
969 p
.prefixlen
= stream_getc(s
);
970 if (p
.prefixlen
> 128) {
971 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
976 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
979 "TLV size differs from expected size for the prefixlen. "
980 "(expected %u but got %" PRIu8
")\n",
981 1 + PSIZE(p
.prefixlen
), tlv_len
);
985 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
987 if (subtlvs
->source_prefix
) {
990 "WARNING: source prefix Sub-TLV present multiple times.\n");
991 /* Ignore all but first occurrence of the source prefix Sub-TLV
996 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
997 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1001 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1002 enum isis_tlv_type type
,
1003 struct isis_item
*item
);
1004 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1005 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1006 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1007 enum isis_tlv_type type
, struct isis_item_list
*items
,
1008 struct sbuf
*buf
, int indent
);
1009 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1010 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1011 struct isis_item_list
*items
);
1012 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1013 enum isis_tlv_type type
, struct isis_item_list
*items
,
1014 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1015 const struct pack_order_entry
*pe
,
1016 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1017 struct list
*new_fragment_arg
);
1018 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1020 /* Functions related to subtlvs */
1022 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1024 struct isis_subtlvs
*result
;
1026 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1027 result
->context
= context
;
1029 init_item_list(&result
->prefix_sids
);
1034 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1039 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1041 rv
->context
= subtlvs
->context
;
1043 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1044 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1047 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1051 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1054 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1055 &subtlvs
->prefix_sids
, buf
, indent
);
1057 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
1060 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1065 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1066 &subtlvs
->prefix_sids
);
1068 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1070 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1073 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1076 size_t subtlv_len_pos
= stream_get_endp(s
);
1078 if (STREAM_WRITEABLE(s
) < 1)
1081 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1083 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1084 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1088 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1092 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1093 if (subtlv_len
> 255)
1096 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1100 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1101 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1102 int indent
, bool *unpacked_known_tlvs
);
1104 /* Functions related to TLVs 1 Area Addresses */
1106 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1108 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1109 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1111 rv
->len
= addr
->len
;
1112 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1113 return (struct isis_item
*)rv
;
1116 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1117 struct sbuf
*buf
, int indent
)
1119 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1121 sbuf_push(buf
, indent
, "Area Address: %s\n",
1122 isonet_print(addr
->addr
, addr
->len
));
1125 static void free_item_area_address(struct isis_item
*i
)
1127 XFREE(MTYPE_ISIS_TLV
, i
);
1130 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
1132 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1134 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
1136 stream_putc(s
, addr
->len
);
1137 stream_put(s
, addr
->addr
, addr
->len
);
1141 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1142 struct stream
*s
, struct sbuf
*log
,
1143 void *dest
, int indent
)
1145 struct isis_tlvs
*tlvs
= dest
;
1146 struct isis_area_address
*rv
= NULL
;
1148 sbuf_push(log
, indent
, "Unpack area address...\n");
1152 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
1158 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1159 rv
->len
= stream_getc(s
);
1161 if (len
< 1 + rv
->len
) {
1162 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
1163 " bytes of address, got %" PRIu8
")\n",
1168 if (rv
->len
< 1 || rv
->len
> 20) {
1169 sbuf_push(log
, indent
,
1170 "Implausible area address length %" PRIu8
"\n",
1175 stream_get(rv
->addr
, s
, rv
->len
);
1177 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1179 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1182 XFREE(MTYPE_ISIS_TLV
, rv
);
1186 /* Functions related to TLV 2 (Old-Style) IS Reach */
1187 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1189 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1190 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1192 memcpy(rv
->id
, r
->id
, 7);
1193 rv
->metric
= r
->metric
;
1194 return (struct isis_item
*)rv
;
1197 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1198 struct sbuf
*buf
, int indent
)
1200 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1202 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
1203 isis_format_id(r
->id
, 7), r
->metric
);
1206 static void free_item_oldstyle_reach(struct isis_item
*i
)
1208 XFREE(MTYPE_ISIS_TLV
, i
);
1211 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
1213 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1215 if (STREAM_WRITEABLE(s
) < 11)
1218 stream_putc(s
, r
->metric
);
1219 stream_putc(s
, 0x80); /* delay metric - unsupported */
1220 stream_putc(s
, 0x80); /* expense metric - unsupported */
1221 stream_putc(s
, 0x80); /* error metric - unsupported */
1222 stream_put(s
, r
->id
, 7);
1227 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1228 struct stream
*s
, struct sbuf
*log
,
1229 void *dest
, int indent
)
1231 struct isis_tlvs
*tlvs
= dest
;
1233 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1237 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
1243 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1244 rv
->metric
= stream_getc(s
);
1245 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1246 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1249 stream_forward_getp(s
, 3); /* Skip other metrics */
1250 stream_get(rv
->id
, s
, 7);
1252 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
1254 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1258 /* Functions related to TLV 6 LAN Neighbors */
1259 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1261 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1262 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1264 memcpy(rv
->mac
, n
->mac
, 6);
1265 return (struct isis_item
*)rv
;
1268 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1269 struct sbuf
*buf
, int indent
)
1271 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1273 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
1276 static void free_item_lan_neighbor(struct isis_item
*i
)
1278 XFREE(MTYPE_ISIS_TLV
, i
);
1281 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
1283 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1285 if (STREAM_WRITEABLE(s
) < 6)
1288 stream_put(s
, n
->mac
, 6);
1293 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1294 struct stream
*s
, struct sbuf
*log
,
1295 void *dest
, int indent
)
1297 struct isis_tlvs
*tlvs
= dest
;
1299 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1303 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
1309 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1310 stream_get(rv
->mac
, s
, 6);
1312 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1313 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1317 /* Functions related to TLV 9 LSP Entry */
1318 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1320 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1321 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1323 rv
->rem_lifetime
= e
->rem_lifetime
;
1324 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1325 rv
->seqno
= e
->seqno
;
1326 rv
->checksum
= e
->checksum
;
1328 return (struct isis_item
*)rv
;
1331 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1332 struct sbuf
*buf
, int indent
)
1334 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1336 sbuf_push(buf
, indent
,
1337 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1338 ", lifetime %" PRIu16
"s\n",
1339 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1343 static void free_item_lsp_entry(struct isis_item
*i
)
1345 XFREE(MTYPE_ISIS_TLV
, i
);
1348 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
1350 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1352 if (STREAM_WRITEABLE(s
) < 16)
1355 stream_putw(s
, e
->rem_lifetime
);
1356 stream_put(s
, e
->id
, 8);
1357 stream_putl(s
, e
->seqno
);
1358 stream_putw(s
, e
->checksum
);
1363 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1364 struct sbuf
*log
, void *dest
, int indent
)
1366 struct isis_tlvs
*tlvs
= dest
;
1368 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1372 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
1377 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1378 rv
->rem_lifetime
= stream_getw(s
);
1379 stream_get(rv
->id
, s
, 8);
1380 rv
->seqno
= stream_getl(s
);
1381 rv
->checksum
= stream_getw(s
);
1383 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1384 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1388 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1390 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1392 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1393 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1395 memcpy(rv
->id
, r
->id
, 7);
1396 rv
->metric
= r
->metric
;
1399 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1401 return (struct isis_item
*)rv
;
1404 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1405 struct sbuf
*buf
, int indent
)
1407 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1409 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1410 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1411 isis_format_id(r
->id
, 7), r
->metric
);
1412 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1413 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1414 sbuf_push(buf
, 0, "\n");
1417 format_item_ext_subtlvs(r
->subtlvs
, buf
, indent
+ 2, mtid
);
1420 static void free_item_extended_reach(struct isis_item
*i
)
1422 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1423 if (item
->subtlvs
!= NULL
)
1424 free_item_ext_subtlvs(item
->subtlvs
);
1425 XFREE(MTYPE_ISIS_TLV
, item
);
1428 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
1430 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1434 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
)
1437 stream_put(s
, r
->id
, sizeof(r
->id
));
1438 stream_put3(s
, r
->metric
);
1439 len_pos
= stream_get_endp(s
);
1440 /* Real length will be adjust after adding subTLVs */
1443 pack_item_ext_subtlvs(r
->subtlvs
, s
);
1445 len
= stream_get_endp(s
) - len_pos
- 1;
1446 stream_putc_at(s
, len_pos
, len
);
1450 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1451 struct stream
*s
, struct sbuf
*log
,
1452 void *dest
, int indent
)
1454 struct isis_tlvs
*tlvs
= dest
;
1455 struct isis_extended_reach
*rv
= NULL
;
1457 struct isis_item_list
*items
;
1459 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1460 items
= &tlvs
->extended_reach
;
1462 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1465 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1466 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1469 sbuf_push(log
, indent
,
1470 "Not enough data left. (expected 11 or more bytes, got %"
1476 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1477 stream_get(rv
->id
, s
, 7);
1478 rv
->metric
= stream_get3(s
);
1479 subtlv_len
= stream_getc(s
);
1481 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1482 sbuf_push(log
, indent
,
1483 "Not enough data left for subtlv size %" PRIu8
1484 ", there are only %" PRIu8
" bytes left.\n",
1485 subtlv_len
, len
- 11);
1489 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
1493 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1499 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
1501 append_item(items
, (struct isis_item
*)rv
);
1505 free_item_extended_reach((struct isis_item
*)rv
);
1510 /* Functions related to TLV 128 (Old-Style) IP Reach */
1511 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1513 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1514 struct isis_oldstyle_ip_reach
*rv
=
1515 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1517 rv
->metric
= r
->metric
;
1518 rv
->prefix
= r
->prefix
;
1519 return (struct isis_item
*)rv
;
1522 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1523 struct sbuf
*buf
, int indent
)
1525 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1526 char prefixbuf
[PREFIX2STR_BUFFER
];
1528 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
1529 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1533 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
1535 XFREE(MTYPE_ISIS_TLV
, i
);
1538 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
1540 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1542 if (STREAM_WRITEABLE(s
) < 12)
1545 stream_putc(s
, r
->metric
);
1546 stream_putc(s
, 0x80); /* delay metric - unsupported */
1547 stream_putc(s
, 0x80); /* expense metric - unsupported */
1548 stream_putc(s
, 0x80); /* error metric - unsupported */
1549 stream_put(s
, &r
->prefix
.prefix
, 4);
1551 struct in_addr mask
;
1552 masklen2ip(r
->prefix
.prefixlen
, &mask
);
1553 stream_put(s
, &mask
, sizeof(mask
));
1558 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
1559 struct stream
*s
, struct sbuf
*log
,
1560 void *dest
, int indent
)
1562 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
1566 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
1572 struct isis_oldstyle_ip_reach
*rv
=
1573 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1574 rv
->metric
= stream_getc(s
);
1575 if ((rv
->metric
& 0x7f) != rv
->metric
) {
1576 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1579 stream_forward_getp(s
, 3); /* Skip other metrics */
1580 rv
->prefix
.family
= AF_INET
;
1581 stream_get(&rv
->prefix
.prefix
, s
, 4);
1583 struct in_addr mask
;
1584 stream_get(&mask
, s
, 4);
1585 rv
->prefix
.prefixlen
= ip_masklen(mask
);
1587 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1589 append_item(dest
, (struct isis_item
*)rv
);
1594 /* Functions related to TLV 129 protocols supported */
1596 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
1597 struct isis_protocols_supported
*dest
)
1599 if (!src
->protocols
|| !src
->count
)
1601 dest
->count
= src
->count
;
1602 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
1603 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
1606 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
1607 struct sbuf
*buf
, int indent
)
1609 if (!p
|| !p
->count
|| !p
->protocols
)
1612 sbuf_push(buf
, indent
, "Protocols Supported: ");
1613 for (uint8_t i
= 0; i
< p
->count
; i
++) {
1614 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
1615 (i
+ 1 < p
->count
) ? ", " : "");
1617 sbuf_push(buf
, 0, "\n");
1620 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
1622 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
1625 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
1628 if (!p
|| !p
->count
|| !p
->protocols
)
1631 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
1634 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
1635 stream_putc(s
, p
->count
);
1636 stream_put(s
, p
->protocols
, p
->count
);
1640 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
1641 uint8_t tlv_type
, uint8_t tlv_len
,
1642 struct stream
*s
, struct sbuf
*log
,
1643 void *dest
, int indent
)
1645 struct isis_tlvs
*tlvs
= dest
;
1647 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
1649 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
1652 if (tlvs
->protocols_supported
.protocols
) {
1655 "WARNING: protocols supported TLV present multiple times.\n");
1656 stream_forward_getp(s
, tlv_len
);
1660 tlvs
->protocols_supported
.count
= tlv_len
;
1661 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
1662 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
1664 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
1669 /* Functions related to TLV 132 IPv4 Interface addresses */
1670 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
1672 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1673 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1676 return (struct isis_item
*)rv
;
1679 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
1680 struct sbuf
*buf
, int indent
)
1682 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1683 char addrbuf
[INET_ADDRSTRLEN
];
1685 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1686 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
1689 static void free_item_ipv4_address(struct isis_item
*i
)
1691 XFREE(MTYPE_ISIS_TLV
, i
);
1694 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
1696 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1698 if (STREAM_WRITEABLE(s
) < 4)
1701 stream_put(s
, &a
->addr
, 4);
1706 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
1707 struct stream
*s
, struct sbuf
*log
,
1708 void *dest
, int indent
)
1710 struct isis_tlvs
*tlvs
= dest
;
1712 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
1716 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
1722 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1723 stream_get(&rv
->addr
, s
, 4);
1725 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1726 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
1731 /* Functions related to TLV 232 IPv6 Interface addresses */
1732 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
1734 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1735 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1738 return (struct isis_item
*)rv
;
1741 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
1742 struct sbuf
*buf
, int indent
)
1744 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1745 char addrbuf
[INET6_ADDRSTRLEN
];
1747 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1748 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
1751 static void free_item_ipv6_address(struct isis_item
*i
)
1753 XFREE(MTYPE_ISIS_TLV
, i
);
1756 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
1758 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1760 if (STREAM_WRITEABLE(s
) < 16)
1763 stream_put(s
, &a
->addr
, 16);
1768 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
1769 struct stream
*s
, struct sbuf
*log
,
1770 void *dest
, int indent
)
1772 struct isis_tlvs
*tlvs
= dest
;
1774 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
1778 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
1784 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1785 stream_get(&rv
->addr
, s
, 16);
1787 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1788 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
1793 /* Functions related to TLV 229 MT Router information */
1794 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
1796 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1797 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1799 rv
->overload
= info
->overload
;
1800 rv
->attached
= info
->attached
;
1801 rv
->mtid
= info
->mtid
;
1802 return (struct isis_item
*)rv
;
1805 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
1806 struct sbuf
*buf
, int indent
)
1808 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1810 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
1811 isis_mtid2str(info
->mtid
),
1812 info
->overload
? " Overload" : "",
1813 info
->attached
? " Attached" : "");
1816 static void free_item_mt_router_info(struct isis_item
*i
)
1818 XFREE(MTYPE_ISIS_TLV
, i
);
1821 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
1823 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1825 if (STREAM_WRITEABLE(s
) < 2)
1828 uint16_t entry
= info
->mtid
;
1831 entry
|= ISIS_MT_OL_MASK
;
1833 entry
|= ISIS_MT_AT_MASK
;
1835 stream_putw(s
, entry
);
1840 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1841 struct stream
*s
, struct sbuf
*log
,
1842 void *dest
, int indent
)
1844 struct isis_tlvs
*tlvs
= dest
;
1846 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1850 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1856 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1858 uint16_t entry
= stream_getw(s
);
1859 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1860 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1861 rv
->mtid
= entry
& ISIS_MT_MASK
;
1863 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1865 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1869 /* Functions related to TLV 134 TE Router ID */
1871 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1876 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1877 memcpy(rv
, id
, sizeof(*rv
));
1881 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1887 char addrbuf
[INET_ADDRSTRLEN
];
1888 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1889 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1892 static void free_tlv_te_router_id(struct in_addr
*id
)
1894 XFREE(MTYPE_ISIS_TLV
, id
);
1897 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1902 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1905 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1907 stream_put(s
, id
, 4);
1911 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1912 uint8_t tlv_type
, uint8_t tlv_len
,
1913 struct stream
*s
, struct sbuf
*log
,
1914 void *dest
, int indent
)
1916 struct isis_tlvs
*tlvs
= dest
;
1918 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1920 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1924 if (tlvs
->te_router_id
) {
1925 sbuf_push(log
, indent
,
1926 "WARNING: TE Router ID present multiple times.\n");
1927 stream_forward_getp(s
, tlv_len
);
1931 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1932 stream_get(tlvs
->te_router_id
, s
, 4);
1933 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1938 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1940 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1942 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1943 struct isis_extended_ip_reach
*rv
=
1944 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1946 rv
->metric
= r
->metric
;
1948 rv
->prefix
= r
->prefix
;
1949 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1951 return (struct isis_item
*)rv
;
1954 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1955 struct sbuf
*buf
, int indent
)
1957 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1958 char prefixbuf
[PREFIX2STR_BUFFER
];
1960 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1961 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1962 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1963 r
->down
? " Down" : "");
1964 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1965 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1966 sbuf_push(buf
, 0, "\n");
1969 sbuf_push(buf
, indent
, " Subtlvs:\n");
1970 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1974 static void free_item_extended_ip_reach(struct isis_item
*i
)
1976 struct isis_extended_ip_reach
*item
=
1977 (struct isis_extended_ip_reach
*)i
;
1978 isis_free_subtlvs(item
->subtlvs
);
1979 XFREE(MTYPE_ISIS_TLV
, item
);
1982 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1984 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1987 if (STREAM_WRITEABLE(s
) < 5)
1989 stream_putl(s
, r
->metric
);
1991 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1992 control
|= r
->prefix
.prefixlen
;
1993 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
1995 stream_putc(s
, control
);
1997 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1999 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2002 return pack_subtlvs(r
->subtlvs
, s
);
2006 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2007 struct stream
*s
, struct sbuf
*log
,
2008 void *dest
, int indent
)
2010 struct isis_tlvs
*tlvs
= dest
;
2011 struct isis_extended_ip_reach
*rv
= NULL
;
2013 uint8_t control
, subtlv_len
;
2014 struct isis_item_list
*items
;
2016 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2017 items
= &tlvs
->extended_ip_reach
;
2019 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2022 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2023 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2026 if (len
< consume
) {
2027 sbuf_push(log
, indent
,
2028 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
2033 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2035 rv
->metric
= stream_getl(s
);
2036 control
= stream_getc(s
);
2037 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2038 rv
->prefix
.family
= AF_INET
;
2039 rv
->prefix
.prefixlen
= control
& 0x3f;
2040 if (rv
->prefix
.prefixlen
> 32) {
2041 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2042 rv
->prefix
.prefixlen
);
2046 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2047 if (len
< consume
) {
2048 sbuf_push(log
, indent
,
2049 "Expected %u bytes of prefix, but only %u bytes available.\n",
2050 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2053 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2054 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2055 apply_mask_ipv4(&rv
->prefix
);
2056 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2057 sbuf_push(log
, indent
+ 2,
2058 "WARNING: Prefix had hostbits set.\n");
2059 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
2062 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2064 if (len
< consume
) {
2065 sbuf_push(log
, indent
,
2066 "Expected 1 byte of subtlv len, but no more data present.\n");
2069 subtlv_len
= stream_getc(s
);
2072 sbuf_push(log
, indent
+ 2,
2073 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2075 consume
+= subtlv_len
;
2076 if (len
< consume
) {
2077 sbuf_push(log
, indent
,
2079 " bytes of subtlvs, but only %u bytes available.\n",
2081 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2085 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2086 bool unpacked_known_tlvs
= false;
2088 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2089 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2092 if (!unpacked_known_tlvs
) {
2093 isis_free_subtlvs(rv
->subtlvs
);
2098 append_item(items
, (struct isis_item
*)rv
);
2102 free_item_extended_ip_reach((struct isis_item
*)rv
);
2106 /* Functions related to TLV 137 Dynamic Hostname */
2108 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2113 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2116 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2122 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2125 static void free_tlv_dynamic_hostname(char *hostname
)
2127 XFREE(MTYPE_ISIS_TLV
, hostname
);
2130 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2135 uint8_t name_len
= strlen(hostname
);
2137 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2140 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2141 stream_putc(s
, name_len
);
2142 stream_put(s
, hostname
, name_len
);
2146 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2147 uint8_t tlv_type
, uint8_t tlv_len
,
2148 struct stream
*s
, struct sbuf
*log
,
2149 void *dest
, int indent
)
2151 struct isis_tlvs
*tlvs
= dest
;
2153 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2155 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2159 if (tlvs
->hostname
) {
2160 sbuf_push(log
, indent
,
2161 "WARNING: Hostname present multiple times.\n");
2162 stream_forward_getp(s
, tlv_len
);
2166 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2167 stream_get(tlvs
->hostname
, s
, tlv_len
);
2168 tlvs
->hostname
[tlv_len
] = '\0';
2171 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2172 if ((unsigned char)tlvs
->hostname
[i
] > 127
2173 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2175 tlvs
->hostname
[i
] = '?';
2181 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2187 /* Functions related to TLV 150 Spine-Leaf-Extension */
2189 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2190 const struct isis_spine_leaf
*spine_leaf
)
2195 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2196 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2201 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2202 struct sbuf
*buf
, int indent
)
2207 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2208 if (spine_leaf
->has_tier
) {
2209 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2210 sbuf_push(buf
, indent
, " Tier: undefined\n");
2212 sbuf_push(buf
, indent
, " Tier: %" PRIu8
"\n",
2217 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2218 spine_leaf
->is_leaf
? " LEAF" : "",
2219 spine_leaf
->is_spine
? " SPINE" : "",
2220 spine_leaf
->is_backup
? " BACKUP" : "");
2224 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2226 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2229 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2230 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2231 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2232 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2234 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2240 uint8_t tlv_len
= 2;
2242 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2245 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2246 stream_putc(s
, tlv_len
);
2248 uint16_t spine_leaf_flags
= 0;
2250 if (spine_leaf
->has_tier
) {
2251 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2252 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2255 if (spine_leaf
->is_leaf
)
2256 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2258 if (spine_leaf
->is_spine
)
2259 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
2261 if (spine_leaf
->is_backup
)
2262 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
2264 stream_putw(s
, spine_leaf_flags
);
2269 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
2270 uint8_t tlv_type
, uint8_t tlv_len
,
2271 struct stream
*s
, struct sbuf
*log
,
2272 void *dest
, int indent
)
2274 struct isis_tlvs
*tlvs
= dest
;
2276 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
2278 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2279 stream_forward_getp(s
, tlv_len
);
2283 if (tlvs
->spine_leaf
) {
2284 sbuf_push(log
, indent
,
2285 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
2286 stream_forward_getp(s
, tlv_len
);
2290 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
2292 uint16_t spine_leaf_flags
= stream_getw(s
);
2294 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
2295 tlvs
->spine_leaf
->has_tier
= true;
2296 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
2299 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
2300 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
2301 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
2303 stream_forward_getp(s
, tlv_len
- 2);
2307 /* Functions related to TLV 240 P2P Three-Way Adjacency */
2309 const char *isis_threeway_state_name(enum isis_threeway_state state
)
2312 case ISIS_THREEWAY_DOWN
:
2314 case ISIS_THREEWAY_INITIALIZING
:
2315 return "Initializing";
2316 case ISIS_THREEWAY_UP
:
2323 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
2324 const struct isis_threeway_adj
*threeway_adj
)
2329 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2330 memcpy(rv
, threeway_adj
, sizeof(*rv
));
2335 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
2336 struct sbuf
*buf
, int indent
)
2341 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
2342 sbuf_push(buf
, indent
, " State: %s (%d)\n",
2343 isis_threeway_state_name(threeway_adj
->state
),
2344 threeway_adj
->state
);
2345 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %" PRIu32
"\n",
2346 threeway_adj
->local_circuit_id
);
2347 if (!threeway_adj
->neighbor_set
)
2350 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
2351 isis_format_id(threeway_adj
->neighbor_id
, 6));
2352 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %" PRIu32
"\n",
2353 threeway_adj
->neighbor_circuit_id
);
2356 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
2358 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
2361 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
2367 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
2369 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2372 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
2373 stream_putc(s
, tlv_len
);
2374 stream_putc(s
, threeway_adj
->state
);
2375 stream_putl(s
, threeway_adj
->local_circuit_id
);
2377 if (threeway_adj
->neighbor_set
) {
2378 stream_put(s
, threeway_adj
->neighbor_id
, 6);
2379 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
2385 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
2386 uint8_t tlv_type
, uint8_t tlv_len
,
2387 struct stream
*s
, struct sbuf
*log
,
2388 void *dest
, int indent
)
2390 struct isis_tlvs
*tlvs
= dest
;
2392 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
2393 if (tlv_len
!= 5 && tlv_len
!= 15) {
2394 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2395 stream_forward_getp(s
, tlv_len
);
2399 if (tlvs
->threeway_adj
) {
2400 sbuf_push(log
, indent
,
2401 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
2402 stream_forward_getp(s
, tlv_len
);
2406 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
2408 tlvs
->threeway_adj
->state
= stream_getc(s
);
2409 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
2411 if (tlv_len
== 15) {
2412 tlvs
->threeway_adj
->neighbor_set
= true;
2413 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
2414 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
2420 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
2422 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
2424 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2425 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2426 rv
->metric
= r
->metric
;
2428 rv
->external
= r
->external
;
2429 rv
->prefix
= r
->prefix
;
2430 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2432 return (struct isis_item
*)rv
;
2435 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
2436 struct sbuf
*buf
, int indent
)
2438 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2439 char prefixbuf
[PREFIX2STR_BUFFER
];
2441 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
2442 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
2443 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2445 r
->down
? " Down" : "",
2446 r
->external
? " External" : "");
2447 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2448 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2449 sbuf_push(buf
, 0, "\n");
2452 sbuf_push(buf
, indent
, " Subtlvs:\n");
2453 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
2457 static void free_item_ipv6_reach(struct isis_item
*i
)
2459 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
2461 isis_free_subtlvs(item
->subtlvs
);
2462 XFREE(MTYPE_ISIS_TLV
, item
);
2465 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
2467 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2470 if (STREAM_WRITEABLE(s
) < 6)
2472 stream_putl(s
, r
->metric
);
2474 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
2475 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
2476 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
2478 stream_putc(s
, control
);
2479 stream_putc(s
, r
->prefix
.prefixlen
);
2481 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
2483 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
2486 return pack_subtlvs(r
->subtlvs
, s
);
2491 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
2492 struct sbuf
*log
, void *dest
, int indent
)
2494 struct isis_tlvs
*tlvs
= dest
;
2495 struct isis_ipv6_reach
*rv
= NULL
;
2497 uint8_t control
, subtlv_len
;
2498 struct isis_item_list
*items
;
2500 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2501 items
= &tlvs
->ipv6_reach
;
2503 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
2506 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
2507 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
2509 if (len
< consume
) {
2510 sbuf_push(log
, indent
,
2511 "Not enough data left. (expected 6 or more bytes, got %"
2517 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2519 rv
->metric
= stream_getl(s
);
2520 control
= stream_getc(s
);
2521 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
2522 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
2524 rv
->prefix
.family
= AF_INET6
;
2525 rv
->prefix
.prefixlen
= stream_getc(s
);
2526 if (rv
->prefix
.prefixlen
> 128) {
2527 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
2528 rv
->prefix
.prefixlen
);
2532 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2533 if (len
< consume
) {
2534 sbuf_push(log
, indent
,
2535 "Expected %u bytes of prefix, but only %u bytes available.\n",
2536 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
2539 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2540 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
2542 apply_mask_ipv6(&rv
->prefix
);
2543 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
2544 sbuf_push(log
, indent
+ 2,
2545 "WARNING: Prefix had hostbits set.\n");
2546 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2548 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
2550 if (len
< consume
) {
2551 sbuf_push(log
, indent
,
2552 "Expected 1 byte of subtlv len, but no more data persent.\n");
2555 subtlv_len
= stream_getc(s
);
2558 sbuf_push(log
, indent
+ 2,
2559 " WARNING: subtlv bit set, but there are no subtlvs.\n");
2561 consume
+= subtlv_len
;
2562 if (len
< consume
) {
2563 sbuf_push(log
, indent
,
2565 " bytes of subtlvs, but only %u bytes available.\n",
2567 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2571 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
2572 bool unpacked_known_tlvs
= false;
2574 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
2575 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2578 if (!unpacked_known_tlvs
) {
2579 isis_free_subtlvs(rv
->subtlvs
);
2584 append_item(items
, (struct isis_item
*)rv
);
2588 free_item_ipv6_reach((struct isis_item
*)rv
);
2592 /* Functions related to TLV 242 Router Capability as per RFC7981 */
2593 static struct isis_router_cap
*copy_tlv_router_cap(
2594 const struct isis_router_cap
*router_cap
)
2596 struct isis_router_cap
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2601 memcpy(rv
, router_cap
, sizeof(*rv
));
2606 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
2607 struct sbuf
*buf
, int indent
)
2609 char addrbuf
[INET_ADDRSTRLEN
];
2614 /* Router ID and Flags */
2615 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
2616 sbuf_push(buf
, indent
, "Router Capability:");
2617 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
2618 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
2619 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
2621 /* Segment Routing Global Block as per RFC8667 section #3.1 */
2622 if (router_cap
->srgb
.range_size
!= 0)
2625 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
2626 IS_SR_IPV4(router_cap
->srgb
) ? "1" : "0",
2627 IS_SR_IPV6(router_cap
->srgb
) ? "1" : "0",
2628 router_cap
->srgb
.lower_bound
,
2629 router_cap
->srgb
.range_size
);
2631 /* Segment Routing Local Block as per RFC8667 section #3.3 */
2632 if (router_cap
->srlb
.range_size
!= 0)
2633 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
2634 router_cap
->srlb
.lower_bound
,
2635 router_cap
->srlb
.range_size
);
2637 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
2638 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
2639 sbuf_push(buf
, indent
, " SR Algorithm:\n");
2640 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
2641 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
2642 sbuf_push(buf
, indent
, " %u: %s\n", i
,
2643 router_cap
->algo
[i
] == 0
2648 /* Segment Routing Node MSD as per RFC8491 section #2 */
2649 if (router_cap
->msd
!= 0)
2650 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
2654 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
2656 XFREE(MTYPE_ISIS_TLV
, router_cap
);
2659 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
2662 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
2669 /* Compute Maximum TLV size */
2670 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
2671 + ISIS_SUBTLV_HDR_SIZE
2672 + ISIS_SUBTLV_ALGORITHM_SIZE
2673 + ISIS_SUBTLV_NODE_MSD_SIZE
;
2675 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
2678 /* Add Router Capability TLV 242 with Router ID and Flags */
2679 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
2680 /* Real length will be adjusted later */
2681 len_pos
= stream_get_endp(s
);
2682 stream_putc(s
, tlv_len
);
2683 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
2684 stream_putc(s
, router_cap
->flags
);
2686 /* Add SRGB if set as per RFC8667 section #3.1 */
2687 if ((router_cap
->srgb
.range_size
!= 0)
2688 && (router_cap
->srgb
.lower_bound
!= 0)) {
2689 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
2690 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
2691 stream_putc(s
, router_cap
->srgb
.flags
);
2692 stream_put3(s
, router_cap
->srgb
.range_size
);
2693 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
2694 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
2695 stream_put3(s
, router_cap
->srgb
.lower_bound
);
2697 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
2698 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
2699 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
2702 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
2703 stream_putc(s
, nb_algo
);
2704 for (int i
= 0; i
< nb_algo
; i
++)
2705 stream_putc(s
, router_cap
->algo
[i
]);
2708 /* Local Block if defined as per RFC8667 section #3.3 */
2709 if ((router_cap
->srlb
.range_size
!= 0)
2710 && (router_cap
->srlb
.lower_bound
!= 0)) {
2711 stream_putc(s
, ISIS_SUBTLV_SRLB
);
2712 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
2713 /* No Flags are defined for SRLB */
2715 stream_put3(s
, router_cap
->srlb
.range_size
);
2716 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
2717 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
2718 stream_put3(s
, router_cap
->srlb
.lower_bound
);
2721 /* And finish with MSD if set as per RFC8491 section #2 */
2722 if (router_cap
->msd
!= 0) {
2723 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
2724 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
2725 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
2726 stream_putc(s
, router_cap
->msd
);
2730 /* Adjust TLV length which depends on subTLVs presence */
2731 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
2732 stream_putc_at(s
, len_pos
, tlv_len
);
2737 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
2738 uint8_t tlv_type
, uint8_t tlv_len
,
2739 struct stream
*s
, struct sbuf
*log
,
2740 void *dest
, int indent
)
2742 struct isis_tlvs
*tlvs
= dest
;
2743 struct isis_router_cap
*rcap
;
2749 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
2750 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
2751 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2752 stream_forward_getp(s
, tlv_len
);
2756 if (tlvs
->router_cap
) {
2757 sbuf_push(log
, indent
,
2758 "WARNING: Router Capability TLV present multiple times.\n");
2759 stream_forward_getp(s
, tlv_len
);
2763 /* Allocate router cap structure and initialize SR Algorithms */
2764 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
2765 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
2766 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
2768 /* Get Router ID and Flags */
2769 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
2770 rcap
->flags
= stream_getc(s
);
2772 /* Parse remaining part of the TLV if present */
2773 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
2774 while (subtlv_len
> 2) {
2777 type
= stream_getc(s
);
2778 length
= stream_getc(s
);
2780 case ISIS_SUBTLV_SID_LABEL_RANGE
:
2781 /* Check that SRGB is correctly formated */
2782 if (length
< SUBTLV_RANGE_LABEL_SIZE
2783 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
2784 stream_forward_getp(s
, length
);
2787 /* Only one SRGB is supported. Skip subsequent one */
2788 if (rcap
->srgb
.range_size
!= 0) {
2789 stream_forward_getp(s
, length
);
2792 rcap
->srgb
.flags
= stream_getc(s
);
2793 rcap
->srgb
.range_size
= stream_get3(s
);
2794 /* Skip Type and get Length of SID Label */
2796 size
= stream_getc(s
);
2797 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
)
2798 rcap
->srgb
.lower_bound
= stream_get3(s
);
2800 rcap
->srgb
.lower_bound
= stream_getl(s
);
2802 /* SRGB sanity checks. */
2803 if (rcap
->srgb
.range_size
== 0
2804 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
2805 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
2806 > MPLS_LABEL_UNRESERVED_MAX
)) {
2807 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
2808 rcap
->srgb
.lower_bound
= 0;
2809 rcap
->srgb
.range_size
= 0;
2811 /* Only one range is supported. Skip subsequent one */
2812 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
2814 stream_forward_getp(s
, length
);
2816 case ISIS_SUBTLV_ALGORITHM
:
2817 /* Only 2 algorithms are supported: SPF & Strict SPF */
2818 stream_get(&rcap
->algo
, s
,
2819 length
> SR_ALGORITHM_COUNT
2820 ? SR_ALGORITHM_COUNT
2822 if (length
> SR_ALGORITHM_COUNT
)
2823 stream_forward_getp(
2824 s
, length
- SR_ALGORITHM_COUNT
);
2826 case ISIS_SUBTLV_SRLB
:
2827 /* Check that SRLB is correctly formated */
2828 if (length
< SUBTLV_RANGE_LABEL_SIZE
2829 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
2830 stream_forward_getp(s
, length
);
2833 /* RFC 8667 section #3.3: Only one SRLB is authorized */
2834 if (rcap
->srlb
.range_size
!= 0) {
2835 stream_forward_getp(s
, length
);
2838 /* Ignore Flags which are not defined */
2840 rcap
->srlb
.range_size
= stream_get3(s
);
2841 /* Skip Type and get Length of SID Label */
2843 size
= stream_getc(s
);
2844 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
)
2845 rcap
->srlb
.lower_bound
= stream_get3(s
);
2847 rcap
->srlb
.lower_bound
= stream_getl(s
);
2849 /* SRLB sanity checks. */
2850 if (rcap
->srlb
.range_size
== 0
2851 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
2852 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
2853 > MPLS_LABEL_UNRESERVED_MAX
)) {
2854 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
2855 rcap
->srlb
.lower_bound
= 0;
2856 rcap
->srlb
.range_size
= 0;
2858 /* Only one range is supported. Skip subsequent one */
2859 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
2861 stream_forward_getp(s
, length
);
2863 case ISIS_SUBTLV_NODE_MSD
:
2864 /* Check that MSD is correctly formated */
2865 if (length
< MSD_TLV_SIZE
) {
2866 stream_forward_getp(s
, length
);
2869 msd_type
= stream_getc(s
);
2870 rcap
->msd
= stream_getc(s
);
2871 /* Only BMI-MSD type has been defined in RFC 8491 */
2872 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
2874 /* Only one MSD is standardized. Skip others */
2875 if (length
> MSD_TLV_SIZE
)
2876 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
2879 stream_forward_getp(s
, length
);
2882 subtlv_len
= subtlv_len
- length
- 2;
2884 tlvs
->router_cap
= rcap
;
2888 /* Functions related to TLV 10 Authentication */
2889 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
2891 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2892 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2894 rv
->type
= auth
->type
;
2895 rv
->length
= auth
->length
;
2896 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
2897 return (struct isis_item
*)rv
;
2900 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
2901 struct sbuf
*buf
, int indent
)
2903 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2906 sbuf_push(buf
, indent
, "Authentication:\n");
2907 switch (auth
->type
) {
2908 case ISIS_PASSWD_TYPE_CLEARTXT
:
2909 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
2910 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
2912 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2913 for (unsigned int j
= 0; j
< 16; j
++) {
2914 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
,
2915 "%02" PRIx8
, auth
->value
[j
]);
2917 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
2920 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
2925 static void free_item_auth(struct isis_item
*i
)
2927 XFREE(MTYPE_ISIS_TLV
, i
);
2930 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
2932 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2934 if (STREAM_WRITEABLE(s
) < 1)
2936 stream_putc(s
, auth
->type
);
2938 switch (auth
->type
) {
2939 case ISIS_PASSWD_TYPE_CLEARTXT
:
2940 if (STREAM_WRITEABLE(s
) < auth
->length
)
2942 stream_put(s
, auth
->passwd
, auth
->length
);
2944 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2945 if (STREAM_WRITEABLE(s
) < 16)
2947 auth
->offset
= stream_get_endp(s
);
2948 stream_put(s
, NULL
, 16);
2957 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
2958 struct sbuf
*log
, void *dest
, int indent
)
2960 struct isis_tlvs
*tlvs
= dest
;
2962 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
2966 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
2972 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2974 rv
->type
= stream_getc(s
);
2975 rv
->length
= len
- 1;
2977 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
2980 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
2983 XFREE(MTYPE_ISIS_TLV
, rv
);
2987 rv
->offset
= stream_get_getp(s
);
2988 stream_get(rv
->value
, s
, rv
->length
);
2989 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2990 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
2994 /* Functions related to TLV 13 Purge Originator */
2996 static struct isis_purge_originator
*copy_tlv_purge_originator(
2997 struct isis_purge_originator
*poi
)
3002 struct isis_purge_originator
*rv
;
3004 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3005 rv
->sender_set
= poi
->sender_set
;
3006 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3007 if (poi
->sender_set
)
3008 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
3012 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
3013 struct sbuf
*buf
, int indent
)
3018 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
3019 sbuf_push(buf
, indent
, " Generator: %s\n",
3020 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3021 if (poi
->sender_set
) {
3022 sbuf_push(buf
, indent
, " Received-From: %s\n",
3023 isis_format_id(poi
->sender
, sizeof(poi
->sender
)));
3027 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
3029 XFREE(MTYPE_ISIS_TLV
, poi
);
3032 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
3038 uint8_t data_len
= 1 + sizeof(poi
->generator
);
3040 if (poi
->sender_set
)
3041 data_len
+= sizeof(poi
->sender
);
3043 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
3046 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
3047 stream_putc(s
, data_len
);
3048 stream_putc(s
, poi
->sender_set
? 2 : 1);
3049 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
3050 if (poi
->sender_set
)
3051 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
3055 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
3056 uint8_t tlv_type
, uint8_t tlv_len
,
3057 struct stream
*s
, struct sbuf
*log
,
3058 void *dest
, int indent
)
3060 struct isis_tlvs
*tlvs
= dest
;
3061 struct isis_purge_originator poi
= {};
3063 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
3065 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %"
3066 PRIu8
")\n", tlv_len
);
3070 uint8_t number_of_ids
= stream_getc(s
);
3072 if (number_of_ids
== 1) {
3073 poi
.sender_set
= false;
3074 } else if (number_of_ids
== 2) {
3075 poi
.sender_set
= true;
3077 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %"
3078 PRIu8
")\n", number_of_ids
);
3082 if (tlv_len
!= 1 + 6 * number_of_ids
) {
3083 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
3087 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
3089 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
3091 if (tlvs
->purge_originator
) {
3092 sbuf_push(log
, indent
,
3093 "WARNING: Purge originator present multiple times, ignoring.\n");
3097 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
3102 /* Functions relating to item TLVs */
3104 static void init_item_list(struct isis_item_list
*items
)
3107 items
->tail
= &items
->head
;
3111 static struct isis_item
*copy_item(enum isis_tlv_context context
,
3112 enum isis_tlv_type type
,
3113 struct isis_item
*item
)
3115 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3117 if (ops
&& ops
->copy_item
)
3118 return ops
->copy_item(item
);
3120 assert(!"Unknown item tlv type!");
3124 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3125 struct isis_item_list
*src
, struct isis_item_list
*dest
)
3127 struct isis_item
*item
;
3129 init_item_list(dest
);
3131 for (item
= src
->head
; item
; item
= item
->next
) {
3132 append_item(dest
, copy_item(context
, type
, item
));
3136 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
3137 enum isis_tlv_type type
, struct isis_item
*i
,
3138 struct sbuf
*buf
, int indent
)
3140 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3142 if (ops
&& ops
->format_item
) {
3143 ops
->format_item(mtid
, i
, buf
, indent
);
3147 assert(!"Unknown item tlv type!");
3150 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
3151 enum isis_tlv_type type
, struct isis_item_list
*items
,
3152 struct sbuf
*buf
, int indent
)
3154 struct isis_item
*i
;
3156 for (i
= items
->head
; i
; i
= i
->next
)
3157 format_item(mtid
, context
, type
, i
, buf
, indent
);
3160 static void free_item(enum isis_tlv_context tlv_context
,
3161 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
3163 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
3165 if (ops
&& ops
->free_item
) {
3166 ops
->free_item(item
);
3170 assert(!"Unknown item tlv type!");
3173 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3174 struct isis_item_list
*items
)
3176 struct isis_item
*item
, *next_item
;
3178 for (item
= items
->head
; item
; item
= next_item
) {
3179 next_item
= item
->next
;
3180 free_item(context
, type
, item
);
3184 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
3185 struct isis_item
*i
, struct stream
*s
,
3186 struct isis_tlvs
**fragment_tlvs
,
3187 const struct pack_order_entry
*pe
, uint16_t mtid
)
3189 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3191 if (ops
&& ops
->pack_item
) {
3192 return ops
->pack_item(i
, s
);
3195 assert(!"Unknown item tlv type!");
3199 static void add_item_to_fragment(struct isis_item
*i
,
3200 const struct pack_order_entry
*pe
,
3201 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
3203 struct isis_item_list
*l
;
3205 if (pe
->how_to_pack
== ISIS_ITEMS
) {
3206 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
3208 struct isis_mt_item_list
*m
;
3209 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
3210 l
= isis_get_mt_items(m
, mtid
);
3213 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
3216 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
3217 enum isis_tlv_type type
, struct isis_item_list
*items
,
3218 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
3219 const struct pack_order_entry
*pe
,
3220 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3221 struct list
*new_fragment_arg
)
3223 size_t len_pos
, last_len
, len
;
3224 struct isis_item
*item
= NULL
;
3231 if (STREAM_WRITEABLE(s
) < 2)
3234 stream_putc(s
, type
);
3235 len_pos
= stream_get_endp(s
);
3236 stream_putc(s
, 0); /* Put 0 as length for now */
3238 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
3239 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
3240 if (STREAM_WRITEABLE(s
) < 2)
3242 stream_putw(s
, mtid
);
3245 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
3246 if (STREAM_WRITEABLE(s
) < 1)
3248 stream_putc(s
, 0); /* Virtual flag is set to 0 */
3252 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
3253 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
3257 len
= stream_get_endp(s
) - len_pos
- 1;
3259 /* Multiple auths don't go into one TLV, so always break */
3260 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
3265 /* Multiple prefix-sids don't go into one TLV, so always break */
3266 if (type
== ISIS_SUBTLV_PREFIX_SID
3267 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
3268 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
3274 if (!last_len
) /* strange, not a single item fit */
3276 /* drop last tlv, otherwise, its too long */
3277 stream_set_endp(s
, len_pos
+ 1 + last_len
);
3283 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
3288 stream_putc_at(s
, len_pos
, len
);
3297 *fragment_tlvs
= new_fragment(new_fragment_arg
);
3300 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
3302 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
3305 dest
->tail
= &(*dest
->tail
)->next
;
3309 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
3311 struct isis_item
*item
, *prev
= NULL
, *next
;
3314 if ((dest
== NULL
) || (del
== NULL
))
3318 * TODO: delete is tricky because "dest" is a singly linked list.
3319 * We need to switch a doubly linked list.
3321 for (item
= dest
->head
; item
; item
= next
) {
3322 if (item
->next
== del
) {
3329 prev
->next
= del
->next
;
3330 if (dest
->head
== del
)
3331 dest
->head
= del
->next
;
3332 if ((struct isis_item
*)dest
->tail
== del
) {
3335 dest
->tail
= &(*dest
->tail
)->next
;
3337 dest
->tail
= &dest
->head
;
3342 static struct isis_item
*last_item(struct isis_item_list
*list
)
3344 return container_of(list
->tail
, struct isis_item
, next
);
3347 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
3348 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
3349 struct sbuf
*log
, void *dest
, int indent
)
3351 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
3353 if (ops
&& ops
->unpack_item
)
3354 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
3356 assert(!"Unknown item tlv type!");
3357 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
3361 static int unpack_tlv_with_items(enum isis_tlv_context context
,
3362 uint8_t tlv_type
, uint8_t tlv_len
,
3363 struct stream
*s
, struct sbuf
*log
, void *dest
,
3371 tlv_start
= stream_get_getp(s
);
3374 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
3376 sbuf_push(log
, indent
,
3377 "TLV is too short to contain MTID\n");
3380 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
3382 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
3383 isis_mtid2str(mtid
));
3385 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
3386 mtid
= ISIS_MT_IPV4_UNICAST
;
3389 if (context
== ISIS_CONTEXT_LSP
3390 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
3391 if (tlv_len
- tlv_pos
< 1) {
3392 sbuf_push(log
, indent
,
3393 "TLV is too short for old style reach\n");
3396 stream_forward_getp(s
, 1);
3400 if (context
== ISIS_CONTEXT_LSP
3401 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
3402 struct isis_tlvs
*tlvs
= dest
;
3403 dest
= &tlvs
->oldstyle_ip_reach
;
3404 } else if (context
== ISIS_CONTEXT_LSP
3405 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
3406 struct isis_tlvs
*tlvs
= dest
;
3407 dest
= &tlvs
->oldstyle_ip_reach_ext
;
3410 if (context
== ISIS_CONTEXT_LSP
3411 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
3412 struct isis_tlvs
*tlvs
= dest
;
3413 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
3416 while (tlv_pos
< (size_t)tlv_len
) {
3417 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
3418 log
, dest
, indent
+ 2);
3422 tlv_pos
= stream_get_getp(s
) - tlv_start
;
3428 /* Functions to manipulate mt_item_lists */
3430 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
3431 const struct isis_item_list
*b
)
3433 if (a
->mtid
< b
->mtid
)
3435 if (a
->mtid
> b
->mtid
)
3440 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
3441 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
3443 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
3446 struct isis_item_list
*rv
;
3448 rv
= isis_lookup_mt_items(m
, mtid
);
3450 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
3453 RB_INSERT(isis_mt_item_list
, m
, rv
);
3459 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
3462 struct isis_item_list key
= {.mtid
= mtid
};
3464 return RB_FIND(isis_mt_item_list
, m
, &key
);
3467 static void free_mt_items(enum isis_tlv_context context
,
3468 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
3470 struct isis_item_list
*n
, *nnext
;
3472 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
3473 free_items(context
, type
, n
);
3474 RB_REMOVE(isis_mt_item_list
, m
, n
);
3475 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
3479 static void format_mt_items(enum isis_tlv_context context
,
3480 enum isis_tlv_type type
,
3481 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
3484 struct isis_item_list
*n
;
3486 RB_FOREACH (n
, isis_mt_item_list
, m
) {
3487 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
3491 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3492 struct isis_mt_item_list
*m
, struct stream
*s
,
3493 struct isis_tlvs
**fragment_tlvs
,
3494 const struct pack_order_entry
*pe
,
3495 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3496 struct list
*new_fragment_arg
)
3498 struct isis_item_list
*n
;
3500 RB_FOREACH (n
, isis_mt_item_list
, m
) {
3503 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
3504 pe
, new_fragment
, new_fragment_arg
);
3512 static void copy_mt_items(enum isis_tlv_context context
,
3513 enum isis_tlv_type type
,
3514 struct isis_mt_item_list
*src
,
3515 struct isis_mt_item_list
*dest
)
3517 struct isis_item_list
*n
;
3519 RB_INIT(isis_mt_item_list
, dest
);
3521 RB_FOREACH (n
, isis_mt_item_list
, src
) {
3522 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
3526 /* Functions related to tlvs in general */
3528 struct isis_tlvs
*isis_alloc_tlvs(void)
3530 struct isis_tlvs
*result
;
3532 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
3534 init_item_list(&result
->isis_auth
);
3535 init_item_list(&result
->area_addresses
);
3536 init_item_list(&result
->mt_router_info
);
3537 init_item_list(&result
->oldstyle_reach
);
3538 init_item_list(&result
->lan_neighbor
);
3539 init_item_list(&result
->lsp_entries
);
3540 init_item_list(&result
->extended_reach
);
3541 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
3542 init_item_list(&result
->oldstyle_ip_reach
);
3543 init_item_list(&result
->oldstyle_ip_reach_ext
);
3544 init_item_list(&result
->ipv4_address
);
3545 init_item_list(&result
->ipv6_address
);
3546 init_item_list(&result
->extended_ip_reach
);
3547 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
3548 init_item_list(&result
->ipv6_reach
);
3549 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
3554 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
3556 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3558 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
3561 rv
->purge_originator
=
3562 copy_tlv_purge_originator(tlvs
->purge_originator
);
3564 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3565 &tlvs
->area_addresses
, &rv
->area_addresses
);
3567 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3568 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
3570 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
3572 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3573 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
3575 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3576 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
3578 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
3581 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3582 &tlvs
->extended_reach
, &rv
->extended_reach
);
3584 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
3587 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3588 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
3590 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
3591 &rv
->protocols_supported
);
3593 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3594 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
3596 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
3599 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
3602 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
3604 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3605 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
3607 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3608 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
3610 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
3612 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
3615 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3616 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
3618 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
3620 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
3622 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
3627 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
3629 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
3631 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
3634 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, indent
);
3636 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3637 &tlvs
->area_addresses
, buf
, indent
);
3639 if (tlvs
->mt_router_info_empty
) {
3640 sbuf_push(buf
, indent
, "MT Router Info: None\n");
3642 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3643 &tlvs
->mt_router_info
, buf
, indent
);
3646 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3647 &tlvs
->oldstyle_reach
, buf
, indent
);
3649 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3650 &tlvs
->lan_neighbor
, buf
, indent
);
3652 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
3655 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
3656 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
3657 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
3659 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3660 &tlvs
->extended_reach
, buf
, indent
);
3662 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
3665 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3666 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
3668 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3669 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
3671 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
3672 &tlvs
->ipv4_address
, buf
, indent
);
3674 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
3675 &tlvs
->ipv6_address
, buf
, indent
);
3677 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3678 &tlvs
->extended_ip_reach
, buf
, indent
);
3680 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3681 &tlvs
->mt_ip_reach
, buf
, indent
);
3683 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
3686 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3687 &tlvs
->mt_ipv6_reach
, buf
, indent
);
3689 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
3691 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, indent
);
3694 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
3696 static struct sbuf buf
;
3698 if (!sbuf_buf(&buf
))
3699 sbuf_init(&buf
, NULL
, 0);
3702 format_tlvs(tlvs
, &buf
, 0);
3703 return sbuf_buf(&buf
);
3706 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
3711 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
3712 free_tlv_purge_originator(tlvs
->purge_originator
);
3713 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3714 &tlvs
->area_addresses
);
3715 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3716 &tlvs
->mt_router_info
);
3717 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3718 &tlvs
->oldstyle_reach
);
3719 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3720 &tlvs
->lan_neighbor
);
3721 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
3722 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3723 &tlvs
->extended_reach
);
3724 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
3725 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3726 &tlvs
->oldstyle_ip_reach
);
3727 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
3728 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3729 &tlvs
->oldstyle_ip_reach_ext
);
3730 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
3731 &tlvs
->ipv4_address
);
3732 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
3733 &tlvs
->ipv6_address
);
3734 free_tlv_te_router_id(tlvs
->te_router_id
);
3735 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3736 &tlvs
->extended_ip_reach
);
3737 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3738 &tlvs
->mt_ip_reach
);
3739 free_tlv_dynamic_hostname(tlvs
->hostname
);
3740 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
3741 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3742 &tlvs
->mt_ipv6_reach
);
3743 free_tlv_threeway_adj(tlvs
->threeway_adj
);
3744 free_tlv_router_cap(tlvs
->router_cap
);
3745 free_tlv_spine_leaf(tlvs
->spine_leaf
);
3747 XFREE(MTYPE_ISIS_TLV
, tlvs
);
3750 static void add_padding(struct stream
*s
)
3752 while (STREAM_WRITEABLE(s
)) {
3753 if (STREAM_WRITEABLE(s
) == 1)
3755 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
3757 if (padding_len
> 255) {
3758 if (padding_len
== 256)
3764 stream_putc(s
, ISIS_TLV_PADDING
);
3765 stream_putc(s
, padding_len
);
3766 stream_put(s
, NULL
, padding_len
);
3770 #define LSP_REM_LIFETIME_OFF 10
3771 #define LSP_CHECKSUM_OFF 24
3772 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
3773 uint16_t *rem_lifetime
)
3775 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
3776 sizeof(*rem_lifetime
));
3777 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
3778 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
3779 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
3782 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
3783 uint16_t rem_lifetime
)
3785 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
3786 sizeof(rem_lifetime
));
3787 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
3790 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
3794 uint16_t checksum
, rem_lifetime
;
3797 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
3799 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
3800 #ifdef CRYPTO_OPENSSL
3801 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
3802 auth
->plength
, STREAM_DATA(s
),
3803 stream_get_endp(s
), NULL
, NULL
);
3805 memcpy(digest
, result
, 16);
3806 #elif CRYPTO_INTERNAL
3807 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
3808 auth
->plength
, digest
);
3810 memcpy(auth
->value
, digest
, 16);
3811 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
3814 restore_auth_md5(s
, checksum
, rem_lifetime
);
3817 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
3819 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
3821 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
3822 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
3823 update_auth_hmac_md5(auth
, s
, is_lsp
);
3827 static int handle_pack_entry(const struct pack_order_entry
*pe
,
3828 struct isis_tlvs
*tlvs
, struct stream
*stream
,
3829 struct isis_tlvs
**fragment_tlvs
,
3830 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3831 struct list
*new_fragment_arg
)
3835 if (pe
->how_to_pack
== ISIS_ITEMS
) {
3836 struct isis_item_list
*l
;
3837 l
= (struct isis_item_list
*)(((char *)tlvs
)
3838 + pe
->what_to_pack
);
3839 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
3840 pe
, new_fragment
, new_fragment_arg
);
3842 struct isis_mt_item_list
*l
;
3843 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
3844 + pe
->what_to_pack
);
3845 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
3846 fragment_tlvs
, pe
, new_fragment
,
3853 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
3854 struct isis_tlvs
*fragment_tlvs
,
3855 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3856 struct list
*new_fragment_arg
)
3860 /* When fragmenting, don't add auth as it's already accounted for in the
3861 * size we are given. */
3862 if (!fragment_tlvs
) {
3863 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
3864 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
3870 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
3873 if (fragment_tlvs
) {
3874 fragment_tlvs
->purge_originator
=
3875 copy_tlv_purge_originator(tlvs
->purge_originator
);
3878 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
3881 if (fragment_tlvs
) {
3882 copy_tlv_protocols_supported(
3883 &tlvs
->protocols_supported
,
3884 &fragment_tlvs
->protocols_supported
);
3887 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3888 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
3891 if (fragment_tlvs
) {
3892 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3893 &tlvs
->area_addresses
,
3894 &fragment_tlvs
->area_addresses
);
3898 if (tlvs
->mt_router_info_empty
) {
3899 if (STREAM_WRITEABLE(stream
) < 2)
3901 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
3902 stream_putc(stream
, 0);
3904 fragment_tlvs
->mt_router_info_empty
= true;
3906 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3907 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
3911 if (fragment_tlvs
) {
3912 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3913 &tlvs
->mt_router_info
,
3914 &fragment_tlvs
->mt_router_info
);
3918 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
3922 fragment_tlvs
->hostname
=
3923 copy_tlv_dynamic_hostname(tlvs
->hostname
);
3925 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
3928 if (fragment_tlvs
) {
3929 fragment_tlvs
->router_cap
=
3930 copy_tlv_router_cap(tlvs
->router_cap
);
3933 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
3936 if (fragment_tlvs
) {
3937 fragment_tlvs
->te_router_id
=
3938 copy_tlv_te_router_id(tlvs
->te_router_id
);
3941 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
3944 if (fragment_tlvs
) {
3945 fragment_tlvs
->threeway_adj
=
3946 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
3949 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
3952 if (fragment_tlvs
) {
3953 fragment_tlvs
->spine_leaf
=
3954 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
3957 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
3959 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
3960 fragment_tlvs
? &fragment_tlvs
: NULL
,
3961 new_fragment
, new_fragment_arg
);
3970 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
3971 size_t len_pointer
, bool pad
, bool is_lsp
)
3975 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
3980 add_padding(stream
);
3982 if (len_pointer
!= (size_t)-1) {
3983 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
3986 update_auth(tlvs
, stream
, is_lsp
);
3991 static struct isis_tlvs
*new_fragment(struct list
*l
)
3993 struct isis_tlvs
*rv
= isis_alloc_tlvs();
3995 listnode_add(l
, rv
);
3999 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
4001 struct stream
*dummy_stream
= stream_new(size
);
4002 struct list
*rv
= list_new();
4003 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
4005 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
4006 struct listnode
*node
;
4007 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
4008 isis_free_tlvs(fragment_tlvs
);
4012 stream_free(dummy_stream
);
4016 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
4017 uint8_t tlv_len
, struct stream
*s
,
4018 struct sbuf
*log
, int indent
)
4020 stream_forward_getp(s
, tlv_len
);
4021 sbuf_push(log
, indent
,
4022 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
4027 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
4028 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4029 int indent
, bool *unpacked_known_tlvs
)
4031 uint8_t tlv_type
, tlv_len
;
4032 const struct tlv_ops
*ops
;
4034 sbuf_push(log
, indent
, "Unpacking TLV...\n");
4036 if (avail_len
< 2) {
4039 "Available data %zu too short to contain a TLV header.\n",
4044 tlv_type
= stream_getc(stream
);
4045 tlv_len
= stream_getc(stream
);
4047 sbuf_push(log
, indent
+ 2,
4048 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
4051 if (avail_len
< ((size_t)tlv_len
) + 2) {
4052 sbuf_push(log
, indent
+ 2,
4053 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
4054 avail_len
- 2, tlv_len
);
4058 ops
= tlv_table
[context
][tlv_type
];
4059 if (ops
&& ops
->unpack
) {
4060 if (unpacked_known_tlvs
)
4061 *unpacked_known_tlvs
= true;
4062 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
4066 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
4070 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
4071 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4072 int indent
, bool *unpacked_known_tlvs
)
4075 size_t tlv_start
, tlv_pos
;
4077 tlv_start
= stream_get_getp(stream
);
4080 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
4081 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
4083 while (tlv_pos
< avail_len
) {
4084 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
4085 indent
+ 2, unpacked_known_tlvs
);
4089 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
4095 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
4096 struct isis_tlvs
**dest
, const char **log
)
4098 static struct sbuf logbuf
;
4101 struct isis_tlvs
*result
;
4103 if (!sbuf_buf(&logbuf
))
4104 sbuf_init(&logbuf
, NULL
, 0);
4106 sbuf_reset(&logbuf
);
4107 if (avail_len
> STREAM_READABLE(stream
)) {
4108 sbuf_push(&logbuf
, indent
,
4109 "Stream doesn't contain sufficient data. "
4110 "Claimed %zu, available %zu\n",
4111 avail_len
, STREAM_READABLE(stream
));
4115 result
= isis_alloc_tlvs();
4116 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
4119 *log
= sbuf_buf(&logbuf
);
4125 #define TLV_OPS(_name_, _desc_) \
4126 static const struct tlv_ops tlv_##_name_##_ops = { \
4127 .name = _desc_, .unpack = unpack_tlv_##_name_, \
4130 #define ITEM_TLV_OPS(_name_, _desc_) \
4131 static const struct tlv_ops tlv_##_name_##_ops = { \
4133 .unpack = unpack_tlv_with_items, \
4135 .pack_item = pack_item_##_name_, \
4136 .free_item = free_item_##_name_, \
4137 .unpack_item = unpack_item_##_name_, \
4138 .format_item = format_item_##_name_, \
4139 .copy_item = copy_item_##_name_}
4141 #define SUBTLV_OPS(_name_, _desc_) \
4142 static const struct tlv_ops subtlv_##_name_##_ops = { \
4143 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
4146 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
4147 ITEM_TLV_OPS(_name_, _desc_)
4149 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
4150 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
4151 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
4152 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
4153 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
4154 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
4155 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
4156 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
4157 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
4158 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
4159 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
4160 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
4161 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
4162 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
4163 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
4164 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
4165 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
4166 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
4167 TLV_OPS(router_cap
, "TLV 242 Router Capability");
4169 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
4170 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
4172 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
4173 [ISIS_CONTEXT_LSP
] = {
4174 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
4175 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
4176 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
4177 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
4178 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
4179 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
4180 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
4181 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
4182 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
4183 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
4184 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
4185 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
4186 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
4187 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
4188 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
4189 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
4190 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
4191 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
4192 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
4193 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
4194 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
4195 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
4196 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
4198 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
4199 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
4200 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
4202 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
4203 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
4204 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
4208 /* Accessor functions */
4210 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
4212 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4213 init_item_list(&tlvs
->isis_auth
);
4215 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
4218 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
4220 auth
->type
= passwd
->type
;
4222 auth
->plength
= passwd
->len
;
4223 memcpy(auth
->passwd
, passwd
->passwd
,
4224 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
4226 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
4227 auth
->length
= passwd
->len
;
4228 memcpy(auth
->value
, passwd
->passwd
,
4229 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
4232 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
4235 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
4236 struct list
*addresses
)
4238 struct listnode
*node
;
4239 struct area_addr
*area_addr
;
4241 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
4242 struct isis_area_address
*a
=
4243 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4245 a
->len
= area_addr
->addr_len
;
4246 memcpy(a
->addr
, area_addr
->area_addr
, 20);
4247 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
4251 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
4253 struct listnode
*node
;
4256 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
4257 struct isis_lan_neighbor
*n
=
4258 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
4260 memcpy(n
->mac
, snpa
, 6);
4261 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
4265 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
4266 struct nlpids
*nlpids
)
4268 tlvs
->protocols_supported
.count
= nlpids
->count
;
4269 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
4270 if (nlpids
->count
) {
4271 tlvs
->protocols_supported
.protocols
=
4272 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
4273 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
4276 tlvs
->protocols_supported
.protocols
= NULL
;
4280 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4281 bool overload
, bool attached
)
4283 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
4285 i
->overload
= overload
;
4286 i
->attached
= attached
;
4288 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
4291 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
4293 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4295 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
4299 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
4300 struct list
*addresses
)
4302 struct listnode
*node
;
4303 struct prefix_ipv4
*ip_addr
;
4304 unsigned int addr_count
= 0;
4306 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
4307 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
4309 if (addr_count
>= 63)
4314 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
4315 struct list
*addresses
)
4317 struct listnode
*node
;
4318 struct prefix_ipv6
*ip_addr
;
4319 unsigned int addr_count
= 0;
4321 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
4322 if (addr_count
>= 15)
4325 struct isis_ipv6_address
*a
=
4326 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4328 a
->addr
= ip_addr
->prefix
;
4329 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
4334 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
4335 struct stream
*stream
,
4336 struct isis_auth
*auth
, bool is_lsp
);
4338 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
4339 struct stream
*stream
,
4340 struct isis_auth
*auth
, bool is_lsp
)
4342 return (auth
->length
== passwd
->len
4343 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
4346 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
4347 struct stream
*stream
,
4348 struct isis_auth
*auth
, bool is_lsp
)
4352 uint16_t rem_lifetime
;
4355 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
4357 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
4358 #ifdef CRYPTO_OPENSSL
4359 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
4360 passwd
->len
, STREAM_DATA(stream
),
4361 stream_get_endp(stream
), NULL
, NULL
);
4363 memcpy(digest
, result
, 16);
4364 #elif CRYPTO_INTERNAL
4365 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
4366 passwd
->len
, digest
);
4368 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
4370 bool rv
= !memcmp(digest
, auth
->value
, 16);
4373 restore_auth_md5(stream
, checksum
, rem_lifetime
);
4378 static const auth_validator_func auth_validators
[] = {
4379 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
4380 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
4383 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
4384 struct stream
*stream
, bool is_lsp
)
4386 /* If no auth is set, always pass authentication */
4388 return ISIS_AUTH_OK
;
4390 /* If we don't known how to validate the auth, return invalid */
4391 if (passwd
->type
>= array_size(auth_validators
)
4392 || !auth_validators
[passwd
->type
])
4393 return ISIS_AUTH_NO_VALIDATOR
;
4395 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4396 struct isis_auth
*auth
;
4397 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
4398 if (auth
->type
== passwd
->type
)
4402 /* If matching auth TLV could not be found, return invalid */
4404 return ISIS_AUTH_TYPE_FAILURE
;
4407 /* Perform validation and return result */
4408 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
4409 return ISIS_AUTH_OK
;
4411 return ISIS_AUTH_FAILURE
;
4414 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
4415 struct list
*addresses
)
4417 struct isis_area_address
*addr_head
;
4419 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
4420 for (struct isis_area_address
*addr
= addr_head
; addr
;
4421 addr
= addr
->next
) {
4422 struct listnode
*node
;
4423 struct area_addr
*a
;
4425 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
4426 if (a
->addr_len
== addr
->len
4427 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
4435 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
4436 struct isis_adjacency
*adj
,
4439 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
4441 adj
->area_address_count
= tlvs
->area_addresses
.count
;
4442 adj
->area_addresses
= XREALLOC(
4443 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
4444 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
4447 struct isis_area_address
*addr
= NULL
;
4448 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
4450 addr
= (struct isis_area_address
*)
4451 tlvs
->area_addresses
.head
;
4455 if (adj
->area_addresses
[i
].addr_len
== addr
->len
4456 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
4462 adj
->area_addresses
[i
].addr_len
= addr
->len
;
4463 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
4467 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
4468 struct isis_adjacency
*adj
,
4471 bool ipv4_supported
= false, ipv6_supported
= false;
4473 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
4474 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
4475 ipv4_supported
= true;
4476 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
4477 ipv6_supported
= true;
4480 struct nlpids reduced
= {};
4482 if (ipv4_supported
&& ipv6_supported
) {
4484 reduced
.nlpids
[0] = NLPID_IP
;
4485 reduced
.nlpids
[1] = NLPID_IPV6
;
4486 } else if (ipv4_supported
) {
4488 reduced
.nlpids
[0] = NLPID_IP
;
4489 } else if (ipv6_supported
) {
4491 reduced
.nlpids
[0] = NLPID_IPV6
;
4496 if (adj
->nlpids
.count
== reduced
.count
4497 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
4501 adj
->nlpids
.count
= reduced
.count
;
4502 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
4505 DEFINE_HOOK(isis_adj_ip_enabled_hook
, (struct isis_adjacency
*adj
, int family
),
4507 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
4508 (struct isis_adjacency
*adj
, int family
), (adj
, family
))
4510 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
4511 struct isis_adjacency
*adj
,
4514 bool ipv4_enabled
= false;
4516 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
4517 ipv4_enabled
= true;
4518 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
4519 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
);
4521 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
4523 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
4524 adj
->ipv4_addresses
= XREALLOC(
4525 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
4526 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
4529 struct isis_ipv4_address
*addr
= NULL
;
4530 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
4532 addr
= (struct isis_ipv4_address
*)
4533 tlvs
->ipv4_address
.head
;
4537 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
4538 sizeof(addr
->addr
)))
4542 adj
->ipv4_addresses
[i
] = addr
->addr
;
4546 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
);
4549 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
4550 struct isis_adjacency
*adj
,
4553 bool ipv6_enabled
= false;
4555 if (adj
->ipv6_address_count
== 0 && tlvs
->ipv6_address
.count
> 0)
4556 ipv6_enabled
= true;
4557 else if (adj
->ipv6_address_count
> 0 && tlvs
->ipv6_address
.count
== 0)
4558 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
);
4560 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
4562 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
4563 adj
->ipv6_addresses
= XREALLOC(
4564 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
4565 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
4568 struct isis_ipv6_address
*addr
= NULL
;
4569 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
4571 addr
= (struct isis_ipv6_address
*)
4572 tlvs
->ipv6_address
.head
;
4576 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
4577 sizeof(addr
->addr
)))
4581 adj
->ipv6_addresses
[i
] = addr
->addr
;
4585 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
);
4588 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
4593 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
4594 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
4595 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
4596 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
4599 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
4601 struct isis_lan_neighbor
*ne_head
;
4603 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
4604 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
4605 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
4612 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
4614 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
4616 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
4617 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
4618 entry
->checksum
= lsp
->hdr
.checksum
;
4619 entry
->seqno
= lsp
->hdr
.seqno
;
4622 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
4625 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
4626 uint8_t *stop_id
, uint16_t num_lsps
,
4627 struct lspdb_head
*head
,
4628 struct isis_lsp
**last_lsp
)
4630 struct isis_lsp searchfor
;
4631 struct isis_lsp
*first
, *lsp
;
4633 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
4634 first
= lspdb_find_gteq(head
, &searchfor
);
4638 frr_each_from (lspdb
, head
, lsp
, first
) {
4639 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
4640 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
4643 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
4648 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
4649 const char *hostname
)
4651 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
4653 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
4656 /* Set Router Capability TLV parameters */
4657 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
4658 const struct isis_router_cap
*cap
)
4660 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
4664 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
4665 *tlvs
->router_cap
= *cap
;
4668 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
4669 const struct in_addr
*id
)
4671 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
4674 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
4675 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
4678 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
4679 struct prefix_ipv4
*dest
, uint8_t metric
)
4681 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4684 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4685 apply_mask_ipv4(&r
->prefix
);
4686 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
4689 /* Add IS-IS SR Adjacency-SID subTLVs */
4690 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
4691 struct isis_adj_sid
*adj
)
4693 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
4694 SET_SUBTLV(exts
, EXT_ADJ_SID
);
4697 /* Delete IS-IS SR Adjacency-SID subTLVs */
4698 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
4699 struct isis_adj_sid
*adj
)
4701 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
4702 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
4703 if (exts
->adj_sid
.count
== 0)
4704 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
4707 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
4708 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
4709 struct isis_lan_adj_sid
*lan
)
4711 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
4712 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
4715 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
4716 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
4717 struct isis_lan_adj_sid
*lan
)
4719 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
4720 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
4721 if (exts
->lan_sid
.count
== 0)
4722 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
4725 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
4726 struct prefix_ipv4
*dest
, uint32_t metric
,
4727 bool external
, struct sr_prefix_cfg
*pcfg
)
4729 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4732 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4733 apply_mask_ipv4(&r
->prefix
);
4735 struct isis_prefix_sid
*psid
=
4736 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
4738 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
4739 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
4740 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
4742 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
4745 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4746 struct prefix_ipv6
*dest
, uint32_t metric
,
4747 bool external
, struct sr_prefix_cfg
*pcfg
)
4749 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4752 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4753 apply_mask_ipv6(&r
->prefix
);
4755 struct isis_prefix_sid
*psid
=
4756 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
4758 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
4759 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
4760 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
4763 struct isis_item_list
*l
;
4764 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
4766 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
4767 append_item(l
, (struct isis_item
*)r
);
4770 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4771 struct prefix_ipv6
*dest
,
4772 struct prefix_ipv6
*src
,
4775 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
4776 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
4779 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
4780 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
4781 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
4782 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
4785 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
4788 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4791 memcpy(r
->id
, id
, sizeof(r
->id
));
4792 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
4795 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4796 uint8_t *id
, uint32_t metric
,
4797 struct isis_ext_subtlvs
*exts
)
4799 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4801 memcpy(r
->id
, id
, sizeof(r
->id
));
4804 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
4806 struct isis_item_list
*l
;
4807 if (mtid
== ISIS_MT_IPV4_UNICAST
)
4808 l
= &tlvs
->extended_reach
;
4810 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
4811 append_item(l
, (struct isis_item
*)r
);
4814 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
4815 enum isis_threeway_state state
,
4816 uint32_t local_circuit_id
,
4817 const uint8_t *neighbor_id
,
4818 uint32_t neighbor_circuit_id
)
4820 assert(!tlvs
->threeway_adj
);
4822 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
4823 tlvs
->threeway_adj
->state
= state
;
4824 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
4827 tlvs
->threeway_adj
->neighbor_set
= true;
4828 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
4829 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
4833 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
4834 bool has_tier
, bool is_leaf
, bool is_spine
,
4837 assert(!tlvs
->spine_leaf
);
4839 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
4842 tlvs
->spine_leaf
->tier
= tier
;
4845 tlvs
->spine_leaf
->has_tier
= has_tier
;
4846 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
4847 tlvs
->spine_leaf
->is_spine
= is_spine
;
4848 tlvs
->spine_leaf
->is_backup
= is_backup
;
4851 struct isis_mt_router_info
*
4852 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
4854 if (tlvs
->mt_router_info_empty
)
4857 struct isis_mt_router_info
*rv
;
4858 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
4860 if (rv
->mtid
== mtid
)
4867 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
4868 const uint8_t *generator
,
4869 const uint8_t *sender
)
4871 assert(!tlvs
->purge_originator
);
4873 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
4874 sizeof(*tlvs
->purge_originator
));
4875 memcpy(tlvs
->purge_originator
->generator
, generator
,
4876 sizeof(tlvs
->purge_originator
->generator
));
4878 tlvs
->purge_originator
->sender_set
= true;
4879 memcpy(tlvs
->purge_originator
->sender
, sender
,
4880 sizeof(tlvs
->purge_originator
->sender
));