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_tlvs.h"
37 #include "isisd/isis_common.h"
38 #include "isisd/isis_mt.h"
39 #include "isisd/isis_misc.h"
40 #include "isisd/isis_adjacency.h"
41 #include "isisd/isis_circuit.h"
42 #include "isisd/isis_pdu.h"
43 #include "isisd/isis_lsp.h"
44 #include "isisd/isis_te.h"
45 #include "isisd/isis_sr.h"
47 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs");
48 DEFINE_MTYPE(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs");
49 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists");
51 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
52 uint8_t tlv_len
, struct stream
*s
,
53 struct sbuf
*log
, void *dest
, int indent
);
54 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%x\n",
205 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
206 sbuf_push(buf
, indent
, "Link Local ID: %u\n",
208 sbuf_push(buf
, indent
, "Link Remote ID: %u\n",
211 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
))
212 sbuf_push(buf
, indent
, "Local Interface IP Address(es): %pI4\n",
214 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
))
215 sbuf_push(buf
, indent
, "Remote Interface IP Address(es): %pI4\n",
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: %u\n",
248 if (IS_SUBTLV(exts
, EXT_RMT_IP
))
249 sbuf_push(buf
, indent
,
250 "Inter-AS TE Remote ASBR IP address: %pI4\n",
252 /* Extended metrics */
253 if (IS_SUBTLV(exts
, EXT_DELAY
))
254 sbuf_push(buf
, indent
,
255 "%s Average Link Delay: %u (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: %u / %u (micro-sec)\n",
260 IS_ANORMAL(exts
->min_delay
) ? "Anomalous" : "Normal",
261 exts
->min_delay
& TE_EXT_MASK
,
262 exts
->max_delay
& TE_EXT_MASK
);
264 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
265 sbuf_push(buf
, indent
,
266 "Delay Variation: %u (micro-sec)\n",
267 exts
->delay_var
& TE_EXT_MASK
);
269 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
))
270 sbuf_push(buf
, indent
, "%s Link Packet Loss: %g (%%)\n",
271 IS_ANORMAL(exts
->pkt_loss
) ? "Anomalous" : "Normal",
272 (float)((exts
->pkt_loss
& TE_EXT_MASK
)
274 if (IS_SUBTLV(exts
, EXT_RES_BW
))
275 sbuf_push(buf
, indent
,
276 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
278 if (IS_SUBTLV(exts
, EXT_AVA_BW
))
279 sbuf_push(buf
, indent
,
280 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
282 if (IS_SUBTLV(exts
, EXT_USE_BW
))
283 sbuf_push(buf
, indent
,
284 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
286 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
287 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
288 struct isis_adj_sid
*adj
;
290 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
292 if (((mtid
== ISIS_MT_IPV4_UNICAST
)
293 && (adj
->family
!= AF_INET
))
294 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
295 && (adj
->family
!= AF_INET6
)))
299 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
300 adj
->sid
, adj
->weight
,
301 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? '1'
303 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? '1'
305 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
? '1'
307 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
? '1'
309 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
? '1'
311 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
316 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
317 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
318 struct isis_lan_adj_sid
*lan
;
320 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
;
321 lan
; lan
= lan
->next
) {
322 if (((mtid
== ISIS_MT_IPV4_UNICAST
)
323 && (lan
->family
!= AF_INET
))
324 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
325 && (lan
->family
!= AF_INET6
)))
327 sbuf_push(buf
, indent
,
328 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
329 " Neighbor-ID: %s\n",
330 lan
->sid
, lan
->weight
,
331 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
334 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
337 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
340 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
343 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
346 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
349 isis_format_id(lan
->neighbor_id
, 6));
354 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
356 struct isis_item
*item
, *next_item
;
358 /* First, free Adj SID and LAN Adj SID list if needed */
359 for (item
= exts
->adj_sid
.head
; item
; item
= next_item
) {
360 next_item
= item
->next
;
361 XFREE(MTYPE_ISIS_SUBTLV
, item
);
363 for (item
= exts
->lan_sid
.head
; item
; item
= next_item
) {
364 next_item
= item
->next
;
365 XFREE(MTYPE_ISIS_SUBTLV
, item
);
367 XFREE(MTYPE_ISIS_SUBTLV
, exts
);
370 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
371 struct stream
*s
, size_t *min_len
)
375 if (STREAM_WRITEABLE(s
) < ISIS_SUBTLV_MAX_SIZE
) {
376 *min_len
= ISIS_SUBTLV_MAX_SIZE
;
380 if (IS_SUBTLV(exts
, EXT_ADM_GRP
)) {
381 stream_putc(s
, ISIS_SUBTLV_ADMIN_GRP
);
382 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
383 stream_putl(s
, exts
->adm_group
);
385 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
386 stream_putc(s
, ISIS_SUBTLV_LLRI
);
387 stream_putc(s
, ISIS_SUBTLV_LLRI_SIZE
);
388 stream_putl(s
, exts
->local_llri
);
389 stream_putl(s
, exts
->remote_llri
);
391 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
)) {
392 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR
);
393 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
394 stream_put(s
, &exts
->local_addr
.s_addr
, 4);
396 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
)) {
397 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR
);
398 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
399 stream_put(s
, &exts
->neigh_addr
.s_addr
, 4);
401 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
)) {
402 stream_putc(s
, ISIS_SUBTLV_LOCAL_IPADDR6
);
403 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
404 stream_put(s
, &exts
->local_addr6
, 16);
406 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
)) {
407 stream_putc(s
, ISIS_SUBTLV_RMT_IPADDR6
);
408 stream_putc(s
, ISIS_SUBTLV_IPV6_ADDR_SIZE
);
409 stream_put(s
, &exts
->neigh_addr6
, 16);
411 if (IS_SUBTLV(exts
, EXT_MAX_BW
)) {
412 stream_putc(s
, ISIS_SUBTLV_MAX_BW
);
413 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
414 stream_putf(s
, exts
->max_bw
);
416 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
)) {
417 stream_putc(s
, ISIS_SUBTLV_MAX_RSV_BW
);
418 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
419 stream_putf(s
, exts
->max_rsv_bw
);
421 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
422 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW
);
423 stream_putc(s
, ISIS_SUBTLV_UNRSV_BW_SIZE
);
424 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
++)
425 stream_putf(s
, exts
->unrsv_bw
[j
]);
427 if (IS_SUBTLV(exts
, EXT_TE_METRIC
)) {
428 stream_putc(s
, ISIS_SUBTLV_TE_METRIC
);
429 stream_putc(s
, ISIS_SUBTLV_TE_METRIC_SIZE
);
430 stream_put3(s
, exts
->te_metric
);
432 if (IS_SUBTLV(exts
, EXT_RMT_AS
)) {
433 stream_putc(s
, ISIS_SUBTLV_RAS
);
434 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
435 stream_putl(s
, exts
->remote_as
);
437 if (IS_SUBTLV(exts
, EXT_RMT_IP
)) {
438 stream_putc(s
, ISIS_SUBTLV_RIP
);
439 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
440 stream_put(s
, &exts
->remote_ip
.s_addr
, 4);
442 if (IS_SUBTLV(exts
, EXT_DELAY
)) {
443 stream_putc(s
, ISIS_SUBTLV_AV_DELAY
);
444 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
445 stream_putl(s
, exts
->delay
);
447 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
448 stream_putc(s
, ISIS_SUBTLV_MM_DELAY
);
449 stream_putc(s
, ISIS_SUBTLV_MM_DELAY_SIZE
);
450 stream_putl(s
, exts
->min_delay
);
451 stream_putl(s
, exts
->max_delay
);
453 if (IS_SUBTLV(exts
, EXT_DELAY_VAR
)) {
454 stream_putc(s
, ISIS_SUBTLV_DELAY_VAR
);
455 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
456 stream_putl(s
, exts
->delay_var
);
458 if (IS_SUBTLV(exts
, EXT_PKT_LOSS
)) {
459 stream_putc(s
, ISIS_SUBTLV_PKT_LOSS
);
460 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
461 stream_putl(s
, exts
->pkt_loss
);
463 if (IS_SUBTLV(exts
, EXT_RES_BW
)) {
464 stream_putc(s
, ISIS_SUBTLV_RES_BW
);
465 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
466 stream_putf(s
, exts
->res_bw
);
468 if (IS_SUBTLV(exts
, EXT_AVA_BW
)) {
469 stream_putc(s
, ISIS_SUBTLV_AVA_BW
);
470 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
471 stream_putf(s
, exts
->ava_bw
);
473 if (IS_SUBTLV(exts
, EXT_USE_BW
)) {
474 stream_putc(s
, ISIS_SUBTLV_USE_BW
);
475 stream_putc(s
, ISIS_SUBTLV_DEF_SIZE
);
476 stream_putf(s
, exts
->use_bw
);
478 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
479 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
480 struct isis_adj_sid
*adj
;
482 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
484 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
485 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
486 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
488 stream_putc(s
, size
);
489 stream_putc(s
, adj
->flags
);
490 stream_putc(s
, adj
->weight
);
491 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
492 stream_put3(s
, adj
->sid
);
494 stream_putl(s
, adj
->sid
);
498 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
499 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
500 struct isis_lan_adj_sid
*lan
;
502 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
504 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
505 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
506 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
508 stream_putc(s
, size
);
509 stream_putc(s
, lan
->flags
);
510 stream_putc(s
, lan
->weight
);
511 stream_put(s
, lan
->neighbor_id
, 6);
512 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
513 stream_put3(s
, lan
->sid
);
515 stream_putl(s
, lan
->sid
);
522 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
523 struct sbuf
*log
, void *dest
, int indent
)
529 struct isis_extended_reach
*rv
= dest
;
530 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
535 * Parse subTLVs until reach subTLV length
536 * Check that it remains at least 2 bytes: subTLV Type & Length
538 while (len
> sum
+ 2) {
539 /* Read SubTLV Type and Length */
540 subtlv_type
= stream_getc(s
);
541 subtlv_len
= stream_getc(s
);
542 if (subtlv_len
> len
- sum
- ISIS_SUBTLV_HDR_SIZE
) {
545 "TLV %hhu: Available data %u is less than TLV size %u !\n",
546 subtlv_type
, len
- sum
- ISIS_SUBTLV_HDR_SIZE
,
551 switch (subtlv_type
) {
552 /* Standard Metric as defined in RFC5305 */
553 case ISIS_SUBTLV_ADMIN_GRP
:
554 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
555 sbuf_push(log
, indent
,
556 "TLV size does not match expected size for Administrative Group!\n");
557 stream_forward_getp(s
, subtlv_len
);
559 exts
->adm_group
= stream_getl(s
);
560 SET_SUBTLV(exts
, EXT_ADM_GRP
);
563 case ISIS_SUBTLV_LLRI
:
564 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
565 sbuf_push(log
, indent
,
566 "TLV size does not match expected size for Link ID!\n");
567 stream_forward_getp(s
, subtlv_len
);
569 exts
->local_llri
= stream_getl(s
);
570 exts
->remote_llri
= stream_getl(s
);
571 SET_SUBTLV(exts
, EXT_LLRI
);
574 case ISIS_SUBTLV_LOCAL_IPADDR
:
575 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
576 sbuf_push(log
, indent
,
577 "TLV size does not match expected size for Local IP address!\n");
578 stream_forward_getp(s
, subtlv_len
);
580 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
581 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
584 case ISIS_SUBTLV_RMT_IPADDR
:
585 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
586 sbuf_push(log
, indent
,
587 "TLV size does not match expected size for Remote IP address!\n");
588 stream_forward_getp(s
, subtlv_len
);
590 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
591 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
594 case ISIS_SUBTLV_LOCAL_IPADDR6
:
595 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
596 sbuf_push(log
, indent
,
597 "TLV size does not match expected size for Local IPv6 address!\n");
598 stream_forward_getp(s
, subtlv_len
);
600 stream_get(&exts
->local_addr6
, s
, 16);
601 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
604 case ISIS_SUBTLV_RMT_IPADDR6
:
605 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
606 sbuf_push(log
, indent
,
607 "TLV size does not match expected size for Remote IPv6 address!\n");
608 stream_forward_getp(s
, subtlv_len
);
610 stream_get(&exts
->neigh_addr6
, s
, 16);
611 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
614 case ISIS_SUBTLV_MAX_BW
:
615 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
616 sbuf_push(log
, indent
,
617 "TLV size does not match expected size for Maximum Bandwidth!\n");
618 stream_forward_getp(s
, subtlv_len
);
620 exts
->max_bw
= stream_getf(s
);
621 SET_SUBTLV(exts
, EXT_MAX_BW
);
624 case ISIS_SUBTLV_MAX_RSV_BW
:
625 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
626 sbuf_push(log
, indent
,
627 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
628 stream_forward_getp(s
, subtlv_len
);
630 exts
->max_rsv_bw
= stream_getf(s
);
631 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
634 case ISIS_SUBTLV_UNRSV_BW
:
635 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
636 sbuf_push(log
, indent
,
637 "TLV size does not match expected size for Unreserved Bandwidth!\n");
638 stream_forward_getp(s
, subtlv_len
);
640 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
641 exts
->unrsv_bw
[i
] = stream_getf(s
);
642 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
645 case ISIS_SUBTLV_TE_METRIC
:
646 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
647 sbuf_push(log
, indent
,
648 "TLV size does not match expected size for Traffic Engineering Metric!\n");
649 stream_forward_getp(s
, subtlv_len
);
651 exts
->te_metric
= stream_get3(s
);
652 SET_SUBTLV(exts
, EXT_TE_METRIC
);
655 case ISIS_SUBTLV_RAS
:
656 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
657 sbuf_push(log
, indent
,
658 "TLV size does not match expected size for Remote AS number!\n");
659 stream_forward_getp(s
, subtlv_len
);
661 exts
->remote_as
= stream_getl(s
);
662 SET_SUBTLV(exts
, EXT_RMT_AS
);
665 case ISIS_SUBTLV_RIP
:
666 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
667 sbuf_push(log
, indent
,
668 "TLV size does not match expected size for Remote ASBR IP Address!\n");
669 stream_forward_getp(s
, subtlv_len
);
671 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
672 SET_SUBTLV(exts
, EXT_RMT_IP
);
675 /* Extended Metrics as defined in RFC 7810 */
676 case ISIS_SUBTLV_AV_DELAY
:
677 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
678 sbuf_push(log
, indent
,
679 "TLV size does not match expected size for Average Link Delay!\n");
680 stream_forward_getp(s
, subtlv_len
);
682 exts
->delay
= stream_getl(s
);
683 SET_SUBTLV(exts
, EXT_DELAY
);
686 case ISIS_SUBTLV_MM_DELAY
:
687 if (subtlv_len
!= ISIS_SUBTLV_MM_DELAY_SIZE
) {
688 sbuf_push(log
, indent
,
689 "TLV size does not match expected size for Min/Max Link Delay!\n");
690 stream_forward_getp(s
, subtlv_len
);
692 exts
->min_delay
= stream_getl(s
);
693 exts
->max_delay
= stream_getl(s
);
694 SET_SUBTLV(exts
, EXT_MM_DELAY
);
697 case ISIS_SUBTLV_DELAY_VAR
:
698 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
699 sbuf_push(log
, indent
,
700 "TLV size does not match expected size for Delay Variation!\n");
701 stream_forward_getp(s
, subtlv_len
);
703 exts
->delay_var
= stream_getl(s
);
704 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
707 case ISIS_SUBTLV_PKT_LOSS
:
708 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
709 sbuf_push(log
, indent
,
710 "TLV size does not match expected size for Link Packet Loss!\n");
711 stream_forward_getp(s
, subtlv_len
);
713 exts
->pkt_loss
= stream_getl(s
);
714 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
717 case ISIS_SUBTLV_RES_BW
:
718 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
719 sbuf_push(log
, indent
,
720 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
721 stream_forward_getp(s
, subtlv_len
);
723 exts
->res_bw
= stream_getf(s
);
724 SET_SUBTLV(exts
, EXT_RES_BW
);
727 case ISIS_SUBTLV_AVA_BW
:
728 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
729 sbuf_push(log
, indent
,
730 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
731 stream_forward_getp(s
, subtlv_len
);
733 exts
->ava_bw
= stream_getf(s
);
734 SET_SUBTLV(exts
, EXT_AVA_BW
);
737 case ISIS_SUBTLV_USE_BW
:
738 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
739 sbuf_push(log
, indent
,
740 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
741 stream_forward_getp(s
, subtlv_len
);
743 exts
->use_bw
= stream_getf(s
);
744 SET_SUBTLV(exts
, EXT_USE_BW
);
747 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
748 case ISIS_SUBTLV_ADJ_SID
:
749 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
750 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
751 sbuf_push(log
, indent
,
752 "TLV size does not match expected size for Adjacency SID!\n");
753 stream_forward_getp(s
, subtlv_len
);
755 struct isis_adj_sid
*adj
;
757 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
758 sizeof(struct isis_adj_sid
));
759 adj
->flags
= stream_getc(s
);
760 adj
->weight
= stream_getc(s
);
761 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
762 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
) {
765 "TLV size does not match expected size for Adjacency SID!\n");
766 stream_forward_getp(s
, subtlv_len
- 2);
770 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
772 != ISIS_SUBTLV_ADJ_SID_SIZE
776 "TLV size does not match expected size for Adjacency SID!\n");
777 stream_forward_getp(s
, subtlv_len
- 2);
781 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
782 adj
->sid
= stream_get3(s
);
783 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
785 adj
->sid
= stream_getl(s
);
787 if (mtid
== ISIS_MT_IPV4_UNICAST
)
788 adj
->family
= AF_INET
;
789 if (mtid
== ISIS_MT_IPV6_UNICAST
)
790 adj
->family
= AF_INET6
;
791 append_item(&exts
->adj_sid
,
792 (struct isis_item
*)adj
);
793 SET_SUBTLV(exts
, EXT_ADJ_SID
);
796 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
797 case ISIS_SUBTLV_LAN_ADJ_SID
:
798 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
799 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
800 sbuf_push(log
, indent
,
801 "TLV size does not match expected size for LAN-Adjacency SID!\n");
802 stream_forward_getp(s
, subtlv_len
);
804 struct isis_lan_adj_sid
*lan
;
806 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
807 sizeof(struct isis_lan_adj_sid
));
808 lan
->flags
= stream_getc(s
);
809 lan
->weight
= stream_getc(s
);
810 stream_get(&(lan
->neighbor_id
), s
,
813 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
815 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
) {
818 "TLV size does not match expected size for LAN-Adjacency SID!\n");
825 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
827 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
831 "TLV size does not match expected size for LAN-Adjacency SID!\n");
838 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
839 lan
->sid
= stream_get3(s
);
840 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
842 lan
->sid
= stream_getl(s
);
844 if (mtid
== ISIS_MT_IPV4_UNICAST
)
845 lan
->family
= AF_INET
;
846 if (mtid
== ISIS_MT_IPV6_UNICAST
)
847 lan
->family
= AF_INET6
;
848 append_item(&exts
->lan_sid
,
849 (struct isis_item
*)lan
);
850 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
854 /* Skip unknown TLV */
855 stream_forward_getp(s
, subtlv_len
);
858 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
864 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
865 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
867 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
868 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
870 rv
->flags
= sid
->flags
;
871 rv
->algorithm
= sid
->algorithm
;
872 rv
->value
= sid
->value
;
873 return (struct isis_item
*)rv
;
876 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
877 struct sbuf
*buf
, int indent
)
879 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
881 sbuf_push(buf
, indent
, "SR Prefix-SID ");
882 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
883 sbuf_push(buf
, 0, "Label: %u, ", sid
->value
);
885 sbuf_push(buf
, 0, "Index: %u, ", sid
->value
);
887 sbuf_push(buf
, 0, "Algorithm: %hhu, ", sid
->algorithm
);
888 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
889 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
? " READVERTISED"
891 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
892 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP" : " PHP",
893 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
? " EXPLICIT-NULL"
895 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
896 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
899 static void free_item_prefix_sid(struct isis_item
*i
)
901 XFREE(MTYPE_ISIS_SUBTLV
, i
);
904 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
,
907 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
909 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
911 if (STREAM_WRITEABLE(s
) < size
) {
916 stream_putc(s
, sid
->flags
);
917 stream_putc(s
, sid
->algorithm
);
919 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
920 stream_put3(s
, sid
->value
);
922 stream_putl(s
, sid
->value
);
928 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
929 struct sbuf
*log
, void *dest
, int indent
)
931 struct isis_subtlvs
*subtlvs
= dest
;
932 struct isis_prefix_sid sid
= {
935 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
938 sbuf_push(log
, indent
,
939 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
944 sid
.flags
= stream_getc(s
);
945 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
946 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
947 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
951 sid
.algorithm
= stream_getc(s
);
953 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
954 ? ISIS_SUBTLV_PREFIX_SID_SIZE
955 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
956 if (len
!= expected_size
) {
957 sbuf_push(log
, indent
,
958 "TLV size differs from expected size. (expected %u but got %hhu)\n",
963 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
964 sid
.value
= stream_get3(s
);
965 if (!IS_MPLS_UNRESERVED_LABEL(sid
.value
)) {
966 sbuf_push(log
, indent
, "Invalid absolute SID %u\n",
971 sid
.value
= stream_getl(s
);
974 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, indent
+ 2);
975 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
979 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
981 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
986 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
987 rv
->family
= p
->family
;
988 rv
->prefixlen
= p
->prefixlen
;
989 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
993 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
994 struct sbuf
*buf
, int indent
)
999 char prefixbuf
[PREFIX2STR_BUFFER
];
1000 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
1001 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
1004 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
1010 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
1013 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
1014 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
1015 stream_putc(s
, p
->prefixlen
);
1016 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
1020 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
1021 uint8_t tlv_type
, uint8_t tlv_len
,
1022 struct stream
*s
, struct sbuf
*log
,
1023 void *dest
, int indent
)
1025 struct isis_subtlvs
*subtlvs
= dest
;
1026 struct prefix_ipv6 p
= {
1030 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1033 sbuf_push(log
, indent
,
1034 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1039 p
.prefixlen
= stream_getc(s
);
1040 if (p
.prefixlen
> IPV6_MAX_BITLEN
) {
1041 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
1046 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
1049 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1050 1 + PSIZE(p
.prefixlen
), tlv_len
);
1054 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
1056 if (subtlvs
->source_prefix
) {
1059 "WARNING: source prefix Sub-TLV present multiple times.\n");
1060 /* Ignore all but first occurrence of the source prefix Sub-TLV
1065 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
1066 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
1070 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1071 enum isis_tlv_type type
,
1072 struct isis_item
*item
);
1073 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1074 struct isis_item_list
*src
, struct isis_item_list
*dest
);
1075 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1076 enum isis_tlv_type type
, struct isis_item_list
*items
,
1077 struct sbuf
*buf
, int indent
);
1078 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1079 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1080 struct isis_item_list
*items
);
1081 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1082 enum isis_tlv_type type
, struct isis_item_list
*items
,
1083 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1084 const struct pack_order_entry
*pe
,
1085 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1086 struct list
*new_fragment_arg
);
1087 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1089 /* Functions related to subtlvs */
1091 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1093 struct isis_subtlvs
*result
;
1095 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1096 result
->context
= context
;
1098 init_item_list(&result
->prefix_sids
);
1103 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1108 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1110 rv
->context
= subtlvs
->context
;
1112 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1113 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1116 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1120 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1123 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1124 &subtlvs
->prefix_sids
, buf
, indent
);
1126 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
1129 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1134 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1135 &subtlvs
->prefix_sids
);
1137 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1139 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1142 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1145 size_t subtlv_len_pos
= stream_get_endp(s
);
1147 if (STREAM_WRITEABLE(s
) < 1)
1150 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1152 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1153 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1157 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1161 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1162 if (subtlv_len
> 255)
1165 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1169 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1170 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1171 int indent
, bool *unpacked_known_tlvs
);
1173 /* Functions related to TLVs 1 Area Addresses */
1175 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1177 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1178 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1180 rv
->len
= addr
->len
;
1181 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1182 return (struct isis_item
*)rv
;
1185 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1186 struct sbuf
*buf
, int indent
)
1188 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1190 sbuf_push(buf
, indent
, "Area Address: %s\n",
1191 isonet_print(addr
->addr
, addr
->len
));
1194 static void free_item_area_address(struct isis_item
*i
)
1196 XFREE(MTYPE_ISIS_TLV
, i
);
1199 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
,
1202 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1204 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
) {
1205 *min_len
= (unsigned)1 + addr
->len
;
1208 stream_putc(s
, addr
->len
);
1209 stream_put(s
, addr
->addr
, addr
->len
);
1213 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1214 struct stream
*s
, struct sbuf
*log
,
1215 void *dest
, int indent
)
1217 struct isis_tlvs
*tlvs
= dest
;
1218 struct isis_area_address
*rv
= NULL
;
1220 sbuf_push(log
, indent
, "Unpack area address...\n");
1224 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1229 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1230 rv
->len
= stream_getc(s
);
1232 if (len
< 1 + rv
->len
) {
1233 sbuf_push(log
, indent
, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1238 if (rv
->len
< 1 || rv
->len
> 20) {
1239 sbuf_push(log
, indent
,
1240 "Implausible area address length %hhu\n",
1245 stream_get(rv
->addr
, s
, rv
->len
);
1247 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1249 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1252 XFREE(MTYPE_ISIS_TLV
, rv
);
1256 /* Functions related to TLV 2 (Old-Style) IS Reach */
1257 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1259 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1260 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1262 memcpy(rv
->id
, r
->id
, 7);
1263 rv
->metric
= r
->metric
;
1264 return (struct isis_item
*)rv
;
1267 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1268 struct sbuf
*buf
, int indent
)
1270 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1272 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %hhu)\n",
1273 isis_format_id(r
->id
, 7), r
->metric
);
1276 static void free_item_oldstyle_reach(struct isis_item
*i
)
1278 XFREE(MTYPE_ISIS_TLV
, i
);
1281 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
,
1284 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1286 if (STREAM_WRITEABLE(s
) < 11) {
1291 stream_putc(s
, r
->metric
);
1292 stream_putc(s
, 0x80); /* delay metric - unsupported */
1293 stream_putc(s
, 0x80); /* expense metric - unsupported */
1294 stream_putc(s
, 0x80); /* error metric - unsupported */
1295 stream_put(s
, r
->id
, 7);
1300 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1301 struct stream
*s
, struct sbuf
*log
,
1302 void *dest
, int indent
)
1304 struct isis_tlvs
*tlvs
= dest
;
1306 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1310 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1315 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1316 rv
->metric
= stream_getc(s
);
1317 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1318 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1321 stream_forward_getp(s
, 3); /* Skip other metrics */
1322 stream_get(rv
->id
, s
, 7);
1324 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
1326 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1330 /* Functions related to TLV 6 LAN Neighbors */
1331 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1333 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1334 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1336 memcpy(rv
->mac
, n
->mac
, 6);
1337 return (struct isis_item
*)rv
;
1340 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1341 struct sbuf
*buf
, int indent
)
1343 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1345 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
1348 static void free_item_lan_neighbor(struct isis_item
*i
)
1350 XFREE(MTYPE_ISIS_TLV
, i
);
1353 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
,
1356 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1358 if (STREAM_WRITEABLE(s
) < 6) {
1363 stream_put(s
, n
->mac
, 6);
1368 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1369 struct stream
*s
, struct sbuf
*log
,
1370 void *dest
, int indent
)
1372 struct isis_tlvs
*tlvs
= dest
;
1374 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1378 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1383 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1384 stream_get(rv
->mac
, s
, 6);
1386 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1387 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1391 /* Functions related to TLV 9 LSP Entry */
1392 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1394 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1395 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1397 rv
->rem_lifetime
= e
->rem_lifetime
;
1398 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1399 rv
->seqno
= e
->seqno
;
1400 rv
->checksum
= e
->checksum
;
1402 return (struct isis_item
*)rv
;
1405 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1406 struct sbuf
*buf
, int indent
)
1408 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1410 sbuf_push(buf
, indent
,
1411 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1412 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1416 static void free_item_lsp_entry(struct isis_item
*i
)
1418 XFREE(MTYPE_ISIS_TLV
, i
);
1421 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
,
1424 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1426 if (STREAM_WRITEABLE(s
) < 16) {
1431 stream_putw(s
, e
->rem_lifetime
);
1432 stream_put(s
, e
->id
, 8);
1433 stream_putl(s
, e
->seqno
);
1434 stream_putw(s
, e
->checksum
);
1439 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1440 struct sbuf
*log
, void *dest
, int indent
)
1442 struct isis_tlvs
*tlvs
= dest
;
1444 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1448 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1453 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1454 rv
->rem_lifetime
= stream_getw(s
);
1455 stream_get(rv
->id
, s
, 8);
1456 rv
->seqno
= stream_getl(s
);
1457 rv
->checksum
= stream_getw(s
);
1459 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1460 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1464 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1466 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1468 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1469 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1471 memcpy(rv
->id
, r
->id
, 7);
1472 rv
->metric
= r
->metric
;
1475 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1477 return (struct isis_item
*)rv
;
1480 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1481 struct sbuf
*buf
, int indent
)
1483 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1485 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1486 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1487 isis_format_id(r
->id
, 7), r
->metric
);
1488 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1489 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1490 sbuf_push(buf
, 0, "\n");
1493 format_item_ext_subtlvs(r
->subtlvs
, buf
, indent
+ 2, mtid
);
1496 static void free_item_extended_reach(struct isis_item
*i
)
1498 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1499 if (item
->subtlvs
!= NULL
)
1500 free_item_ext_subtlvs(item
->subtlvs
);
1501 XFREE(MTYPE_ISIS_TLV
, item
);
1504 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
,
1507 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1511 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
) {
1512 *min_len
= 11 + ISIS_SUBTLV_MAX_SIZE
;
1516 stream_put(s
, r
->id
, sizeof(r
->id
));
1517 stream_put3(s
, r
->metric
);
1518 len_pos
= stream_get_endp(s
);
1519 /* Real length will be adjust after adding subTLVs */
1522 pack_item_ext_subtlvs(r
->subtlvs
, s
, min_len
);
1524 len
= stream_get_endp(s
) - len_pos
- 1;
1525 stream_putc_at(s
, len_pos
, len
);
1529 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1530 struct stream
*s
, struct sbuf
*log
,
1531 void *dest
, int indent
)
1533 struct isis_tlvs
*tlvs
= dest
;
1534 struct isis_extended_reach
*rv
= NULL
;
1536 struct isis_item_list
*items
;
1538 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1539 items
= &tlvs
->extended_reach
;
1541 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1544 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1545 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1548 sbuf_push(log
, indent
,
1549 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
1554 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1555 stream_get(rv
->id
, s
, 7);
1556 rv
->metric
= stream_get3(s
);
1557 subtlv_len
= stream_getc(s
);
1559 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1560 sbuf_push(log
, indent
,
1561 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
1562 subtlv_len
, len
- 11);
1566 sbuf_push(log
, indent
, "Storing %hhu bytes of subtlvs\n",
1570 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1576 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
1578 append_item(items
, (struct isis_item
*)rv
);
1582 free_item_extended_reach((struct isis_item
*)rv
);
1587 /* Functions related to TLV 128 (Old-Style) IP Reach */
1588 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1590 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1591 struct isis_oldstyle_ip_reach
*rv
=
1592 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1594 rv
->metric
= r
->metric
;
1595 rv
->prefix
= r
->prefix
;
1596 return (struct isis_item
*)rv
;
1599 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1600 struct sbuf
*buf
, int indent
)
1602 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1603 char prefixbuf
[PREFIX2STR_BUFFER
];
1605 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %hhu)\n",
1606 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1610 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
1612 XFREE(MTYPE_ISIS_TLV
, i
);
1615 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
,
1618 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1620 if (STREAM_WRITEABLE(s
) < 12) {
1625 stream_putc(s
, r
->metric
);
1626 stream_putc(s
, 0x80); /* delay metric - unsupported */
1627 stream_putc(s
, 0x80); /* expense metric - unsupported */
1628 stream_putc(s
, 0x80); /* error metric - unsupported */
1629 stream_put(s
, &r
->prefix
.prefix
, 4);
1631 struct in_addr mask
;
1632 masklen2ip(r
->prefix
.prefixlen
, &mask
);
1633 stream_put(s
, &mask
, sizeof(mask
));
1638 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
1639 struct stream
*s
, struct sbuf
*log
,
1640 void *dest
, int indent
)
1642 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
1646 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
1651 struct isis_oldstyle_ip_reach
*rv
=
1652 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1653 rv
->metric
= stream_getc(s
);
1654 if ((rv
->metric
& 0x7f) != rv
->metric
) {
1655 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1658 stream_forward_getp(s
, 3); /* Skip other metrics */
1659 rv
->prefix
.family
= AF_INET
;
1660 stream_get(&rv
->prefix
.prefix
, s
, 4);
1662 struct in_addr mask
;
1663 stream_get(&mask
, s
, 4);
1664 rv
->prefix
.prefixlen
= ip_masklen(mask
);
1666 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1668 append_item(dest
, (struct isis_item
*)rv
);
1673 /* Functions related to TLV 129 protocols supported */
1675 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
1676 struct isis_protocols_supported
*dest
)
1678 if (!src
->protocols
|| !src
->count
)
1680 dest
->count
= src
->count
;
1681 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
1682 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
1685 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
1686 struct sbuf
*buf
, int indent
)
1688 if (!p
|| !p
->count
|| !p
->protocols
)
1691 sbuf_push(buf
, indent
, "Protocols Supported: ");
1692 for (uint8_t i
= 0; i
< p
->count
; i
++) {
1693 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
1694 (i
+ 1 < p
->count
) ? ", " : "");
1696 sbuf_push(buf
, 0, "\n");
1699 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
1701 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
1704 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
1707 if (!p
|| !p
->count
|| !p
->protocols
)
1710 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
1713 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
1714 stream_putc(s
, p
->count
);
1715 stream_put(s
, p
->protocols
, p
->count
);
1719 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
1720 uint8_t tlv_type
, uint8_t tlv_len
,
1721 struct stream
*s
, struct sbuf
*log
,
1722 void *dest
, int indent
)
1724 struct isis_tlvs
*tlvs
= dest
;
1726 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
1728 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
1731 if (tlvs
->protocols_supported
.protocols
) {
1734 "WARNING: protocols supported TLV present multiple times.\n");
1735 stream_forward_getp(s
, tlv_len
);
1739 tlvs
->protocols_supported
.count
= tlv_len
;
1740 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
1741 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
1743 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
1748 /* Functions related to TLV 132 IPv4 Interface addresses */
1749 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
1751 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1752 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1755 return (struct isis_item
*)rv
;
1758 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
1759 struct sbuf
*buf
, int indent
)
1761 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1762 char addrbuf
[INET_ADDRSTRLEN
];
1764 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1765 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
1768 static void free_item_ipv4_address(struct isis_item
*i
)
1770 XFREE(MTYPE_ISIS_TLV
, i
);
1773 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
,
1776 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1778 if (STREAM_WRITEABLE(s
) < 4) {
1783 stream_put(s
, &a
->addr
, 4);
1788 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
1789 struct stream
*s
, struct sbuf
*log
,
1790 void *dest
, int indent
)
1792 struct isis_tlvs
*tlvs
= dest
;
1794 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
1798 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
1803 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1804 stream_get(&rv
->addr
, s
, 4);
1806 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1807 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
1812 /* Functions related to TLV 232 IPv6 Interface addresses */
1813 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
1815 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1816 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1819 return (struct isis_item
*)rv
;
1822 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
1823 struct sbuf
*buf
, int indent
)
1825 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1826 char addrbuf
[INET6_ADDRSTRLEN
];
1828 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1829 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
1832 static void free_item_ipv6_address(struct isis_item
*i
)
1834 XFREE(MTYPE_ISIS_TLV
, i
);
1837 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
,
1840 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1842 if (STREAM_WRITEABLE(s
) < 16) {
1847 stream_put(s
, &a
->addr
, 16);
1852 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
1853 struct stream
*s
, struct sbuf
*log
,
1854 void *dest
, int indent
)
1856 struct isis_tlvs
*tlvs
= dest
;
1858 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
1862 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
1867 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1868 stream_get(&rv
->addr
, s
, 16);
1870 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1871 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
1876 /* Functions related to TLV 229 MT Router information */
1877 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
1879 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1880 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1882 rv
->overload
= info
->overload
;
1883 rv
->attached
= info
->attached
;
1884 rv
->mtid
= info
->mtid
;
1885 return (struct isis_item
*)rv
;
1888 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
1889 struct sbuf
*buf
, int indent
)
1891 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1893 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
1894 isis_mtid2str(info
->mtid
),
1895 info
->overload
? " Overload" : "",
1896 info
->attached
? " Attached" : "");
1899 static void free_item_mt_router_info(struct isis_item
*i
)
1901 XFREE(MTYPE_ISIS_TLV
, i
);
1904 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
,
1907 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1909 if (STREAM_WRITEABLE(s
) < 2) {
1914 uint16_t entry
= info
->mtid
;
1917 entry
|= ISIS_MT_OL_MASK
;
1919 entry
|= ISIS_MT_AT_MASK
;
1921 stream_putw(s
, entry
);
1926 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1927 struct stream
*s
, struct sbuf
*log
,
1928 void *dest
, int indent
)
1930 struct isis_tlvs
*tlvs
= dest
;
1932 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1936 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
1941 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1943 uint16_t entry
= stream_getw(s
);
1944 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1945 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1946 rv
->mtid
= entry
& ISIS_MT_MASK
;
1948 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1950 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1954 /* Functions related to TLV 134 TE Router ID */
1956 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1961 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1962 memcpy(rv
, id
, sizeof(*rv
));
1966 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1972 char addrbuf
[INET_ADDRSTRLEN
];
1973 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1974 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1977 static void free_tlv_te_router_id(struct in_addr
*id
)
1979 XFREE(MTYPE_ISIS_TLV
, id
);
1982 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1987 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1990 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1992 stream_put(s
, id
, 4);
1996 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1997 uint8_t tlv_type
, uint8_t tlv_len
,
1998 struct stream
*s
, struct sbuf
*log
,
1999 void *dest
, int indent
)
2001 struct isis_tlvs
*tlvs
= dest
;
2003 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
2005 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
2009 if (tlvs
->te_router_id
) {
2010 sbuf_push(log
, indent
,
2011 "WARNING: TE Router ID present multiple times.\n");
2012 stream_forward_getp(s
, tlv_len
);
2016 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
2017 stream_get(tlvs
->te_router_id
, s
, 4);
2018 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
2023 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
2025 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
2027 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2028 struct isis_extended_ip_reach
*rv
=
2029 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2031 rv
->metric
= r
->metric
;
2033 rv
->prefix
= r
->prefix
;
2034 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2036 return (struct isis_item
*)rv
;
2039 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
2040 struct sbuf
*buf
, int indent
)
2042 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2043 char prefixbuf
[PREFIX2STR_BUFFER
];
2045 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
2046 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
2047 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
2048 r
->down
? " Down" : "");
2049 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2050 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2051 sbuf_push(buf
, 0, "\n");
2054 sbuf_push(buf
, indent
, " Subtlvs:\n");
2055 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
2059 static void free_item_extended_ip_reach(struct isis_item
*i
)
2061 struct isis_extended_ip_reach
*item
=
2062 (struct isis_extended_ip_reach
*)i
;
2063 isis_free_subtlvs(item
->subtlvs
);
2064 XFREE(MTYPE_ISIS_TLV
, item
);
2067 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
,
2070 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
2073 if (STREAM_WRITEABLE(s
) < 5) {
2077 stream_putl(s
, r
->metric
);
2079 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
2080 control
|= r
->prefix
.prefixlen
;
2081 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
2083 stream_putc(s
, control
);
2085 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2086 *min_len
= 5 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2089 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
2092 return pack_subtlvs(r
->subtlvs
, s
);
2096 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
2097 struct stream
*s
, struct sbuf
*log
,
2098 void *dest
, int indent
)
2100 struct isis_tlvs
*tlvs
= dest
;
2101 struct isis_extended_ip_reach
*rv
= NULL
;
2103 uint8_t control
, subtlv_len
;
2104 struct isis_item_list
*items
;
2106 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2107 items
= &tlvs
->extended_ip_reach
;
2109 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2112 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2113 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2116 if (len
< consume
) {
2117 sbuf_push(log
, indent
,
2118 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2123 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2125 rv
->metric
= stream_getl(s
);
2126 control
= stream_getc(s
);
2127 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2128 rv
->prefix
.family
= AF_INET
;
2129 rv
->prefix
.prefixlen
= control
& 0x3f;
2130 if (rv
->prefix
.prefixlen
> IPV4_MAX_BITLEN
) {
2131 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2132 rv
->prefix
.prefixlen
);
2136 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2137 if (len
< consume
) {
2138 sbuf_push(log
, indent
,
2139 "Expected %u bytes of prefix, but only %u bytes available.\n",
2140 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2143 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2144 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2145 apply_mask_ipv4(&rv
->prefix
);
2146 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2147 sbuf_push(log
, indent
+ 2,
2148 "WARNING: Prefix had hostbits set.\n");
2149 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
2152 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2154 if (len
< consume
) {
2155 sbuf_push(log
, indent
,
2156 "Expected 1 byte of subtlv len, but no more data present.\n");
2159 subtlv_len
= stream_getc(s
);
2162 sbuf_push(log
, indent
+ 2,
2163 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2165 consume
+= subtlv_len
;
2166 if (len
< consume
) {
2167 sbuf_push(log
, indent
,
2168 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2170 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2174 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2175 bool unpacked_known_tlvs
= false;
2177 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2178 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2181 if (!unpacked_known_tlvs
) {
2182 isis_free_subtlvs(rv
->subtlvs
);
2187 append_item(items
, (struct isis_item
*)rv
);
2191 free_item_extended_ip_reach((struct isis_item
*)rv
);
2195 /* Functions related to TLV 137 Dynamic Hostname */
2197 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2202 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2205 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2211 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2214 static void free_tlv_dynamic_hostname(char *hostname
)
2216 XFREE(MTYPE_ISIS_TLV
, hostname
);
2219 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2224 uint8_t name_len
= strlen(hostname
);
2226 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2229 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2230 stream_putc(s
, name_len
);
2231 stream_put(s
, hostname
, name_len
);
2235 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2236 uint8_t tlv_type
, uint8_t tlv_len
,
2237 struct stream
*s
, struct sbuf
*log
,
2238 void *dest
, int indent
)
2240 struct isis_tlvs
*tlvs
= dest
;
2242 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2244 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2248 if (tlvs
->hostname
) {
2249 sbuf_push(log
, indent
,
2250 "WARNING: Hostname present multiple times.\n");
2251 stream_forward_getp(s
, tlv_len
);
2255 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2256 stream_get(tlvs
->hostname
, s
, tlv_len
);
2257 tlvs
->hostname
[tlv_len
] = '\0';
2260 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2261 if ((unsigned char)tlvs
->hostname
[i
] > 127
2262 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2264 tlvs
->hostname
[i
] = '?';
2270 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2276 /* Functions related to TLV 150 Spine-Leaf-Extension */
2278 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2279 const struct isis_spine_leaf
*spine_leaf
)
2284 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2285 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2290 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2291 struct sbuf
*buf
, int indent
)
2296 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2297 if (spine_leaf
->has_tier
) {
2298 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2299 sbuf_push(buf
, indent
, " Tier: undefined\n");
2301 sbuf_push(buf
, indent
, " Tier: %hhu\n",
2306 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2307 spine_leaf
->is_leaf
? " LEAF" : "",
2308 spine_leaf
->is_spine
? " SPINE" : "",
2309 spine_leaf
->is_backup
? " BACKUP" : "");
2313 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2315 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2318 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2319 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2320 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2321 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2323 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2329 uint8_t tlv_len
= 2;
2331 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2334 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2335 stream_putc(s
, tlv_len
);
2337 uint16_t spine_leaf_flags
= 0;
2339 if (spine_leaf
->has_tier
) {
2340 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2341 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2344 if (spine_leaf
->is_leaf
)
2345 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2347 if (spine_leaf
->is_spine
)
2348 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
2350 if (spine_leaf
->is_backup
)
2351 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
2353 stream_putw(s
, spine_leaf_flags
);
2358 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
2359 uint8_t tlv_type
, uint8_t tlv_len
,
2360 struct stream
*s
, struct sbuf
*log
,
2361 void *dest
, int indent
)
2363 struct isis_tlvs
*tlvs
= dest
;
2365 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
2367 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2368 stream_forward_getp(s
, tlv_len
);
2372 if (tlvs
->spine_leaf
) {
2373 sbuf_push(log
, indent
,
2374 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
2375 stream_forward_getp(s
, tlv_len
);
2379 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
2381 uint16_t spine_leaf_flags
= stream_getw(s
);
2383 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
2384 tlvs
->spine_leaf
->has_tier
= true;
2385 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
2388 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
2389 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
2390 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
2392 stream_forward_getp(s
, tlv_len
- 2);
2396 /* Functions related to TLV 240 P2P Three-Way Adjacency */
2398 const char *isis_threeway_state_name(enum isis_threeway_state state
)
2401 case ISIS_THREEWAY_DOWN
:
2403 case ISIS_THREEWAY_INITIALIZING
:
2404 return "Initializing";
2405 case ISIS_THREEWAY_UP
:
2412 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
2413 const struct isis_threeway_adj
*threeway_adj
)
2418 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2419 memcpy(rv
, threeway_adj
, sizeof(*rv
));
2424 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
2425 struct sbuf
*buf
, int indent
)
2430 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
2431 sbuf_push(buf
, indent
, " State: %s (%d)\n",
2432 isis_threeway_state_name(threeway_adj
->state
),
2433 threeway_adj
->state
);
2434 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %u\n",
2435 threeway_adj
->local_circuit_id
);
2436 if (!threeway_adj
->neighbor_set
)
2439 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
2440 isis_format_id(threeway_adj
->neighbor_id
, 6));
2441 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %u\n",
2442 threeway_adj
->neighbor_circuit_id
);
2445 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
2447 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
2450 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
2456 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
2458 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2461 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
2462 stream_putc(s
, tlv_len
);
2463 stream_putc(s
, threeway_adj
->state
);
2464 stream_putl(s
, threeway_adj
->local_circuit_id
);
2466 if (threeway_adj
->neighbor_set
) {
2467 stream_put(s
, threeway_adj
->neighbor_id
, 6);
2468 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
2474 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
2475 uint8_t tlv_type
, uint8_t tlv_len
,
2476 struct stream
*s
, struct sbuf
*log
,
2477 void *dest
, int indent
)
2479 struct isis_tlvs
*tlvs
= dest
;
2481 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
2482 if (tlv_len
!= 5 && tlv_len
!= 15) {
2483 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2484 stream_forward_getp(s
, tlv_len
);
2488 if (tlvs
->threeway_adj
) {
2489 sbuf_push(log
, indent
,
2490 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
2491 stream_forward_getp(s
, tlv_len
);
2495 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
2497 tlvs
->threeway_adj
->state
= stream_getc(s
);
2498 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
2500 if (tlv_len
== 15) {
2501 tlvs
->threeway_adj
->neighbor_set
= true;
2502 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
2503 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
2509 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
2510 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
2512 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2513 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2515 rv
->metric
= r
->metric
;
2517 rv
->external
= r
->external
;
2518 rv
->prefix
= r
->prefix
;
2519 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2521 return (struct isis_item
*)rv
;
2524 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
2525 struct sbuf
*buf
, int indent
)
2527 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2528 char prefixbuf
[PREFIX2STR_BUFFER
];
2530 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
2531 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
2532 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2534 r
->down
? " Down" : "",
2535 r
->external
? " External" : "");
2536 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2537 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2538 sbuf_push(buf
, 0, "\n");
2541 sbuf_push(buf
, indent
, " Subtlvs:\n");
2542 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
2546 static void free_item_ipv6_reach(struct isis_item
*i
)
2548 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
2550 isis_free_subtlvs(item
->subtlvs
);
2551 XFREE(MTYPE_ISIS_TLV
, item
);
2554 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
,
2557 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2560 if (STREAM_WRITEABLE(s
) < 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
)) {
2561 *min_len
= 6 + (unsigned)PSIZE(r
->prefix
.prefixlen
);
2564 stream_putl(s
, r
->metric
);
2566 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
2567 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
2568 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
2570 stream_putc(s
, control
);
2571 stream_putc(s
, r
->prefix
.prefixlen
);
2573 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
2576 return pack_subtlvs(r
->subtlvs
, s
);
2581 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
2582 struct sbuf
*log
, void *dest
, int indent
)
2584 struct isis_tlvs
*tlvs
= dest
;
2585 struct isis_ipv6_reach
*rv
= NULL
;
2587 uint8_t control
, subtlv_len
;
2588 struct isis_item_list
*items
;
2590 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2591 items
= &tlvs
->ipv6_reach
;
2593 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
2596 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
2597 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
2599 if (len
< consume
) {
2600 sbuf_push(log
, indent
,
2601 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
2606 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2608 rv
->metric
= stream_getl(s
);
2609 control
= stream_getc(s
);
2610 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
2611 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
2613 rv
->prefix
.family
= AF_INET6
;
2614 rv
->prefix
.prefixlen
= stream_getc(s
);
2615 if (rv
->prefix
.prefixlen
> IPV6_MAX_BITLEN
) {
2616 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
2617 rv
->prefix
.prefixlen
);
2621 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2622 if (len
< consume
) {
2623 sbuf_push(log
, indent
,
2624 "Expected %u bytes of prefix, but only %u bytes available.\n",
2625 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
2628 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2629 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
2631 apply_mask_ipv6(&rv
->prefix
);
2632 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
2633 sbuf_push(log
, indent
+ 2,
2634 "WARNING: Prefix had hostbits set.\n");
2635 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2637 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
2639 if (len
< consume
) {
2640 sbuf_push(log
, indent
,
2641 "Expected 1 byte of subtlv len, but no more data persent.\n");
2644 subtlv_len
= stream_getc(s
);
2647 sbuf_push(log
, indent
+ 2,
2648 " WARNING: subtlv bit set, but there are no subtlvs.\n");
2650 consume
+= subtlv_len
;
2651 if (len
< consume
) {
2652 sbuf_push(log
, indent
,
2653 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2655 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2659 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
2660 bool unpacked_known_tlvs
= false;
2662 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
2663 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2666 if (!unpacked_known_tlvs
) {
2667 isis_free_subtlvs(rv
->subtlvs
);
2672 append_item(items
, (struct isis_item
*)rv
);
2676 free_item_ipv6_reach((struct isis_item
*)rv
);
2680 /* Functions related to TLV 242 Router Capability as per RFC7981 */
2681 static struct isis_router_cap
*copy_tlv_router_cap(
2682 const struct isis_router_cap
*router_cap
)
2684 struct isis_router_cap
*rv
;
2689 rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2691 memcpy(rv
, router_cap
, sizeof(*rv
));
2696 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
2697 struct sbuf
*buf
, int indent
)
2699 char addrbuf
[INET_ADDRSTRLEN
];
2704 /* Router ID and Flags */
2705 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
2706 sbuf_push(buf
, indent
, "Router Capability:");
2707 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
2708 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
2709 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
2711 /* Segment Routing Global Block as per RFC8667 section #3.1 */
2712 if (router_cap
->srgb
.range_size
!= 0)
2715 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
2716 IS_SR_IPV4(&router_cap
->srgb
) ? "1" : "0",
2717 IS_SR_IPV6(&router_cap
->srgb
) ? "1" : "0",
2718 router_cap
->srgb
.lower_bound
,
2719 router_cap
->srgb
.range_size
);
2721 /* Segment Routing Local Block as per RFC8667 section #3.3 */
2722 if (router_cap
->srlb
.range_size
!= 0)
2723 sbuf_push(buf
, indent
, " SR Local Block Base: %u Range: %u\n",
2724 router_cap
->srlb
.lower_bound
,
2725 router_cap
->srlb
.range_size
);
2727 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
2728 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
2729 sbuf_push(buf
, indent
, " SR Algorithm:\n");
2730 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
2731 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
2732 sbuf_push(buf
, indent
, " %u: %s\n", i
,
2733 router_cap
->algo
[i
] == 0
2738 /* Segment Routing Node MSD as per RFC8491 section #2 */
2739 if (router_cap
->msd
!= 0)
2740 sbuf_push(buf
, indent
, " Node Maximum SID Depth: %u\n",
2744 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
2746 XFREE(MTYPE_ISIS_TLV
, router_cap
);
2749 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
2752 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
2759 /* Compute Maximum TLV size */
2760 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
2761 + ISIS_SUBTLV_HDR_SIZE
2762 + ISIS_SUBTLV_ALGORITHM_SIZE
2763 + ISIS_SUBTLV_NODE_MSD_SIZE
;
2765 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
2768 /* Add Router Capability TLV 242 with Router ID and Flags */
2769 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
2770 /* Real length will be adjusted later */
2771 len_pos
= stream_get_endp(s
);
2772 stream_putc(s
, tlv_len
);
2773 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
2774 stream_putc(s
, router_cap
->flags
);
2776 /* Add SRGB if set as per RFC8667 section #3.1 */
2777 if ((router_cap
->srgb
.range_size
!= 0)
2778 && (router_cap
->srgb
.lower_bound
!= 0)) {
2779 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
2780 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
2781 stream_putc(s
, router_cap
->srgb
.flags
);
2782 stream_put3(s
, router_cap
->srgb
.range_size
);
2783 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
2784 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
2785 stream_put3(s
, router_cap
->srgb
.lower_bound
);
2787 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
2788 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
2789 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
2792 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
2793 stream_putc(s
, nb_algo
);
2794 for (int i
= 0; i
< nb_algo
; i
++)
2795 stream_putc(s
, router_cap
->algo
[i
]);
2798 /* Local Block if defined as per RFC8667 section #3.3 */
2799 if ((router_cap
->srlb
.range_size
!= 0)
2800 && (router_cap
->srlb
.lower_bound
!= 0)) {
2801 stream_putc(s
, ISIS_SUBTLV_SRLB
);
2802 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
2803 /* No Flags are defined for SRLB */
2805 stream_put3(s
, router_cap
->srlb
.range_size
);
2806 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
2807 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
2808 stream_put3(s
, router_cap
->srlb
.lower_bound
);
2811 /* And finish with MSD if set as per RFC8491 section #2 */
2812 if (router_cap
->msd
!= 0) {
2813 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
2814 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
2815 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
2816 stream_putc(s
, router_cap
->msd
);
2820 /* Adjust TLV length which depends on subTLVs presence */
2821 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
2822 stream_putc_at(s
, len_pos
, tlv_len
);
2827 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
2828 uint8_t tlv_type
, uint8_t tlv_len
,
2829 struct stream
*s
, struct sbuf
*log
,
2830 void *dest
, int indent
)
2832 struct isis_tlvs
*tlvs
= dest
;
2833 struct isis_router_cap
*rcap
;
2839 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
2840 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
2841 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2842 stream_forward_getp(s
, tlv_len
);
2846 if (tlvs
->router_cap
) {
2847 sbuf_push(log
, indent
,
2848 "WARNING: Router Capability TLV present multiple times.\n");
2849 stream_forward_getp(s
, tlv_len
);
2853 /* Allocate router cap structure and initialize SR Algorithms */
2854 rcap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct isis_router_cap
));
2855 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
2856 rcap
->algo
[i
] = SR_ALGORITHM_UNSET
;
2858 /* Get Router ID and Flags */
2859 rcap
->router_id
.s_addr
= stream_get_ipv4(s
);
2860 rcap
->flags
= stream_getc(s
);
2862 /* Parse remaining part of the TLV if present */
2863 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
2864 while (subtlv_len
> 2) {
2867 type
= stream_getc(s
);
2868 length
= stream_getc(s
);
2870 case ISIS_SUBTLV_SID_LABEL_RANGE
:
2871 /* Check that SRGB is correctly formated */
2872 if (length
< SUBTLV_RANGE_LABEL_SIZE
2873 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
2874 stream_forward_getp(s
, length
);
2877 /* Only one SRGB is supported. Skip subsequent one */
2878 if (rcap
->srgb
.range_size
!= 0) {
2879 stream_forward_getp(s
, length
);
2882 rcap
->srgb
.flags
= stream_getc(s
);
2883 rcap
->srgb
.range_size
= stream_get3(s
);
2884 /* Skip Type and get Length of SID Label */
2886 size
= stream_getc(s
);
2887 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
)
2888 rcap
->srgb
.lower_bound
= stream_get3(s
);
2890 rcap
->srgb
.lower_bound
= stream_getl(s
);
2892 /* SRGB sanity checks. */
2893 if (rcap
->srgb
.range_size
== 0
2894 || (rcap
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
2895 || ((rcap
->srgb
.lower_bound
+ rcap
->srgb
.range_size
- 1)
2896 > MPLS_LABEL_UNRESERVED_MAX
)) {
2897 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
2898 rcap
->srgb
.lower_bound
= 0;
2899 rcap
->srgb
.range_size
= 0;
2901 /* Only one range is supported. Skip subsequent one */
2902 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
2904 stream_forward_getp(s
, length
);
2906 case ISIS_SUBTLV_ALGORITHM
:
2907 /* Only 2 algorithms are supported: SPF & Strict SPF */
2908 stream_get(&rcap
->algo
, s
,
2909 length
> SR_ALGORITHM_COUNT
2910 ? SR_ALGORITHM_COUNT
2912 if (length
> SR_ALGORITHM_COUNT
)
2913 stream_forward_getp(
2914 s
, length
- SR_ALGORITHM_COUNT
);
2916 case ISIS_SUBTLV_SRLB
:
2917 /* Check that SRLB is correctly formated */
2918 if (length
< SUBTLV_RANGE_LABEL_SIZE
2919 || length
> SUBTLV_RANGE_INDEX_SIZE
) {
2920 stream_forward_getp(s
, length
);
2923 /* RFC 8667 section #3.3: Only one SRLB is authorized */
2924 if (rcap
->srlb
.range_size
!= 0) {
2925 stream_forward_getp(s
, length
);
2928 /* Ignore Flags which are not defined */
2930 rcap
->srlb
.range_size
= stream_get3(s
);
2931 /* Skip Type and get Length of SID Label */
2933 size
= stream_getc(s
);
2934 if (size
== ISIS_SUBTLV_SID_LABEL_SIZE
)
2935 rcap
->srlb
.lower_bound
= stream_get3(s
);
2937 rcap
->srlb
.lower_bound
= stream_getl(s
);
2939 /* SRLB sanity checks. */
2940 if (rcap
->srlb
.range_size
== 0
2941 || (rcap
->srlb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
2942 || ((rcap
->srlb
.lower_bound
+ rcap
->srlb
.range_size
- 1)
2943 > MPLS_LABEL_UNRESERVED_MAX
)) {
2944 sbuf_push(log
, indent
, "Invalid label range. Reset SRLB\n");
2945 rcap
->srlb
.lower_bound
= 0;
2946 rcap
->srlb
.range_size
= 0;
2948 /* Only one range is supported. Skip subsequent one */
2949 size
= length
- (size
+ SUBTLV_SR_BLOCK_SIZE
);
2951 stream_forward_getp(s
, length
);
2953 case ISIS_SUBTLV_NODE_MSD
:
2954 /* Check that MSD is correctly formated */
2955 if (length
< MSD_TLV_SIZE
) {
2956 stream_forward_getp(s
, length
);
2959 msd_type
= stream_getc(s
);
2960 rcap
->msd
= stream_getc(s
);
2961 /* Only BMI-MSD type has been defined in RFC 8491 */
2962 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
2964 /* Only one MSD is standardized. Skip others */
2965 if (length
> MSD_TLV_SIZE
)
2966 stream_forward_getp(s
, length
- MSD_TLV_SIZE
);
2969 stream_forward_getp(s
, length
);
2972 subtlv_len
= subtlv_len
- length
- 2;
2974 tlvs
->router_cap
= rcap
;
2978 /* Functions related to TLV 10 Authentication */
2979 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
2981 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2982 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2984 rv
->type
= auth
->type
;
2985 rv
->length
= auth
->length
;
2986 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
2987 return (struct isis_item
*)rv
;
2990 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
2991 struct sbuf
*buf
, int indent
)
2993 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2996 sbuf_push(buf
, indent
, "Authentication:\n");
2997 switch (auth
->type
) {
2998 case ISIS_PASSWD_TYPE_CLEARTXT
:
2999 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
3000 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
3002 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3003 for (unsigned int j
= 0; j
< 16; j
++) {
3004 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
,
3005 "%02hhx", auth
->value
[j
]);
3007 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
3010 sbuf_push(buf
, indent
, " Unknown (%hhu)\n", auth
->type
);
3015 static void free_item_auth(struct isis_item
*i
)
3017 XFREE(MTYPE_ISIS_TLV
, i
);
3020 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
,
3023 struct isis_auth
*auth
= (struct isis_auth
*)i
;
3025 if (STREAM_WRITEABLE(s
) < 1) {
3029 stream_putc(s
, auth
->type
);
3031 switch (auth
->type
) {
3032 case ISIS_PASSWD_TYPE_CLEARTXT
:
3033 if (STREAM_WRITEABLE(s
) < auth
->length
) {
3034 *min_len
= 1 + auth
->length
;
3037 stream_put(s
, auth
->passwd
, auth
->length
);
3039 case ISIS_PASSWD_TYPE_HMAC_MD5
:
3040 if (STREAM_WRITEABLE(s
) < 16) {
3044 auth
->offset
= stream_get_endp(s
);
3045 stream_put(s
, NULL
, 16);
3054 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
3055 struct sbuf
*log
, void *dest
, int indent
)
3057 struct isis_tlvs
*tlvs
= dest
;
3059 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
3063 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
3068 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3070 rv
->type
= stream_getc(s
);
3071 rv
->length
= len
- 1;
3073 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
3076 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
3078 XFREE(MTYPE_ISIS_TLV
, rv
);
3082 rv
->offset
= stream_get_getp(s
);
3083 stream_get(rv
->value
, s
, rv
->length
);
3084 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
3085 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
3089 /* Functions related to TLV 13 Purge Originator */
3091 static struct isis_purge_originator
*copy_tlv_purge_originator(
3092 struct isis_purge_originator
*poi
)
3097 struct isis_purge_originator
*rv
;
3099 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3100 rv
->sender_set
= poi
->sender_set
;
3101 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
3102 if (poi
->sender_set
)
3103 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
3107 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
3108 struct sbuf
*buf
, int indent
)
3113 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
3114 sbuf_push(buf
, indent
, " Generator: %s\n",
3115 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
3116 if (poi
->sender_set
) {
3117 sbuf_push(buf
, indent
, " Received-From: %s\n",
3118 isis_format_id(poi
->sender
, sizeof(poi
->sender
)));
3122 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
3124 XFREE(MTYPE_ISIS_TLV
, poi
);
3127 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
3133 uint8_t data_len
= 1 + sizeof(poi
->generator
);
3135 if (poi
->sender_set
)
3136 data_len
+= sizeof(poi
->sender
);
3138 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
3141 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
3142 stream_putc(s
, data_len
);
3143 stream_putc(s
, poi
->sender_set
? 2 : 1);
3144 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
3145 if (poi
->sender_set
)
3146 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
3150 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
3151 uint8_t tlv_type
, uint8_t tlv_len
,
3152 struct stream
*s
, struct sbuf
*log
,
3153 void *dest
, int indent
)
3155 struct isis_tlvs
*tlvs
= dest
;
3156 struct isis_purge_originator poi
= {};
3158 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
3160 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len
);
3164 uint8_t number_of_ids
= stream_getc(s
);
3166 if (number_of_ids
== 1) {
3167 poi
.sender_set
= false;
3168 } else if (number_of_ids
== 2) {
3169 poi
.sender_set
= true;
3171 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids
);
3175 if (tlv_len
!= 1 + 6 * number_of_ids
) {
3176 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
3180 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
3182 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
3184 if (tlvs
->purge_originator
) {
3185 sbuf_push(log
, indent
,
3186 "WARNING: Purge originator present multiple times, ignoring.\n");
3190 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
3195 /* Functions relating to item TLVs */
3197 static void init_item_list(struct isis_item_list
*items
)
3200 items
->tail
= &items
->head
;
3204 static struct isis_item
*copy_item(enum isis_tlv_context context
,
3205 enum isis_tlv_type type
,
3206 struct isis_item
*item
)
3208 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3210 if (ops
&& ops
->copy_item
)
3211 return ops
->copy_item(item
);
3213 assert(!"Unknown item tlv type!");
3217 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3218 struct isis_item_list
*src
, struct isis_item_list
*dest
)
3220 struct isis_item
*item
;
3222 init_item_list(dest
);
3224 for (item
= src
->head
; item
; item
= item
->next
) {
3225 append_item(dest
, copy_item(context
, type
, item
));
3229 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
3230 enum isis_tlv_type type
, struct isis_item
*i
,
3231 struct sbuf
*buf
, int indent
)
3233 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3235 if (ops
&& ops
->format_item
) {
3236 ops
->format_item(mtid
, i
, buf
, indent
);
3240 assert(!"Unknown item tlv type!");
3243 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
3244 enum isis_tlv_type type
, struct isis_item_list
*items
,
3245 struct sbuf
*buf
, int indent
)
3247 struct isis_item
*i
;
3249 for (i
= items
->head
; i
; i
= i
->next
)
3250 format_item(mtid
, context
, type
, i
, buf
, indent
);
3253 static void free_item(enum isis_tlv_context tlv_context
,
3254 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
3256 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
3258 if (ops
&& ops
->free_item
) {
3259 ops
->free_item(item
);
3263 assert(!"Unknown item tlv type!");
3266 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3267 struct isis_item_list
*items
)
3269 struct isis_item
*item
, *next_item
;
3271 for (item
= items
->head
; item
; item
= next_item
) {
3272 next_item
= item
->next
;
3273 free_item(context
, type
, item
);
3277 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
3278 struct isis_item
*i
, struct stream
*s
, size_t *min_len
,
3279 struct isis_tlvs
**fragment_tlvs
,
3280 const struct pack_order_entry
*pe
, uint16_t mtid
)
3282 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3284 if (ops
&& ops
->pack_item
) {
3285 return ops
->pack_item(i
, s
, min_len
);
3288 assert(!"Unknown item tlv type!");
3292 static void add_item_to_fragment(struct isis_item
*i
,
3293 const struct pack_order_entry
*pe
,
3294 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
3296 struct isis_item_list
*l
;
3298 if (pe
->how_to_pack
== ISIS_ITEMS
) {
3299 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
3301 struct isis_mt_item_list
*m
;
3302 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
3303 l
= isis_get_mt_items(m
, mtid
);
3306 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
3309 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
3310 enum isis_tlv_type type
, struct isis_item_list
*items
,
3311 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
3312 const struct pack_order_entry
*pe
,
3313 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3314 struct list
*new_fragment_arg
)
3316 size_t len_pos
, last_len
, len
;
3317 struct isis_item
*item
= NULL
;
3325 if (STREAM_WRITEABLE(s
) < 2)
3328 stream_putc(s
, type
);
3329 len_pos
= stream_get_endp(s
);
3330 stream_putc(s
, 0); /* Put 0 as length for now */
3332 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
3333 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
3334 if (STREAM_WRITEABLE(s
) < 2)
3336 stream_putw(s
, mtid
);
3339 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
3340 if (STREAM_WRITEABLE(s
) < 1)
3342 stream_putc(s
, 0); /* Virtual flag is set to 0 */
3346 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
3347 rv
= pack_item(context
, type
, item
, s
, &min_len
, fragment_tlvs
,
3352 len
= stream_get_endp(s
) - len_pos
- 1;
3354 /* Multiple auths don't go into one TLV, so always break */
3355 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
3360 /* Multiple prefix-sids don't go into one TLV, so always break */
3361 if (type
== ISIS_SUBTLV_PREFIX_SID
3362 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
3363 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
3369 if (!last_len
) /* strange, not a single item fit */
3371 /* drop last tlv, otherwise, its too long */
3372 stream_set_endp(s
, len_pos
+ 1 + last_len
);
3378 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
3383 stream_putc_at(s
, len_pos
, len
);
3392 if (STREAM_WRITEABLE(s
) < min_len
)
3394 *fragment_tlvs
= new_fragment(new_fragment_arg
);
3397 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
3399 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
3402 dest
->tail
= &(*dest
->tail
)->next
;
3406 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
3408 struct isis_item
*item
, *prev
= NULL
, *next
;
3411 if ((dest
== NULL
) || (del
== NULL
))
3415 * TODO: delete is tricky because "dest" is a singly linked list.
3416 * We need to switch a doubly linked list.
3418 for (item
= dest
->head
; item
; item
= next
) {
3419 if (item
->next
== del
) {
3426 prev
->next
= del
->next
;
3427 if (dest
->head
== del
)
3428 dest
->head
= del
->next
;
3429 if ((struct isis_item
*)dest
->tail
== del
) {
3432 dest
->tail
= &(*dest
->tail
)->next
;
3434 dest
->tail
= &dest
->head
;
3439 static struct isis_item
*last_item(struct isis_item_list
*list
)
3441 return container_of(list
->tail
, struct isis_item
, next
);
3444 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
3445 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
3446 struct sbuf
*log
, void *dest
, int indent
)
3448 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
3450 if (ops
&& ops
->unpack_item
)
3451 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
3453 assert(!"Unknown item tlv type!");
3454 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
3458 static int unpack_tlv_with_items(enum isis_tlv_context context
,
3459 uint8_t tlv_type
, uint8_t tlv_len
,
3460 struct stream
*s
, struct sbuf
*log
, void *dest
,
3468 tlv_start
= stream_get_getp(s
);
3471 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
3473 sbuf_push(log
, indent
,
3474 "TLV is too short to contain MTID\n");
3477 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
3479 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
3480 isis_mtid2str(mtid
));
3482 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
3483 mtid
= ISIS_MT_IPV4_UNICAST
;
3486 if (context
== ISIS_CONTEXT_LSP
3487 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
3488 if (tlv_len
- tlv_pos
< 1) {
3489 sbuf_push(log
, indent
,
3490 "TLV is too short for old style reach\n");
3493 stream_forward_getp(s
, 1);
3497 if (context
== ISIS_CONTEXT_LSP
3498 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
3499 struct isis_tlvs
*tlvs
= dest
;
3500 dest
= &tlvs
->oldstyle_ip_reach
;
3501 } else if (context
== ISIS_CONTEXT_LSP
3502 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
3503 struct isis_tlvs
*tlvs
= dest
;
3504 dest
= &tlvs
->oldstyle_ip_reach_ext
;
3507 if (context
== ISIS_CONTEXT_LSP
3508 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
3509 struct isis_tlvs
*tlvs
= dest
;
3510 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
3513 while (tlv_pos
< (size_t)tlv_len
) {
3514 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
3515 log
, dest
, indent
+ 2);
3519 tlv_pos
= stream_get_getp(s
) - tlv_start
;
3525 /* Functions to manipulate mt_item_lists */
3527 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
3528 const struct isis_item_list
*b
)
3530 if (a
->mtid
< b
->mtid
)
3532 if (a
->mtid
> b
->mtid
)
3537 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
3538 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
3540 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
3543 struct isis_item_list
*rv
;
3545 rv
= isis_lookup_mt_items(m
, mtid
);
3547 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
3550 RB_INSERT(isis_mt_item_list
, m
, rv
);
3556 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
3559 struct isis_item_list key
= {.mtid
= mtid
};
3561 return RB_FIND(isis_mt_item_list
, m
, &key
);
3564 static void free_mt_items(enum isis_tlv_context context
,
3565 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
3567 struct isis_item_list
*n
, *nnext
;
3569 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
3570 free_items(context
, type
, n
);
3571 RB_REMOVE(isis_mt_item_list
, m
, n
);
3572 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
3576 static void format_mt_items(enum isis_tlv_context context
,
3577 enum isis_tlv_type type
,
3578 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
3581 struct isis_item_list
*n
;
3583 RB_FOREACH (n
, isis_mt_item_list
, m
) {
3584 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
3588 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3589 struct isis_mt_item_list
*m
, struct stream
*s
,
3590 struct isis_tlvs
**fragment_tlvs
,
3591 const struct pack_order_entry
*pe
,
3592 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3593 struct list
*new_fragment_arg
)
3595 struct isis_item_list
*n
;
3597 RB_FOREACH (n
, isis_mt_item_list
, m
) {
3600 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
3601 pe
, new_fragment
, new_fragment_arg
);
3609 static void copy_mt_items(enum isis_tlv_context context
,
3610 enum isis_tlv_type type
,
3611 struct isis_mt_item_list
*src
,
3612 struct isis_mt_item_list
*dest
)
3614 struct isis_item_list
*n
;
3616 RB_INIT(isis_mt_item_list
, dest
);
3618 RB_FOREACH (n
, isis_mt_item_list
, src
) {
3619 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
3623 /* Functions related to tlvs in general */
3625 struct isis_tlvs
*isis_alloc_tlvs(void)
3627 struct isis_tlvs
*result
;
3629 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
3631 init_item_list(&result
->isis_auth
);
3632 init_item_list(&result
->area_addresses
);
3633 init_item_list(&result
->mt_router_info
);
3634 init_item_list(&result
->oldstyle_reach
);
3635 init_item_list(&result
->lan_neighbor
);
3636 init_item_list(&result
->lsp_entries
);
3637 init_item_list(&result
->extended_reach
);
3638 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
3639 init_item_list(&result
->oldstyle_ip_reach
);
3640 init_item_list(&result
->oldstyle_ip_reach_ext
);
3641 init_item_list(&result
->ipv4_address
);
3642 init_item_list(&result
->ipv6_address
);
3643 init_item_list(&result
->extended_ip_reach
);
3644 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
3645 init_item_list(&result
->ipv6_reach
);
3646 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
3651 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
3653 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3655 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
3658 rv
->purge_originator
=
3659 copy_tlv_purge_originator(tlvs
->purge_originator
);
3661 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3662 &tlvs
->area_addresses
, &rv
->area_addresses
);
3664 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3665 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
3667 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
3669 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3670 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
3672 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3673 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
3675 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
3678 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3679 &tlvs
->extended_reach
, &rv
->extended_reach
);
3681 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
3684 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3685 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
3687 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
3688 &rv
->protocols_supported
);
3690 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3691 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
3693 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
3696 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
3699 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
3701 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3702 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
3704 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3705 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
3707 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
3709 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
3712 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3713 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
3715 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
3717 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
3719 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
3724 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
3726 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
3728 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
3731 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, indent
);
3733 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3734 &tlvs
->area_addresses
, buf
, indent
);
3736 if (tlvs
->mt_router_info_empty
) {
3737 sbuf_push(buf
, indent
, "MT Router Info: None\n");
3739 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3740 &tlvs
->mt_router_info
, buf
, indent
);
3743 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3744 &tlvs
->oldstyle_reach
, buf
, indent
);
3746 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3747 &tlvs
->lan_neighbor
, buf
, indent
);
3749 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
3752 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
3753 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
3754 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
3756 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3757 &tlvs
->extended_reach
, buf
, indent
);
3759 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
3762 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3763 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
3765 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3766 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
3768 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
3769 &tlvs
->ipv4_address
, buf
, indent
);
3771 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
3772 &tlvs
->ipv6_address
, buf
, indent
);
3774 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3775 &tlvs
->extended_ip_reach
, buf
, indent
);
3777 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3778 &tlvs
->mt_ip_reach
, buf
, indent
);
3780 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
3783 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3784 &tlvs
->mt_ipv6_reach
, buf
, indent
);
3786 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
3788 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, indent
);
3791 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
3793 static struct sbuf buf
;
3795 if (!sbuf_buf(&buf
))
3796 sbuf_init(&buf
, NULL
, 0);
3799 format_tlvs(tlvs
, &buf
, 0);
3800 return sbuf_buf(&buf
);
3803 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
3808 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
3809 free_tlv_purge_originator(tlvs
->purge_originator
);
3810 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3811 &tlvs
->area_addresses
);
3812 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3813 &tlvs
->mt_router_info
);
3814 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3815 &tlvs
->oldstyle_reach
);
3816 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3817 &tlvs
->lan_neighbor
);
3818 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
3819 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3820 &tlvs
->extended_reach
);
3821 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
3822 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3823 &tlvs
->oldstyle_ip_reach
);
3824 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
3825 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3826 &tlvs
->oldstyle_ip_reach_ext
);
3827 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
3828 &tlvs
->ipv4_address
);
3829 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
3830 &tlvs
->ipv6_address
);
3831 free_tlv_te_router_id(tlvs
->te_router_id
);
3832 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3833 &tlvs
->extended_ip_reach
);
3834 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3835 &tlvs
->mt_ip_reach
);
3836 free_tlv_dynamic_hostname(tlvs
->hostname
);
3837 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
3838 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3839 &tlvs
->mt_ipv6_reach
);
3840 free_tlv_threeway_adj(tlvs
->threeway_adj
);
3841 free_tlv_router_cap(tlvs
->router_cap
);
3842 free_tlv_spine_leaf(tlvs
->spine_leaf
);
3844 XFREE(MTYPE_ISIS_TLV
, tlvs
);
3847 static void add_padding(struct stream
*s
)
3849 while (STREAM_WRITEABLE(s
)) {
3850 if (STREAM_WRITEABLE(s
) == 1)
3852 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
3854 if (padding_len
> 255) {
3855 if (padding_len
== 256)
3861 stream_putc(s
, ISIS_TLV_PADDING
);
3862 stream_putc(s
, padding_len
);
3863 stream_put(s
, NULL
, padding_len
);
3867 #define LSP_REM_LIFETIME_OFF 10
3868 #define LSP_CHECKSUM_OFF 24
3869 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
3870 uint16_t *rem_lifetime
)
3872 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
3873 sizeof(*rem_lifetime
));
3874 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
3875 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
3876 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
3879 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
3880 uint16_t rem_lifetime
)
3882 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
3883 sizeof(rem_lifetime
));
3884 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
3887 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
3891 uint16_t checksum
, rem_lifetime
;
3894 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
3896 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
3897 #ifdef CRYPTO_OPENSSL
3898 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
3899 auth
->plength
, STREAM_DATA(s
),
3900 stream_get_endp(s
), NULL
, NULL
);
3902 memcpy(digest
, result
, 16);
3903 #elif CRYPTO_INTERNAL
3904 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
3905 auth
->plength
, digest
);
3907 memcpy(auth
->value
, digest
, 16);
3908 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
3911 restore_auth_md5(s
, checksum
, rem_lifetime
);
3914 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
3916 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
3918 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
3919 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
3920 update_auth_hmac_md5(auth
, s
, is_lsp
);
3924 static int handle_pack_entry(const struct pack_order_entry
*pe
,
3925 struct isis_tlvs
*tlvs
, struct stream
*stream
,
3926 struct isis_tlvs
**fragment_tlvs
,
3927 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3928 struct list
*new_fragment_arg
)
3932 if (pe
->how_to_pack
== ISIS_ITEMS
) {
3933 struct isis_item_list
*l
;
3934 l
= (struct isis_item_list
*)(((char *)tlvs
)
3935 + pe
->what_to_pack
);
3936 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
3937 pe
, new_fragment
, new_fragment_arg
);
3939 struct isis_mt_item_list
*l
;
3940 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
3941 + pe
->what_to_pack
);
3942 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
3943 fragment_tlvs
, pe
, new_fragment
,
3950 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
3951 struct isis_tlvs
*fragment_tlvs
,
3952 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3953 struct list
*new_fragment_arg
)
3957 /* When fragmenting, don't add auth as it's already accounted for in the
3958 * size we are given. */
3959 if (!fragment_tlvs
) {
3960 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
3961 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
3967 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
3970 if (fragment_tlvs
) {
3971 fragment_tlvs
->purge_originator
=
3972 copy_tlv_purge_originator(tlvs
->purge_originator
);
3975 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
3978 if (fragment_tlvs
) {
3979 copy_tlv_protocols_supported(
3980 &tlvs
->protocols_supported
,
3981 &fragment_tlvs
->protocols_supported
);
3984 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3985 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
3988 if (fragment_tlvs
) {
3989 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3990 &tlvs
->area_addresses
,
3991 &fragment_tlvs
->area_addresses
);
3995 if (tlvs
->mt_router_info_empty
) {
3996 if (STREAM_WRITEABLE(stream
) < 2)
3998 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
3999 stream_putc(stream
, 0);
4001 fragment_tlvs
->mt_router_info_empty
= true;
4003 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4004 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
4008 if (fragment_tlvs
) {
4009 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
4010 &tlvs
->mt_router_info
,
4011 &fragment_tlvs
->mt_router_info
);
4015 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
4019 fragment_tlvs
->hostname
=
4020 copy_tlv_dynamic_hostname(tlvs
->hostname
);
4022 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
4025 if (fragment_tlvs
) {
4026 fragment_tlvs
->router_cap
=
4027 copy_tlv_router_cap(tlvs
->router_cap
);
4030 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
4033 if (fragment_tlvs
) {
4034 fragment_tlvs
->te_router_id
=
4035 copy_tlv_te_router_id(tlvs
->te_router_id
);
4038 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
4041 if (fragment_tlvs
) {
4042 fragment_tlvs
->threeway_adj
=
4043 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
4046 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
4049 if (fragment_tlvs
) {
4050 fragment_tlvs
->spine_leaf
=
4051 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
4054 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
4056 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
4057 fragment_tlvs
? &fragment_tlvs
: NULL
,
4058 new_fragment
, new_fragment_arg
);
4067 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
4068 size_t len_pointer
, bool pad
, bool is_lsp
)
4072 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
4077 add_padding(stream
);
4079 if (len_pointer
!= (size_t)-1) {
4080 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
4083 update_auth(tlvs
, stream
, is_lsp
);
4088 static struct isis_tlvs
*new_fragment(struct list
*l
)
4090 struct isis_tlvs
*rv
= isis_alloc_tlvs();
4092 listnode_add(l
, rv
);
4096 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
4098 struct stream
*dummy_stream
= stream_new(size
);
4099 struct list
*rv
= list_new();
4100 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
4102 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
4103 struct listnode
*node
;
4104 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
4105 isis_free_tlvs(fragment_tlvs
);
4109 stream_free(dummy_stream
);
4113 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
4114 uint8_t tlv_len
, struct stream
*s
,
4115 struct sbuf
*log
, int indent
)
4117 stream_forward_getp(s
, tlv_len
);
4118 sbuf_push(log
, indent
,
4119 "Skipping unknown TLV %hhu (%hhu bytes)\n",
4124 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
4125 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4126 int indent
, bool *unpacked_known_tlvs
)
4128 uint8_t tlv_type
, tlv_len
;
4129 const struct tlv_ops
*ops
;
4131 sbuf_push(log
, indent
, "Unpacking TLV...\n");
4133 if (avail_len
< 2) {
4136 "Available data %zu too short to contain a TLV header.\n",
4141 tlv_type
= stream_getc(stream
);
4142 tlv_len
= stream_getc(stream
);
4144 sbuf_push(log
, indent
+ 2,
4145 "Found TLV of type %hhu and len %hhu.\n",
4148 if (avail_len
< ((size_t)tlv_len
) + 2) {
4149 sbuf_push(log
, indent
+ 2,
4150 "Available data %zu too short for claimed TLV len %hhu.\n",
4151 avail_len
- 2, tlv_len
);
4155 ops
= tlv_table
[context
][tlv_type
];
4156 if (ops
&& ops
->unpack
) {
4157 if (unpacked_known_tlvs
)
4158 *unpacked_known_tlvs
= true;
4159 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
4163 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
4167 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
4168 struct stream
*stream
, struct sbuf
*log
, void *dest
,
4169 int indent
, bool *unpacked_known_tlvs
)
4172 size_t tlv_start
, tlv_pos
;
4174 tlv_start
= stream_get_getp(stream
);
4177 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
4178 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
4180 while (tlv_pos
< avail_len
) {
4181 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
4182 indent
+ 2, unpacked_known_tlvs
);
4186 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
4192 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
4193 struct isis_tlvs
**dest
, const char **log
)
4195 static struct sbuf logbuf
;
4198 struct isis_tlvs
*result
;
4200 if (!sbuf_buf(&logbuf
))
4201 sbuf_init(&logbuf
, NULL
, 0);
4203 sbuf_reset(&logbuf
);
4204 if (avail_len
> STREAM_READABLE(stream
)) {
4205 sbuf_push(&logbuf
, indent
,
4206 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
4207 avail_len
, STREAM_READABLE(stream
));
4211 result
= isis_alloc_tlvs();
4212 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
4215 *log
= sbuf_buf(&logbuf
);
4221 #define TLV_OPS(_name_, _desc_) \
4222 static const struct tlv_ops tlv_##_name_##_ops = { \
4223 .name = _desc_, .unpack = unpack_tlv_##_name_, \
4226 #define ITEM_TLV_OPS(_name_, _desc_) \
4227 static const struct tlv_ops tlv_##_name_##_ops = { \
4229 .unpack = unpack_tlv_with_items, \
4231 .pack_item = pack_item_##_name_, \
4232 .free_item = free_item_##_name_, \
4233 .unpack_item = unpack_item_##_name_, \
4234 .format_item = format_item_##_name_, \
4235 .copy_item = copy_item_##_name_}
4237 #define SUBTLV_OPS(_name_, _desc_) \
4238 static const struct tlv_ops subtlv_##_name_##_ops = { \
4239 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
4242 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
4243 ITEM_TLV_OPS(_name_, _desc_)
4245 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
4246 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
4247 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
4248 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
4249 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
4250 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
4251 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
4252 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
4253 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
4254 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
4255 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
4256 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
4257 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
4258 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
4259 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
4260 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
4261 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
4262 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
4263 TLV_OPS(router_cap
, "TLV 242 Router Capability");
4265 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
4266 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
4268 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
4269 [ISIS_CONTEXT_LSP
] = {
4270 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
4271 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
4272 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
4273 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
4274 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
4275 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
4276 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
4277 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
4278 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
4279 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
4280 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
4281 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
4282 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
4283 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
4284 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
4285 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
4286 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
4287 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
4288 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
4289 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
4290 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
4291 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
4292 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
4294 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
4295 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
4296 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
4298 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
4299 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
4300 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
4304 /* Accessor functions */
4306 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
4308 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4309 init_item_list(&tlvs
->isis_auth
);
4311 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
4314 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
4316 auth
->type
= passwd
->type
;
4318 auth
->plength
= passwd
->len
;
4319 memcpy(auth
->passwd
, passwd
->passwd
,
4320 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
4322 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
4323 auth
->length
= passwd
->len
;
4324 memcpy(auth
->value
, passwd
->passwd
,
4325 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
4328 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
4331 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
4332 struct list
*addresses
)
4334 struct listnode
*node
;
4335 struct area_addr
*area_addr
;
4337 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
4338 struct isis_area_address
*a
=
4339 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4341 a
->len
= area_addr
->addr_len
;
4342 memcpy(a
->addr
, area_addr
->area_addr
, 20);
4343 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
4347 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
4349 struct listnode
*node
;
4352 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
4353 struct isis_lan_neighbor
*n
=
4354 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
4356 memcpy(n
->mac
, snpa
, 6);
4357 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
4361 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
4362 struct nlpids
*nlpids
)
4364 tlvs
->protocols_supported
.count
= nlpids
->count
;
4365 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
4366 if (nlpids
->count
) {
4367 tlvs
->protocols_supported
.protocols
=
4368 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
4369 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
4372 tlvs
->protocols_supported
.protocols
= NULL
;
4376 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4377 bool overload
, bool attached
)
4379 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
4381 i
->overload
= overload
;
4382 i
->attached
= attached
;
4384 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
4387 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
4389 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4391 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
4395 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
4396 struct list
*addresses
)
4398 struct listnode
*node
;
4399 struct prefix_ipv4
*ip_addr
;
4400 unsigned int addr_count
= 0;
4402 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
4403 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
4405 if (addr_count
>= 63)
4410 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
4411 struct list
*addresses
)
4413 struct listnode
*node
;
4414 struct prefix_ipv6
*ip_addr
;
4415 unsigned int addr_count
= 0;
4417 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
4418 if (addr_count
>= 15)
4421 struct isis_ipv6_address
*a
=
4422 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4424 a
->addr
= ip_addr
->prefix
;
4425 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
4430 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
4431 struct stream
*stream
,
4432 struct isis_auth
*auth
, bool is_lsp
);
4434 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
4435 struct stream
*stream
,
4436 struct isis_auth
*auth
, bool is_lsp
)
4438 return (auth
->length
== passwd
->len
4439 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
4442 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
4443 struct stream
*stream
,
4444 struct isis_auth
*auth
, bool is_lsp
)
4448 uint16_t rem_lifetime
;
4451 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
4453 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
4454 #ifdef CRYPTO_OPENSSL
4455 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
4456 passwd
->len
, STREAM_DATA(stream
),
4457 stream_get_endp(stream
), NULL
, NULL
);
4459 memcpy(digest
, result
, 16);
4460 #elif CRYPTO_INTERNAL
4461 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
4462 passwd
->len
, digest
);
4464 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
4466 bool rv
= !memcmp(digest
, auth
->value
, 16);
4469 restore_auth_md5(stream
, checksum
, rem_lifetime
);
4474 static const auth_validator_func auth_validators
[] = {
4475 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
4476 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
4479 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
4480 struct stream
*stream
, bool is_lsp
)
4482 /* If no auth is set, always pass authentication */
4484 return ISIS_AUTH_OK
;
4486 /* If we don't known how to validate the auth, return invalid */
4487 if (passwd
->type
>= array_size(auth_validators
)
4488 || !auth_validators
[passwd
->type
])
4489 return ISIS_AUTH_NO_VALIDATOR
;
4491 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4492 struct isis_auth
*auth
;
4493 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
4494 if (auth
->type
== passwd
->type
)
4498 /* If matching auth TLV could not be found, return invalid */
4500 return ISIS_AUTH_TYPE_FAILURE
;
4503 /* Perform validation and return result */
4504 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
4505 return ISIS_AUTH_OK
;
4507 return ISIS_AUTH_FAILURE
;
4510 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
4511 struct list
*addresses
)
4513 struct isis_area_address
*addr_head
;
4515 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
4516 for (struct isis_area_address
*addr
= addr_head
; addr
;
4517 addr
= addr
->next
) {
4518 struct listnode
*node
;
4519 struct area_addr
*a
;
4521 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
4522 if (a
->addr_len
== addr
->len
4523 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
4531 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
4532 struct isis_adjacency
*adj
,
4535 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
4536 uint32_t oc
= adj
->area_address_count
;
4539 adj
->area_address_count
= tlvs
->area_addresses
.count
;
4540 adj
->area_addresses
= XREALLOC(
4541 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
4542 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
4544 for (; oc
< adj
->area_address_count
; oc
++) {
4545 adj
->area_addresses
[oc
].addr_len
= 0;
4546 memset(&adj
->area_addresses
[oc
].area_addr
, 0,
4547 sizeof(adj
->area_addresses
[oc
].area_addr
));
4551 struct isis_area_address
*addr
= NULL
;
4552 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
4554 addr
= (struct isis_area_address
*)
4555 tlvs
->area_addresses
.head
;
4559 if (adj
->area_addresses
[i
].addr_len
== addr
->len
4560 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
4566 adj
->area_addresses
[i
].addr_len
= addr
->len
;
4567 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
4571 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
4572 struct isis_adjacency
*adj
,
4575 bool ipv4_supported
= false, ipv6_supported
= false;
4577 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
4578 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
4579 ipv4_supported
= true;
4580 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
4581 ipv6_supported
= true;
4584 struct nlpids reduced
= {};
4586 if (ipv4_supported
&& ipv6_supported
) {
4588 reduced
.nlpids
[0] = NLPID_IP
;
4589 reduced
.nlpids
[1] = NLPID_IPV6
;
4590 } else if (ipv4_supported
) {
4592 reduced
.nlpids
[0] = NLPID_IP
;
4593 } else if (ipv6_supported
) {
4595 reduced
.nlpids
[0] = NLPID_IPV6
;
4600 if (adj
->nlpids
.count
== reduced
.count
4601 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
4605 adj
->nlpids
.count
= reduced
.count
;
4606 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
4609 DEFINE_HOOK(isis_adj_ip_enabled_hook
, (struct isis_adjacency
*adj
, int family
),
4611 DEFINE_HOOK(isis_adj_ip_disabled_hook
,
4612 (struct isis_adjacency
*adj
, int family
), (adj
, family
));
4614 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
4615 struct isis_adjacency
*adj
,
4618 bool ipv4_enabled
= false;
4620 if (adj
->ipv4_address_count
== 0 && tlvs
->ipv4_address
.count
> 0)
4621 ipv4_enabled
= true;
4622 else if (adj
->ipv4_address_count
> 0 && tlvs
->ipv4_address
.count
== 0)
4623 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET
);
4625 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
4626 uint32_t oc
= adj
->ipv4_address_count
;
4629 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
4630 adj
->ipv4_addresses
= XREALLOC(
4631 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
4632 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
4634 for (; oc
< adj
->ipv4_address_count
; oc
++) {
4635 memset(&adj
->ipv4_addresses
[oc
], 0,
4636 sizeof(adj
->ipv4_addresses
[oc
]));
4640 struct isis_ipv4_address
*addr
= NULL
;
4641 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
4643 addr
= (struct isis_ipv4_address
*)
4644 tlvs
->ipv4_address
.head
;
4648 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
4649 sizeof(addr
->addr
)))
4653 adj
->ipv4_addresses
[i
] = addr
->addr
;
4657 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET
);
4660 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
4661 struct isis_adjacency
*adj
,
4664 bool ipv6_enabled
= false;
4666 if (adj
->ipv6_address_count
== 0 && tlvs
->ipv6_address
.count
> 0)
4667 ipv6_enabled
= true;
4668 else if (adj
->ipv6_address_count
> 0 && tlvs
->ipv6_address
.count
== 0)
4669 hook_call(isis_adj_ip_disabled_hook
, adj
, AF_INET6
);
4671 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
4672 uint32_t oc
= adj
->ipv6_address_count
;
4675 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
4676 adj
->ipv6_addresses
= XREALLOC(
4677 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
4678 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
4680 for (; oc
< adj
->ipv6_address_count
; oc
++) {
4681 memset(&adj
->ipv6_addresses
[oc
], 0,
4682 sizeof(adj
->ipv6_addresses
[oc
]));
4686 struct isis_ipv6_address
*addr
= NULL
;
4687 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
4689 addr
= (struct isis_ipv6_address
*)
4690 tlvs
->ipv6_address
.head
;
4694 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
4695 sizeof(addr
->addr
)))
4699 adj
->ipv6_addresses
[i
] = addr
->addr
;
4703 hook_call(isis_adj_ip_enabled_hook
, adj
, AF_INET6
);
4706 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
4711 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
4712 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
4713 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
4714 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
4717 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
4719 struct isis_lan_neighbor
*ne_head
;
4721 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
4722 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
4723 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
4730 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
4732 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
4734 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
4735 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
4736 entry
->checksum
= lsp
->hdr
.checksum
;
4737 entry
->seqno
= lsp
->hdr
.seqno
;
4740 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
4743 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
4744 uint8_t *stop_id
, uint16_t num_lsps
,
4745 struct lspdb_head
*head
,
4746 struct isis_lsp
**last_lsp
)
4748 struct isis_lsp searchfor
;
4749 struct isis_lsp
*first
, *lsp
;
4751 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
4752 first
= lspdb_find_gteq(head
, &searchfor
);
4756 frr_each_from (lspdb
, head
, lsp
, first
) {
4757 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
4758 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
4761 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
4766 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
4767 const char *hostname
)
4769 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
4771 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
4774 /* Set Router Capability TLV parameters */
4775 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
4776 const struct isis_router_cap
*cap
)
4778 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
4782 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
4783 *tlvs
->router_cap
= *cap
;
4786 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
4787 const struct in_addr
*id
)
4789 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
4792 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
4793 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
4796 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
4797 struct prefix_ipv4
*dest
, uint8_t metric
)
4799 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4802 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4803 apply_mask_ipv4(&r
->prefix
);
4804 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
4807 /* Add IS-IS SR Adjacency-SID subTLVs */
4808 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
4809 struct isis_adj_sid
*adj
)
4811 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
4812 SET_SUBTLV(exts
, EXT_ADJ_SID
);
4815 /* Delete IS-IS SR Adjacency-SID subTLVs */
4816 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
4817 struct isis_adj_sid
*adj
)
4819 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
4820 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
4821 if (exts
->adj_sid
.count
== 0)
4822 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
4825 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
4826 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
4827 struct isis_lan_adj_sid
*lan
)
4829 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
4830 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
4833 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
4834 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
4835 struct isis_lan_adj_sid
*lan
)
4837 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
4838 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
4839 if (exts
->lan_sid
.count
== 0)
4840 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
4843 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
4844 struct prefix_ipv4
*dest
, uint32_t metric
,
4845 bool external
, struct sr_prefix_cfg
*pcfg
)
4847 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4850 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4851 apply_mask_ipv4(&r
->prefix
);
4853 struct isis_prefix_sid
*psid
=
4854 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
4856 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
4857 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
4858 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
4860 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
4863 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4864 struct prefix_ipv6
*dest
, uint32_t metric
,
4865 bool external
, struct sr_prefix_cfg
*pcfg
)
4867 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4870 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4871 apply_mask_ipv6(&r
->prefix
);
4873 struct isis_prefix_sid
*psid
=
4874 XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*psid
));
4876 isis_sr_prefix_cfg2subtlv(pcfg
, external
, psid
);
4877 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
4878 append_item(&r
->subtlvs
->prefix_sids
, (struct isis_item
*)psid
);
4881 struct isis_item_list
*l
;
4882 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
4884 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
4885 append_item(l
, (struct isis_item
*)r
);
4888 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4889 struct prefix_ipv6
*dest
,
4890 struct prefix_ipv6
*src
,
4893 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
, false, NULL
);
4894 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
4897 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
4898 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
4899 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
4900 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
4903 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
4906 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4909 memcpy(r
->id
, id
, sizeof(r
->id
));
4910 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
4913 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4914 uint8_t *id
, uint32_t metric
,
4915 struct isis_ext_subtlvs
*exts
)
4917 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4919 memcpy(r
->id
, id
, sizeof(r
->id
));
4922 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
4924 struct isis_item_list
*l
;
4925 if (mtid
== ISIS_MT_IPV4_UNICAST
)
4926 l
= &tlvs
->extended_reach
;
4928 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
4929 append_item(l
, (struct isis_item
*)r
);
4932 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
4933 enum isis_threeway_state state
,
4934 uint32_t local_circuit_id
,
4935 const uint8_t *neighbor_id
,
4936 uint32_t neighbor_circuit_id
)
4938 assert(!tlvs
->threeway_adj
);
4940 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
4941 tlvs
->threeway_adj
->state
= state
;
4942 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
4945 tlvs
->threeway_adj
->neighbor_set
= true;
4946 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
4947 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
4951 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
4952 bool has_tier
, bool is_leaf
, bool is_spine
,
4955 assert(!tlvs
->spine_leaf
);
4957 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
4960 tlvs
->spine_leaf
->tier
= tier
;
4963 tlvs
->spine_leaf
->has_tier
= has_tier
;
4964 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
4965 tlvs
->spine_leaf
->is_spine
= is_spine
;
4966 tlvs
->spine_leaf
->is_backup
= is_backup
;
4969 struct isis_mt_router_info
*
4970 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
4972 if (!tlvs
|| tlvs
->mt_router_info_empty
)
4975 struct isis_mt_router_info
*rv
;
4976 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
4978 if (rv
->mtid
== mtid
)
4985 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
4986 const uint8_t *generator
,
4987 const uint8_t *sender
)
4989 assert(!tlvs
->purge_originator
);
4991 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
4992 sizeof(*tlvs
->purge_originator
));
4993 memcpy(tlvs
->purge_originator
->generator
, generator
,
4994 sizeof(tlvs
->purge_originator
->generator
));
4996 tlvs
->purge_originator
->sender_set
= true;
4997 memcpy(tlvs
->purge_originator
->sender
, sender
,
4998 sizeof(tlvs
->purge_originator
->sender
));