2 * IS-IS TLV Serializer/Deserializer
4 * Copyright (C) 2015,2017 Christian Franke
6 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
8 * This file is part of FRR.
10 * FRR is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FRR; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #ifdef CRYPTO_INTERNAL
35 #include "isisd/isisd.h"
36 #include "isisd/isis_memory.h"
37 #include "isisd/isis_tlvs.h"
38 #include "isisd/isis_common.h"
39 #include "isisd/isis_mt.h"
40 #include "isisd/isis_misc.h"
41 #include "isisd/isis_adjacency.h"
42 #include "isisd/isis_circuit.h"
43 #include "isisd/isis_pdu.h"
44 #include "isisd/isis_lsp.h"
45 #include "isisd/isis_te.h"
47 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs")
48 DEFINE_MTYPE_STATIC(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
);
55 typedef void (*free_item_func
)(struct isis_item
*i
);
56 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
57 struct sbuf
*log
, void *dest
, int indent
);
58 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
59 struct sbuf
*buf
, int indent
);
60 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
64 unpack_tlv_func unpack
;
66 pack_item_func pack_item
;
67 free_item_func free_item
;
68 unpack_item_func unpack_item
;
69 format_item_func format_item
;
70 copy_item_func copy_item
;
78 struct pack_order_entry
{
79 enum isis_tlv_context context
;
80 enum isis_tlv_type type
;
81 enum how_to_pack how_to_pack
;
84 #define PACK_ENTRY(t, h, w) \
86 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
88 .what_to_pack = offsetof(struct isis_tlvs, w), \
91 static const struct pack_order_entry pack_order
[] = {
92 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
93 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
94 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
95 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
96 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
97 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
98 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
99 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
100 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
101 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
102 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
103 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
104 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)
107 /* This is a forward definition. The table is actually initialized
108 * in at the bottom. */
109 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
111 /* End of _ops forward definition. */
114 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
115 static void init_item_list(struct isis_item_list
*items
);
117 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
118 struct isis_ext_subtlvs
*isis_alloc_ext_subtlvs(void)
120 struct isis_ext_subtlvs
*ext
;
122 ext
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_ext_subtlvs
));
123 init_item_list(&ext
->adj_sid
);
124 init_item_list(&ext
->lan_sid
);
130 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
131 * A negative value could be used to skip copy of Adjacency SID.
133 static struct isis_ext_subtlvs
*
134 copy_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
, int16_t mtid
)
136 struct isis_ext_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
137 struct isis_adj_sid
*adj
;
138 struct isis_lan_adj_sid
*lan
;
140 memcpy(rv
, exts
, sizeof(struct isis_ext_subtlvs
));
141 init_item_list(&rv
->adj_sid
);
142 init_item_list(&rv
->lan_sid
);
144 UNSET_SUBTLV(rv
, EXT_ADJ_SID
);
145 UNSET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
147 /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
148 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
!= NULL
;
151 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
152 && (adj
->family
!= AF_INET
))
153 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
154 && (adj
->family
!= AF_INET6
))))
157 struct isis_adj_sid
*new;
159 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_adj_sid
));
160 new->family
= adj
->family
;
161 new->flags
= adj
->flags
;
162 new->weight
= adj
->weight
;
164 append_item(&rv
->adj_sid
, (struct isis_item
*)new);
165 SET_SUBTLV(rv
, EXT_ADJ_SID
);
168 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
!= NULL
;
171 && (((mtid
== ISIS_MT_IPV4_UNICAST
)
172 && (lan
->family
!= AF_INET
))
173 || ((mtid
== ISIS_MT_IPV6_UNICAST
)
174 && (lan
->family
!= AF_INET6
))))
177 struct isis_lan_adj_sid
*new;
179 new = XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(struct isis_lan_adj_sid
));
180 new->family
= lan
->family
;
181 new->flags
= lan
->flags
;
182 new->weight
= lan
->weight
;
183 memcpy(new->neighbor_id
, lan
->neighbor_id
, 6);
185 append_item(&rv
->lan_sid
, (struct isis_item
*)new);
186 SET_SUBTLV(rv
, EXT_LAN_ADJ_SID
);
192 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
193 static void format_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
194 struct sbuf
*buf
, int indent
,
198 char ibuf
[PREFIX2STR_BUFFER
];
200 /* Standard metrics */
201 if (IS_SUBTLV(exts
, EXT_ADM_GRP
))
202 sbuf_push(buf
, indent
, "Administrative Group: 0x%" PRIx32
"\n",
204 if (IS_SUBTLV(exts
, EXT_LLRI
)) {
205 sbuf_push(buf
, indent
, "Link Local ID: %" PRIu32
"\n",
207 sbuf_push(buf
, indent
, "Link Remote ID: %" PRIu32
"\n",
210 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR
))
211 sbuf_push(buf
, indent
, "Local Interface IP Address(es): %s\n",
212 inet_ntoa(exts
->local_addr
));
213 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR
))
214 sbuf_push(buf
, indent
, "Remote Interface IP Address(es): %s\n",
215 inet_ntoa(exts
->neigh_addr
));
216 if (IS_SUBTLV(exts
, EXT_LOCAL_ADDR6
))
217 sbuf_push(buf
, indent
, "Local Interface IPv6 Address(es): %s\n",
218 inet_ntop(AF_INET6
, &exts
->local_addr6
, ibuf
,
220 if (IS_SUBTLV(exts
, EXT_NEIGH_ADDR6
))
221 sbuf_push(buf
, indent
, "Remote Interface IPv6 Address(es): %s\n",
222 inet_ntop(AF_INET6
, &exts
->local_addr6
, ibuf
,
224 if (IS_SUBTLV(exts
, EXT_MAX_BW
))
225 sbuf_push(buf
, indent
, "Maximum Bandwidth: %g (Bytes/sec)\n",
227 if (IS_SUBTLV(exts
, EXT_MAX_RSV_BW
))
228 sbuf_push(buf
, indent
,
229 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
231 if (IS_SUBTLV(exts
, EXT_UNRSV_BW
)) {
232 sbuf_push(buf
, indent
, "Unreserved Bandwidth:\n");
233 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
234 sbuf_push(buf
, indent
+ 2,
235 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
236 j
, exts
->unrsv_bw
[j
],
237 j
+ 1, exts
->unrsv_bw
[j
+ 1]);
240 if (IS_SUBTLV(exts
, EXT_TE_METRIC
))
241 sbuf_push(buf
, indent
, "Traffic Engineering Metric: %u\n",
243 if (IS_SUBTLV(exts
, EXT_RMT_AS
))
244 sbuf_push(buf
, indent
,
245 "Inter-AS TE Remote AS number: %" PRIu32
"\n",
247 if (IS_SUBTLV(exts
, EXT_RMT_IP
))
248 sbuf_push(buf
, indent
,
249 "Inter-AS TE Remote ASBR IP address: %s\n",
250 inet_ntoa(exts
->remote_ip
));
251 /* Extended metrics */
252 if (IS_SUBTLV(exts
, EXT_DELAY
))
253 sbuf_push(buf
, indent
,
254 "%s Average Link Delay: %" PRIu32
" (micro-sec)\n",
255 IS_ANORMAL(exts
->delay
) ? "Anomalous" : "Normal",
257 if (IS_SUBTLV(exts
, EXT_MM_DELAY
)) {
258 sbuf_push(buf
, indent
, "%s Min/Max Link Delay: %" PRIu32
" / %"
259 PRIu32
" (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: %" PRIu32
" (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 */
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: %" PRIu32
", Weight: %" PRIu8
300 ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
301 adj
->sid
, adj
->weight
,
302 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? '1'
304 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? '1'
306 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
? '1'
308 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
? '1'
310 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
? '1'
312 adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
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: %" PRIu32
330 ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
331 " Neighbor-ID: %s\n",
332 lan
->sid
, lan
->weight
,
333 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
336 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
339 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
342 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_LFLG
345 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_SFLG
348 lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_PFLG
351 isis_format_id(lan
->neighbor_id
, 6));
356 static void free_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
)
358 struct isis_item
*item
, *next_item
;
360 /* First, free Adj SID and LAN Adj SID list if needed */
361 for (item
= exts
->adj_sid
.head
; item
; item
= next_item
) {
362 next_item
= item
->next
;
363 XFREE(MTYPE_ISIS_SUBTLV
, item
);
365 for (item
= exts
->lan_sid
.head
; item
; item
= next_item
) {
366 next_item
= item
->next
;
367 XFREE(MTYPE_ISIS_SUBTLV
, item
);
369 XFREE(MTYPE_ISIS_SUBTLV
, exts
);
372 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs
*exts
,
377 if (STREAM_WRITEABLE(s
) < 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 if (IS_SUBTLV(exts
, EXT_ADJ_SID
)) {
479 struct isis_adj_sid
*adj
;
481 for (adj
= (struct isis_adj_sid
*)exts
->adj_sid
.head
; adj
;
483 stream_putc(s
, ISIS_SUBTLV_ADJ_SID
);
484 size
= ISIS_SUBTLV_ADJ_SID_SIZE
;
485 if (!(adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
487 stream_putc(s
, size
);
488 stream_putc(s
, adj
->flags
);
489 stream_putc(s
, adj
->weight
);
490 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
491 stream_put3(s
, adj
->sid
);
493 stream_putl(s
, adj
->sid
);
497 if (IS_SUBTLV(exts
, EXT_LAN_ADJ_SID
)) {
498 struct isis_lan_adj_sid
*lan
;
500 for (lan
= (struct isis_lan_adj_sid
*)exts
->lan_sid
.head
; lan
;
502 stream_putc(s
, ISIS_SUBTLV_LAN_ADJ_SID
);
503 size
= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
;
504 if (!(lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
))
506 stream_putc(s
, size
);
507 stream_putc(s
, lan
->flags
);
508 stream_putc(s
, lan
->weight
);
509 stream_put(s
, lan
->neighbor_id
, 6);
510 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
)
511 stream_put3(s
, lan
->sid
);
513 stream_putl(s
, lan
->sid
);
520 static int unpack_item_ext_subtlvs(uint16_t mtid
, uint8_t len
, struct stream
*s
,
521 struct sbuf
*log
, void *dest
, int indent
)
527 struct isis_extended_reach
*rv
= dest
;
528 struct isis_ext_subtlvs
*exts
= isis_alloc_ext_subtlvs();
533 * Parse subTLVs until reach subTLV length
534 * Check that it remains at least 2 bytes: subTLV Type & Length
536 while (len
> sum
+ 2) {
537 /* Read SubTLV Type and Length */
538 subtlv_type
= stream_getc(s
);
539 subtlv_len
= stream_getc(s
);
540 if (subtlv_len
> len
- sum
) {
541 sbuf_push(log
, indent
, "TLV %" PRIu8
": Available data %" PRIu8
" is less than TLV size %u !\n",
542 subtlv_type
, len
- sum
, subtlv_len
);
546 switch (subtlv_type
) {
547 /* Standard Metric as defined in RFC5305 */
548 case ISIS_SUBTLV_ADMIN_GRP
:
549 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
550 sbuf_push(log
, indent
,
551 "TLV size does not match expected size for Administrative Group!\n");
553 exts
->adm_group
= stream_getl(s
);
554 SET_SUBTLV(exts
, EXT_ADM_GRP
);
557 case ISIS_SUBTLV_LLRI
:
558 if (subtlv_len
!= ISIS_SUBTLV_LLRI_SIZE
) {
559 sbuf_push(log
, indent
,
560 "TLV size does not match expected size for Link ID!\n");
562 exts
->local_llri
= stream_getl(s
);
563 exts
->remote_llri
= stream_getl(s
);
564 SET_SUBTLV(exts
, EXT_LLRI
);
567 case ISIS_SUBTLV_LOCAL_IPADDR
:
568 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
569 sbuf_push(log
, indent
,
570 "TLV size does not match expected size for Local IP address!\n");
572 stream_get(&exts
->local_addr
.s_addr
, s
, 4);
573 SET_SUBTLV(exts
, EXT_LOCAL_ADDR
);
576 case ISIS_SUBTLV_RMT_IPADDR
:
577 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
578 sbuf_push(log
, indent
,
579 "TLV size does not match expected size for Remote IP address!\n");
581 stream_get(&exts
->neigh_addr
.s_addr
, s
, 4);
582 SET_SUBTLV(exts
, EXT_NEIGH_ADDR
);
585 case ISIS_SUBTLV_LOCAL_IPADDR6
:
586 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
587 sbuf_push(log
, indent
,
588 "TLV size does not match expected size for Local IPv6 address!\n");
590 stream_get(&exts
->local_addr6
, s
, 16);
591 SET_SUBTLV(exts
, EXT_LOCAL_ADDR6
);
594 case ISIS_SUBTLV_RMT_IPADDR6
:
595 if (subtlv_len
!= ISIS_SUBTLV_IPV6_ADDR_SIZE
) {
596 sbuf_push(log
, indent
,
597 "TLV size does not match expected size for Remote IPv6 address!\n");
599 stream_get(&exts
->neigh_addr6
, s
, 16);
600 SET_SUBTLV(exts
, EXT_NEIGH_ADDR6
);
603 case ISIS_SUBTLV_MAX_BW
:
604 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
605 sbuf_push(log
, indent
,
606 "TLV size does not match expected size for Maximum Bandwidth!\n");
608 exts
->max_bw
= stream_getf(s
);
609 SET_SUBTLV(exts
, EXT_MAX_BW
);
612 case ISIS_SUBTLV_MAX_RSV_BW
:
613 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
614 sbuf_push(log
, indent
,
615 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
617 exts
->max_rsv_bw
= stream_getf(s
);
618 SET_SUBTLV(exts
, EXT_MAX_RSV_BW
);
621 case ISIS_SUBTLV_UNRSV_BW
:
622 if (subtlv_len
!= ISIS_SUBTLV_UNRSV_BW_SIZE
) {
623 sbuf_push(log
, indent
,
624 "TLV size does not match expected size for Unreserved Bandwidth!\n");
626 for (int i
= 0; i
< MAX_CLASS_TYPE
; i
++)
627 exts
->unrsv_bw
[i
] = stream_getf(s
);
628 SET_SUBTLV(exts
, EXT_UNRSV_BW
);
631 case ISIS_SUBTLV_TE_METRIC
:
632 if (subtlv_len
!= ISIS_SUBTLV_TE_METRIC_SIZE
) {
633 sbuf_push(log
, indent
,
634 "TLV size does not match expected size for Traffic Engineering Metric!\n");
636 exts
->te_metric
= stream_get3(s
);
637 SET_SUBTLV(exts
, EXT_TE_METRIC
);
640 case ISIS_SUBTLV_RAS
:
641 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
642 sbuf_push(log
, indent
,
643 "TLV size does not match expected size for Remote AS number!\n");
645 exts
->remote_as
= stream_getl(s
);
646 SET_SUBTLV(exts
, EXT_RMT_AS
);
649 case ISIS_SUBTLV_RIP
:
650 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
651 sbuf_push(log
, indent
,
652 "TLV size does not match expected size for Remote ASBR IP Address!\n");
654 stream_get(&exts
->remote_ip
.s_addr
, s
, 4);
655 SET_SUBTLV(exts
, EXT_RMT_IP
);
658 /* Extended Metrics as defined in RFC 7810 */
659 case ISIS_SUBTLV_AV_DELAY
:
660 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
661 sbuf_push(log
, indent
,
662 "TLV size does not match expected size for Average Link Delay!\n");
664 exts
->delay
= stream_getl(s
);
665 SET_SUBTLV(exts
, EXT_DELAY
);
668 case ISIS_SUBTLV_MM_DELAY
:
669 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
670 sbuf_push(log
, indent
,
671 "TLV size does not match expected size for Min/Max Link Delay!\n");
673 exts
->min_delay
= stream_getl(s
);
674 exts
->max_delay
= stream_getl(s
);
675 SET_SUBTLV(exts
, EXT_MM_DELAY
);
678 case ISIS_SUBTLV_DELAY_VAR
:
679 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
680 sbuf_push(log
, indent
,
681 "TLV size does not match expected size for Delay Variation!\n");
683 exts
->delay_var
= stream_getl(s
);
684 SET_SUBTLV(exts
, EXT_DELAY_VAR
);
687 case ISIS_SUBTLV_PKT_LOSS
:
688 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
689 sbuf_push(log
, indent
,
690 "TLV size does not match expected size for Link Packet Loss!\n");
692 exts
->pkt_loss
= stream_getl(s
);
693 SET_SUBTLV(exts
, EXT_PKT_LOSS
);
696 case ISIS_SUBTLV_RES_BW
:
697 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
698 sbuf_push(log
, indent
,
699 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
701 exts
->res_bw
= stream_getf(s
);
702 SET_SUBTLV(exts
, EXT_RES_BW
);
705 case ISIS_SUBTLV_AVA_BW
:
706 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
707 sbuf_push(log
, indent
,
708 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
710 exts
->ava_bw
= stream_getf(s
);
711 SET_SUBTLV(exts
, EXT_AVA_BW
);
714 case ISIS_SUBTLV_USE_BW
:
715 if (subtlv_len
!= ISIS_SUBTLV_DEF_SIZE
) {
716 sbuf_push(log
, indent
,
717 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
719 exts
->use_bw
= stream_getf(s
);
720 SET_SUBTLV(exts
, EXT_USE_BW
);
723 /* Segment Routing Adjacency */
724 case ISIS_SUBTLV_ADJ_SID
:
725 if (subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
726 && subtlv_len
!= ISIS_SUBTLV_ADJ_SID_SIZE
+ 1) {
727 sbuf_push(log
, indent
,
728 "TLV size does not match expected size for Adjacency SID!\n");
730 struct isis_adj_sid
*adj
;
732 adj
= XCALLOC(MTYPE_ISIS_SUBTLV
,
733 sizeof(struct isis_adj_sid
));
734 adj
->flags
= stream_getc(s
);
735 adj
->weight
= stream_getc(s
);
736 if (adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
737 adj
->sid
= stream_get3(s
);
738 adj
->sid
&= MPLS_LABEL_VALUE_MASK
;
740 adj
->sid
= stream_getl(s
);
742 if (mtid
== ISIS_MT_IPV4_UNICAST
)
743 adj
->family
= AF_INET
;
744 if (mtid
== ISIS_MT_IPV6_UNICAST
)
745 adj
->family
= AF_INET6
;
746 append_item(&exts
->adj_sid
,
747 (struct isis_item
*)adj
);
748 SET_SUBTLV(exts
, EXT_ADJ_SID
);
751 case ISIS_SUBTLV_LAN_ADJ_SID
:
752 if (subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
753 && subtlv_len
!= ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+ 1) {
754 sbuf_push(log
, indent
,
755 "TLV size does not match expected size for LAN-Adjacency SID!\n");
757 struct isis_lan_adj_sid
*lan
;
759 lan
= XCALLOC(MTYPE_ISIS_SUBTLV
,
760 sizeof(struct isis_lan_adj_sid
));
761 lan
->flags
= stream_getc(s
);
762 lan
->weight
= stream_getc(s
);
763 stream_get(&(lan
->neighbor_id
), s
,
765 if (lan
->flags
& EXT_SUBTLV_LINK_ADJ_SID_VFLG
) {
766 lan
->sid
= stream_get3(s
);
767 lan
->sid
&= MPLS_LABEL_VALUE_MASK
;
769 lan
->sid
= stream_getl(s
);
771 if (mtid
== ISIS_MT_IPV4_UNICAST
)
772 lan
->family
= AF_INET
;
773 if (mtid
== ISIS_MT_IPV6_UNICAST
)
774 lan
->family
= AF_INET6
;
775 append_item(&exts
->lan_sid
,
776 (struct isis_item
*)lan
);
777 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
781 /* Skip unknown TLV */
782 stream_forward_getp(s
, subtlv_len
);
785 sum
+= subtlv_len
+ ISIS_SUBTLV_HDR_SIZE
;
791 /* Functions for Sub-TLV 3 SR Prefix-SID */
792 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
794 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
795 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
797 rv
->flags
= sid
->flags
;
798 rv
->algorithm
= sid
->algorithm
;
799 rv
->value
= sid
->value
;
800 return (struct isis_item
*)rv
;
803 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
804 struct sbuf
*buf
, int indent
)
806 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
808 sbuf_push(buf
, indent
, "SR Prefix-SID ");
809 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
810 sbuf_push(buf
, 0, "Label: %" PRIu32
", ", sid
->value
);
812 sbuf_push(buf
, 0, "Index: %" PRIu32
", ", sid
->value
);
814 sbuf_push(buf
, 0, "Algorithm: %" PRIu8
", ", sid
->algorithm
);
815 sbuf_push(buf
, 0, "Flags:%s%s%s%s%s%s\n",
816 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
? " READVERTISED"
818 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
819 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO-PHP" : " PHP",
820 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
? " EXPLICIT-NULL"
822 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
823 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
826 static void free_item_prefix_sid(struct isis_item
*i
)
828 XFREE(MTYPE_ISIS_SUBTLV
, i
);
831 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
)
833 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
835 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
837 if (STREAM_WRITEABLE(s
) < size
)
840 stream_putc(s
, sid
->flags
);
841 stream_putc(s
, sid
->algorithm
);
843 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
844 stream_put3(s
, sid
->value
);
846 stream_putl(s
, sid
->value
);
852 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
853 struct sbuf
*log
, void *dest
, int indent
)
855 struct isis_subtlvs
*subtlvs
= dest
;
856 struct isis_prefix_sid sid
= {
859 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
862 sbuf_push(log
, indent
,
863 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
868 sid
.flags
= stream_getc(s
);
869 if (!!(sid
.flags
& ISIS_PREFIX_SID_VALUE
)
870 != !!(sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
871 sbuf_push(log
, indent
, "Flags implausible: Local Flag needs to match Value Flag\n");
875 sid
.algorithm
= stream_getc(s
);
877 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
)
878 ? ISIS_SUBTLV_PREFIX_SID_SIZE
879 : ISIS_SUBTLV_PREFIX_SID_SIZE
+ 1;
880 if (len
!= expected_size
) {
881 sbuf_push(log
, indent
,
882 "TLV size differs from expected size. "
883 "(expected %u but got %" PRIu8
")\n",
888 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
889 sid
.value
= stream_get3(s
);
890 sid
.value
&= MPLS_LABEL_VALUE_MASK
;
892 sid
.value
= stream_getl(s
);
895 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, indent
+ 2);
896 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
900 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
902 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
907 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
908 rv
->family
= p
->family
;
909 rv
->prefixlen
= p
->prefixlen
;
910 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
914 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
915 struct sbuf
*buf
, int indent
)
920 char prefixbuf
[PREFIX2STR_BUFFER
];
921 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
922 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
925 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
931 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
934 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
935 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
936 stream_putc(s
, p
->prefixlen
);
937 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
941 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
942 uint8_t tlv_type
, uint8_t tlv_len
,
943 struct stream
*s
, struct sbuf
*log
,
944 void *dest
, int indent
)
946 struct isis_subtlvs
*subtlvs
= dest
;
947 struct prefix_ipv6 p
= {
951 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
954 sbuf_push(log
, indent
,
955 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
")\n",
960 p
.prefixlen
= stream_getc(s
);
961 if (p
.prefixlen
> 128) {
962 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
967 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
970 "TLV size differs from expected size for the prefixlen. "
971 "(expected %u but got %" PRIu8
")\n",
972 1 + PSIZE(p
.prefixlen
), tlv_len
);
976 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
978 if (subtlvs
->source_prefix
) {
981 "WARNING: source prefix Sub-TLV present multiple times.\n");
982 /* Ignore all but first occurrence of the source prefix Sub-TLV
987 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
988 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
992 static struct isis_item
*copy_item(enum isis_tlv_context context
,
993 enum isis_tlv_type type
,
994 struct isis_item
*item
);
995 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
996 struct isis_item_list
*src
, struct isis_item_list
*dest
);
997 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
998 enum isis_tlv_type type
, struct isis_item_list
*items
,
999 struct sbuf
*buf
, int indent
);
1000 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1001 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1002 struct isis_item_list
*items
);
1003 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1004 enum isis_tlv_type type
, struct isis_item_list
*items
,
1005 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1006 const struct pack_order_entry
*pe
,
1007 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1008 struct list
*new_fragment_arg
);
1009 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1011 /* Functions related to subtlvs */
1013 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
1015 struct isis_subtlvs
*result
;
1017 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
1018 result
->context
= context
;
1020 init_item_list(&result
->prefix_sids
);
1025 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
1030 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
1032 rv
->context
= subtlvs
->context
;
1034 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1035 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
1038 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
1042 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
1045 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1046 &subtlvs
->prefix_sids
, buf
, indent
);
1048 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
1051 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
1056 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1057 &subtlvs
->prefix_sids
);
1059 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
1061 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
1064 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
1067 size_t subtlv_len_pos
= stream_get_endp(s
);
1069 if (STREAM_WRITEABLE(s
) < 1)
1072 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
1074 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
1075 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
1079 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
1083 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
1084 if (subtlv_len
> 255)
1087 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
1091 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
1092 struct stream
*stream
, struct sbuf
*log
, void *dest
,
1093 int indent
, bool *unpacked_known_tlvs
);
1095 /* Functions related to TLVs 1 Area Addresses */
1097 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
1099 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1100 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1102 rv
->len
= addr
->len
;
1103 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
1104 return (struct isis_item
*)rv
;
1107 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
1108 struct sbuf
*buf
, int indent
)
1110 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1112 sbuf_push(buf
, indent
, "Area Address: %s\n",
1113 isonet_print(addr
->addr
, addr
->len
));
1116 static void free_item_area_address(struct isis_item
*i
)
1118 XFREE(MTYPE_ISIS_TLV
, i
);
1121 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
1123 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
1125 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
1127 stream_putc(s
, addr
->len
);
1128 stream_put(s
, addr
->addr
, addr
->len
);
1132 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
1133 struct stream
*s
, struct sbuf
*log
,
1134 void *dest
, int indent
)
1136 struct isis_tlvs
*tlvs
= dest
;
1137 struct isis_area_address
*rv
= NULL
;
1139 sbuf_push(log
, indent
, "Unpack area address...\n");
1143 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
1149 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1150 rv
->len
= stream_getc(s
);
1152 if (len
< 1 + rv
->len
) {
1153 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
1154 " bytes of address, got %" PRIu8
")\n",
1159 if (rv
->len
< 1 || rv
->len
> 20) {
1160 sbuf_push(log
, indent
,
1161 "Implausible area address length %" PRIu8
"\n",
1166 stream_get(rv
->addr
, s
, rv
->len
);
1168 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
1170 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
1173 XFREE(MTYPE_ISIS_TLV
, rv
);
1177 /* Functions related to TLV 2 (Old-Style) IS Reach */
1178 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
1180 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1181 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1183 memcpy(rv
->id
, r
->id
, 7);
1184 rv
->metric
= r
->metric
;
1185 return (struct isis_item
*)rv
;
1188 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
1189 struct sbuf
*buf
, int indent
)
1191 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1193 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
1194 isis_format_id(r
->id
, 7), r
->metric
);
1197 static void free_item_oldstyle_reach(struct isis_item
*i
)
1199 XFREE(MTYPE_ISIS_TLV
, i
);
1202 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
1204 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
1206 if (STREAM_WRITEABLE(s
) < 11)
1209 stream_putc(s
, r
->metric
);
1210 stream_putc(s
, 0x80); /* delay metric - unsupported */
1211 stream_putc(s
, 0x80); /* expense metric - unsupported */
1212 stream_putc(s
, 0x80); /* error metric - unsupported */
1213 stream_put(s
, r
->id
, 7);
1218 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
1219 struct stream
*s
, struct sbuf
*log
,
1220 void *dest
, int indent
)
1222 struct isis_tlvs
*tlvs
= dest
;
1224 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
1228 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
1234 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1235 rv
->metric
= stream_getc(s
);
1236 if ((rv
->metric
& 0x3f) != rv
->metric
) {
1237 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1240 stream_forward_getp(s
, 3); /* Skip other metrics */
1241 stream_get(rv
->id
, s
, 7);
1243 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
1245 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
1249 /* Functions related to TLV 6 LAN Neighbors */
1250 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
1252 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1253 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1255 memcpy(rv
->mac
, n
->mac
, 6);
1256 return (struct isis_item
*)rv
;
1259 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
1260 struct sbuf
*buf
, int indent
)
1262 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1264 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
1267 static void free_item_lan_neighbor(struct isis_item
*i
)
1269 XFREE(MTYPE_ISIS_TLV
, i
);
1272 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
1274 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
1276 if (STREAM_WRITEABLE(s
) < 6)
1279 stream_put(s
, n
->mac
, 6);
1284 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
1285 struct stream
*s
, struct sbuf
*log
,
1286 void *dest
, int indent
)
1288 struct isis_tlvs
*tlvs
= dest
;
1290 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
1294 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
1300 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1301 stream_get(rv
->mac
, s
, 6);
1303 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1304 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
1308 /* Functions related to TLV 9 LSP Entry */
1309 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
1311 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1312 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1314 rv
->rem_lifetime
= e
->rem_lifetime
;
1315 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
1316 rv
->seqno
= e
->seqno
;
1317 rv
->checksum
= e
->checksum
;
1319 return (struct isis_item
*)rv
;
1322 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
1323 struct sbuf
*buf
, int indent
)
1325 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1327 sbuf_push(buf
, indent
,
1328 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
1329 ", lifetime %" PRIu16
"s\n",
1330 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
1334 static void free_item_lsp_entry(struct isis_item
*i
)
1336 XFREE(MTYPE_ISIS_TLV
, i
);
1339 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
1341 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
1343 if (STREAM_WRITEABLE(s
) < 16)
1346 stream_putw(s
, e
->rem_lifetime
);
1347 stream_put(s
, e
->id
, 8);
1348 stream_putl(s
, e
->seqno
);
1349 stream_putw(s
, e
->checksum
);
1354 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1355 struct sbuf
*log
, void *dest
, int indent
)
1357 struct isis_tlvs
*tlvs
= dest
;
1359 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
1363 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
1368 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1369 rv
->rem_lifetime
= stream_getw(s
);
1370 stream_get(rv
->id
, s
, 8);
1371 rv
->seqno
= stream_getl(s
);
1372 rv
->checksum
= stream_getw(s
);
1374 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1375 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
1379 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1381 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
1383 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1384 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1386 memcpy(rv
->id
, r
->id
, 7);
1387 rv
->metric
= r
->metric
;
1390 rv
->subtlvs
= copy_item_ext_subtlvs(r
->subtlvs
, -1);
1392 return (struct isis_item
*)rv
;
1395 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
1396 struct sbuf
*buf
, int indent
)
1398 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1400 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
1401 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1402 isis_format_id(r
->id
, 7), r
->metric
);
1403 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1404 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1405 sbuf_push(buf
, 0, "\n");
1408 format_item_ext_subtlvs(r
->subtlvs
, buf
, indent
+ 2, mtid
);
1411 static void free_item_extended_reach(struct isis_item
*i
)
1413 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
1414 if (item
->subtlvs
!= NULL
)
1415 free_item_ext_subtlvs(item
->subtlvs
);
1416 XFREE(MTYPE_ISIS_TLV
, item
);
1419 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
1421 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
1425 if (STREAM_WRITEABLE(s
) < 11 + ISIS_SUBTLV_MAX_SIZE
)
1428 stream_put(s
, r
->id
, sizeof(r
->id
));
1429 stream_put3(s
, r
->metric
);
1430 len_pos
= stream_get_endp(s
);
1431 /* Real length will be adjust after adding subTLVs */
1434 pack_item_ext_subtlvs(r
->subtlvs
, s
);
1436 len
= stream_get_endp(s
) - len_pos
- 1;
1437 stream_putc_at(s
, len_pos
, len
);
1441 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
1442 struct stream
*s
, struct sbuf
*log
,
1443 void *dest
, int indent
)
1445 struct isis_tlvs
*tlvs
= dest
;
1446 struct isis_extended_reach
*rv
= NULL
;
1448 struct isis_item_list
*items
;
1450 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1451 items
= &tlvs
->extended_reach
;
1453 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
1456 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
1457 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1460 sbuf_push(log
, indent
,
1461 "Not enough data left. (expected 11 or more bytes, got %"
1467 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1468 stream_get(rv
->id
, s
, 7);
1469 rv
->metric
= stream_get3(s
);
1470 subtlv_len
= stream_getc(s
);
1472 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
1473 sbuf_push(log
, indent
,
1474 "Not enough data left for subtlv size %" PRIu8
1475 ", there are only %" PRIu8
" bytes left.\n",
1476 subtlv_len
, len
- 11);
1480 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
1484 if (unpack_item_ext_subtlvs(mtid
, subtlv_len
, s
, log
, rv
,
1490 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
1492 append_item(items
, (struct isis_item
*)rv
);
1496 free_item_extended_reach((struct isis_item
*)rv
);
1501 /* Functions related to TLV 128 (Old-Style) IP Reach */
1502 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
1504 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1505 struct isis_oldstyle_ip_reach
*rv
=
1506 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1508 rv
->metric
= r
->metric
;
1509 rv
->prefix
= r
->prefix
;
1510 return (struct isis_item
*)rv
;
1513 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1514 struct sbuf
*buf
, int indent
)
1516 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1517 char prefixbuf
[PREFIX2STR_BUFFER
];
1519 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
1520 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1524 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
1526 XFREE(MTYPE_ISIS_TLV
, i
);
1529 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
1531 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
1533 if (STREAM_WRITEABLE(s
) < 12)
1536 stream_putc(s
, r
->metric
);
1537 stream_putc(s
, 0x80); /* delay metric - unsupported */
1538 stream_putc(s
, 0x80); /* expense metric - unsupported */
1539 stream_putc(s
, 0x80); /* error metric - unsupported */
1540 stream_put(s
, &r
->prefix
.prefix
, 4);
1542 struct in_addr mask
;
1543 masklen2ip(r
->prefix
.prefixlen
, &mask
);
1544 stream_put(s
, &mask
, sizeof(mask
));
1549 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
1550 struct stream
*s
, struct sbuf
*log
,
1551 void *dest
, int indent
)
1553 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
1557 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
1563 struct isis_oldstyle_ip_reach
*rv
=
1564 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1565 rv
->metric
= stream_getc(s
);
1566 if ((rv
->metric
& 0x7f) != rv
->metric
) {
1567 sbuf_push(log
, indent
, "Metric has unplausible format\n");
1570 stream_forward_getp(s
, 3); /* Skip other metrics */
1571 rv
->prefix
.family
= AF_INET
;
1572 stream_get(&rv
->prefix
.prefix
, s
, 4);
1574 struct in_addr mask
;
1575 stream_get(&mask
, s
, 4);
1576 rv
->prefix
.prefixlen
= ip_masklen(mask
);
1578 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1580 append_item(dest
, (struct isis_item
*)rv
);
1585 /* Functions related to TLV 129 protocols supported */
1587 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
1588 struct isis_protocols_supported
*dest
)
1590 if (!src
->protocols
|| !src
->count
)
1592 dest
->count
= src
->count
;
1593 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
1594 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
1597 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
1598 struct sbuf
*buf
, int indent
)
1600 if (!p
|| !p
->count
|| !p
->protocols
)
1603 sbuf_push(buf
, indent
, "Protocols Supported: ");
1604 for (uint8_t i
= 0; i
< p
->count
; i
++) {
1605 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
1606 (i
+ 1 < p
->count
) ? ", " : "");
1608 sbuf_push(buf
, 0, "\n");
1611 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
1613 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
1616 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
1619 if (!p
|| !p
->count
|| !p
->protocols
)
1622 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
1625 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
1626 stream_putc(s
, p
->count
);
1627 stream_put(s
, p
->protocols
, p
->count
);
1631 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
1632 uint8_t tlv_type
, uint8_t tlv_len
,
1633 struct stream
*s
, struct sbuf
*log
,
1634 void *dest
, int indent
)
1636 struct isis_tlvs
*tlvs
= dest
;
1638 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
1640 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
1643 if (tlvs
->protocols_supported
.protocols
) {
1646 "WARNING: protocols supported TLV present multiple times.\n");
1647 stream_forward_getp(s
, tlv_len
);
1651 tlvs
->protocols_supported
.count
= tlv_len
;
1652 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
1653 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
1655 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
1660 /* Functions related to TLV 132 IPv4 Interface addresses */
1661 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
1663 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1664 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1667 return (struct isis_item
*)rv
;
1670 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
1671 struct sbuf
*buf
, int indent
)
1673 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1674 char addrbuf
[INET_ADDRSTRLEN
];
1676 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1677 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
1680 static void free_item_ipv4_address(struct isis_item
*i
)
1682 XFREE(MTYPE_ISIS_TLV
, i
);
1685 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
1687 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1689 if (STREAM_WRITEABLE(s
) < 4)
1692 stream_put(s
, &a
->addr
, 4);
1697 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
1698 struct stream
*s
, struct sbuf
*log
,
1699 void *dest
, int indent
)
1701 struct isis_tlvs
*tlvs
= dest
;
1703 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
1707 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
1713 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1714 stream_get(&rv
->addr
, s
, 4);
1716 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1717 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
1722 /* Functions related to TLV 232 IPv6 Interface addresses */
1723 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
1725 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1726 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1729 return (struct isis_item
*)rv
;
1732 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
1733 struct sbuf
*buf
, int indent
)
1735 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1736 char addrbuf
[INET6_ADDRSTRLEN
];
1738 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1739 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
1742 static void free_item_ipv6_address(struct isis_item
*i
)
1744 XFREE(MTYPE_ISIS_TLV
, i
);
1747 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
1749 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1751 if (STREAM_WRITEABLE(s
) < 16)
1754 stream_put(s
, &a
->addr
, 16);
1759 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
1760 struct stream
*s
, struct sbuf
*log
,
1761 void *dest
, int indent
)
1763 struct isis_tlvs
*tlvs
= dest
;
1765 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
1769 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
1775 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1776 stream_get(&rv
->addr
, s
, 16);
1778 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1779 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
1784 /* Functions related to TLV 229 MT Router information */
1785 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
1787 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1788 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1790 rv
->overload
= info
->overload
;
1791 rv
->attached
= info
->attached
;
1792 rv
->mtid
= info
->mtid
;
1793 return (struct isis_item
*)rv
;
1796 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
1797 struct sbuf
*buf
, int indent
)
1799 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1801 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
1802 isis_mtid2str(info
->mtid
),
1803 info
->overload
? " Overload" : "",
1804 info
->attached
? " Attached" : "");
1807 static void free_item_mt_router_info(struct isis_item
*i
)
1809 XFREE(MTYPE_ISIS_TLV
, i
);
1812 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
1814 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1816 if (STREAM_WRITEABLE(s
) < 2)
1819 uint16_t entry
= info
->mtid
;
1822 entry
|= ISIS_MT_OL_MASK
;
1824 entry
|= ISIS_MT_AT_MASK
;
1826 stream_putw(s
, entry
);
1831 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1832 struct stream
*s
, struct sbuf
*log
,
1833 void *dest
, int indent
)
1835 struct isis_tlvs
*tlvs
= dest
;
1837 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1841 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1847 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1849 uint16_t entry
= stream_getw(s
);
1850 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1851 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1852 rv
->mtid
= entry
& ISIS_MT_MASK
;
1854 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1856 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1860 /* Functions related to TLV 134 TE Router ID */
1862 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1867 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1868 memcpy(rv
, id
, sizeof(*rv
));
1872 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1878 char addrbuf
[INET_ADDRSTRLEN
];
1879 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1880 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1883 static void free_tlv_te_router_id(struct in_addr
*id
)
1885 XFREE(MTYPE_ISIS_TLV
, id
);
1888 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1893 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1896 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1898 stream_put(s
, id
, 4);
1902 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1903 uint8_t tlv_type
, uint8_t tlv_len
,
1904 struct stream
*s
, struct sbuf
*log
,
1905 void *dest
, int indent
)
1907 struct isis_tlvs
*tlvs
= dest
;
1909 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1911 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1915 if (tlvs
->te_router_id
) {
1916 sbuf_push(log
, indent
,
1917 "WARNING: TE Router ID present multiple times.\n");
1918 stream_forward_getp(s
, tlv_len
);
1922 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1923 stream_get(tlvs
->te_router_id
, s
, 4);
1924 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1929 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1931 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1933 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1934 struct isis_extended_ip_reach
*rv
=
1935 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1937 rv
->metric
= r
->metric
;
1939 rv
->prefix
= r
->prefix
;
1940 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1942 return (struct isis_item
*)rv
;
1945 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1946 struct sbuf
*buf
, int indent
)
1948 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1949 char prefixbuf
[PREFIX2STR_BUFFER
];
1951 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1952 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1953 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1954 r
->down
? " Down" : "");
1955 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1956 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1957 sbuf_push(buf
, 0, "\n");
1960 sbuf_push(buf
, indent
, " Subtlvs:\n");
1961 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1965 static void free_item_extended_ip_reach(struct isis_item
*i
)
1967 struct isis_extended_ip_reach
*item
=
1968 (struct isis_extended_ip_reach
*)i
;
1969 isis_free_subtlvs(item
->subtlvs
);
1970 XFREE(MTYPE_ISIS_TLV
, item
);
1973 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1975 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1978 if (STREAM_WRITEABLE(s
) < 5)
1980 stream_putl(s
, r
->metric
);
1982 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1983 control
|= r
->prefix
.prefixlen
;
1984 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
1986 stream_putc(s
, control
);
1988 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1990 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1993 return pack_subtlvs(r
->subtlvs
, s
);
1997 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1998 struct stream
*s
, struct sbuf
*log
,
1999 void *dest
, int indent
)
2001 struct isis_tlvs
*tlvs
= dest
;
2002 struct isis_extended_ip_reach
*rv
= NULL
;
2004 uint8_t control
, subtlv_len
;
2005 struct isis_item_list
*items
;
2007 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2008 items
= &tlvs
->extended_ip_reach
;
2010 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
2013 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
2014 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
2017 if (len
< consume
) {
2018 sbuf_push(log
, indent
,
2019 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
2024 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2026 rv
->metric
= stream_getl(s
);
2027 control
= stream_getc(s
);
2028 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
2029 rv
->prefix
.family
= AF_INET
;
2030 rv
->prefix
.prefixlen
= control
& 0x3f;
2031 if (rv
->prefix
.prefixlen
> 32) {
2032 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv4\n",
2033 rv
->prefix
.prefixlen
);
2037 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2038 if (len
< consume
) {
2039 sbuf_push(log
, indent
,
2040 "Expected %u bytes of prefix, but only %u bytes available.\n",
2041 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
2044 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2045 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
2046 apply_mask_ipv4(&rv
->prefix
);
2047 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
2048 sbuf_push(log
, indent
+ 2,
2049 "WARNING: Prefix had hostbits set.\n");
2050 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
2053 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
2055 if (len
< consume
) {
2056 sbuf_push(log
, indent
,
2057 "Expected 1 byte of subtlv len, but no more data present.\n");
2060 subtlv_len
= stream_getc(s
);
2063 sbuf_push(log
, indent
+ 2,
2064 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2066 consume
+= subtlv_len
;
2067 if (len
< consume
) {
2068 sbuf_push(log
, indent
,
2070 " bytes of subtlvs, but only %u bytes available.\n",
2072 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2076 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
2077 bool unpacked_known_tlvs
= false;
2079 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
2080 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2083 if (!unpacked_known_tlvs
) {
2084 isis_free_subtlvs(rv
->subtlvs
);
2089 append_item(items
, (struct isis_item
*)rv
);
2093 free_item_extended_ip_reach((struct isis_item
*)rv
);
2097 /* Functions related to TLV 137 Dynamic Hostname */
2099 static char *copy_tlv_dynamic_hostname(const char *hostname
)
2104 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2107 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
2113 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
2116 static void free_tlv_dynamic_hostname(char *hostname
)
2118 XFREE(MTYPE_ISIS_TLV
, hostname
);
2121 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
2126 uint8_t name_len
= strlen(hostname
);
2128 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
2131 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
2132 stream_putc(s
, name_len
);
2133 stream_put(s
, hostname
, name_len
);
2137 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
2138 uint8_t tlv_type
, uint8_t tlv_len
,
2139 struct stream
*s
, struct sbuf
*log
,
2140 void *dest
, int indent
)
2142 struct isis_tlvs
*tlvs
= dest
;
2144 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
2146 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
2150 if (tlvs
->hostname
) {
2151 sbuf_push(log
, indent
,
2152 "WARNING: Hostname present multiple times.\n");
2153 stream_forward_getp(s
, tlv_len
);
2157 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
2158 stream_get(tlvs
->hostname
, s
, tlv_len
);
2159 tlvs
->hostname
[tlv_len
] = '\0';
2162 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
2163 if ((unsigned char)tlvs
->hostname
[i
] > 127
2164 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
2166 tlvs
->hostname
[i
] = '?';
2172 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2178 /* Functions related to TLV 150 Spine-Leaf-Extension */
2180 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
2181 const struct isis_spine_leaf
*spine_leaf
)
2186 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2187 memcpy(rv
, spine_leaf
, sizeof(*rv
));
2192 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2193 struct sbuf
*buf
, int indent
)
2198 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
2199 if (spine_leaf
->has_tier
) {
2200 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
2201 sbuf_push(buf
, indent
, " Tier: undefined\n");
2203 sbuf_push(buf
, indent
, " Tier: %" PRIu8
"\n",
2208 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
2209 spine_leaf
->is_leaf
? " LEAF" : "",
2210 spine_leaf
->is_spine
? " SPINE" : "",
2211 spine_leaf
->is_backup
? " BACKUP" : "");
2215 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
2217 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
2220 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2221 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2222 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2223 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2225 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
2231 uint8_t tlv_len
= 2;
2233 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2236 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
2237 stream_putc(s
, tlv_len
);
2239 uint16_t spine_leaf_flags
= 0;
2241 if (spine_leaf
->has_tier
) {
2242 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
2243 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
2246 if (spine_leaf
->is_leaf
)
2247 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
2249 if (spine_leaf
->is_spine
)
2250 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
2252 if (spine_leaf
->is_backup
)
2253 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
2255 stream_putw(s
, spine_leaf_flags
);
2260 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
2261 uint8_t tlv_type
, uint8_t tlv_len
,
2262 struct stream
*s
, struct sbuf
*log
,
2263 void *dest
, int indent
)
2265 struct isis_tlvs
*tlvs
= dest
;
2267 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
2269 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
2270 stream_forward_getp(s
, tlv_len
);
2274 if (tlvs
->spine_leaf
) {
2275 sbuf_push(log
, indent
,
2276 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
2277 stream_forward_getp(s
, tlv_len
);
2281 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
2283 uint16_t spine_leaf_flags
= stream_getw(s
);
2285 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
2286 tlvs
->spine_leaf
->has_tier
= true;
2287 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
2290 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
2291 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
2292 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
2294 stream_forward_getp(s
, tlv_len
- 2);
2298 /* Functions related to TLV 240 P2P Three-Way Adjacency */
2300 const char *isis_threeway_state_name(enum isis_threeway_state state
)
2303 case ISIS_THREEWAY_DOWN
:
2305 case ISIS_THREEWAY_INITIALIZING
:
2306 return "Initializing";
2307 case ISIS_THREEWAY_UP
:
2314 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
2315 const struct isis_threeway_adj
*threeway_adj
)
2320 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2321 memcpy(rv
, threeway_adj
, sizeof(*rv
));
2326 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
2327 struct sbuf
*buf
, int indent
)
2332 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
2333 sbuf_push(buf
, indent
, " State: %s (%d)\n",
2334 isis_threeway_state_name(threeway_adj
->state
),
2335 threeway_adj
->state
);
2336 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %" PRIu32
"\n",
2337 threeway_adj
->local_circuit_id
);
2338 if (!threeway_adj
->neighbor_set
)
2341 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
2342 isis_format_id(threeway_adj
->neighbor_id
, 6));
2343 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %" PRIu32
"\n",
2344 threeway_adj
->neighbor_circuit_id
);
2347 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
2349 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
2352 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
2358 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
2360 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
2363 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
2364 stream_putc(s
, tlv_len
);
2365 stream_putc(s
, threeway_adj
->state
);
2366 stream_putl(s
, threeway_adj
->local_circuit_id
);
2368 if (threeway_adj
->neighbor_set
) {
2369 stream_put(s
, threeway_adj
->neighbor_id
, 6);
2370 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
2376 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
2377 uint8_t tlv_type
, uint8_t tlv_len
,
2378 struct stream
*s
, struct sbuf
*log
,
2379 void *dest
, int indent
)
2381 struct isis_tlvs
*tlvs
= dest
;
2383 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
2384 if (tlv_len
!= 5 && tlv_len
!= 15) {
2385 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
2386 stream_forward_getp(s
, tlv_len
);
2390 if (tlvs
->threeway_adj
) {
2391 sbuf_push(log
, indent
,
2392 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
2393 stream_forward_getp(s
, tlv_len
);
2397 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
2399 tlvs
->threeway_adj
->state
= stream_getc(s
);
2400 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
2402 if (tlv_len
== 15) {
2403 tlvs
->threeway_adj
->neighbor_set
= true;
2404 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
2405 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
2411 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
2413 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
2415 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2416 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2417 rv
->metric
= r
->metric
;
2419 rv
->external
= r
->external
;
2420 rv
->prefix
= r
->prefix
;
2421 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
2423 return (struct isis_item
*)rv
;
2426 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
2427 struct sbuf
*buf
, int indent
)
2429 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2430 char prefixbuf
[PREFIX2STR_BUFFER
];
2432 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
2433 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
2434 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
2436 r
->down
? " Down" : "",
2437 r
->external
? " External" : "");
2438 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
2439 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
2440 sbuf_push(buf
, 0, "\n");
2443 sbuf_push(buf
, indent
, " Subtlvs:\n");
2444 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
2448 static void free_item_ipv6_reach(struct isis_item
*i
)
2450 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
2452 isis_free_subtlvs(item
->subtlvs
);
2453 XFREE(MTYPE_ISIS_TLV
, item
);
2456 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
2458 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
2461 if (STREAM_WRITEABLE(s
) < 6)
2463 stream_putl(s
, r
->metric
);
2465 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
2466 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
2467 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
2469 stream_putc(s
, control
);
2470 stream_putc(s
, r
->prefix
.prefixlen
);
2472 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
2474 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
2477 return pack_subtlvs(r
->subtlvs
, s
);
2482 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
2483 struct sbuf
*log
, void *dest
, int indent
)
2485 struct isis_tlvs
*tlvs
= dest
;
2486 struct isis_ipv6_reach
*rv
= NULL
;
2488 uint8_t control
, subtlv_len
;
2489 struct isis_item_list
*items
;
2491 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
2492 items
= &tlvs
->ipv6_reach
;
2494 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
2497 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
2498 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
2500 if (len
< consume
) {
2501 sbuf_push(log
, indent
,
2502 "Not enough data left. (expected 6 or more bytes, got %"
2508 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2510 rv
->metric
= stream_getl(s
);
2511 control
= stream_getc(s
);
2512 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
2513 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
2515 rv
->prefix
.family
= AF_INET6
;
2516 rv
->prefix
.prefixlen
= stream_getc(s
);
2517 if (rv
->prefix
.prefixlen
> 128) {
2518 sbuf_push(log
, indent
, "Prefixlen %u is implausible for IPv6\n",
2519 rv
->prefix
.prefixlen
);
2523 consume
+= PSIZE(rv
->prefix
.prefixlen
);
2524 if (len
< consume
) {
2525 sbuf_push(log
, indent
,
2526 "Expected %u bytes of prefix, but only %u bytes available.\n",
2527 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
2530 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
2531 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
2533 apply_mask_ipv6(&rv
->prefix
);
2534 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
2535 sbuf_push(log
, indent
+ 2,
2536 "WARNING: Prefix had hostbits set.\n");
2537 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2539 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
2541 if (len
< consume
) {
2542 sbuf_push(log
, indent
,
2543 "Expected 1 byte of subtlv len, but no more data persent.\n");
2546 subtlv_len
= stream_getc(s
);
2549 sbuf_push(log
, indent
+ 2,
2550 " WARNING: subtlv bit set, but there are no subtlvs.\n");
2552 consume
+= subtlv_len
;
2553 if (len
< consume
) {
2554 sbuf_push(log
, indent
,
2556 " bytes of subtlvs, but only %u bytes available.\n",
2558 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
2562 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
2563 bool unpacked_known_tlvs
= false;
2565 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
2566 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
2569 if (!unpacked_known_tlvs
) {
2570 isis_free_subtlvs(rv
->subtlvs
);
2575 append_item(items
, (struct isis_item
*)rv
);
2579 free_item_ipv6_reach((struct isis_item
*)rv
);
2583 /* Functions related to TLV 242 Router Capability */
2584 static struct isis_router_cap
*copy_tlv_router_cap(
2585 const struct isis_router_cap
*router_cap
)
2587 struct isis_router_cap
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2592 memcpy(rv
, router_cap
, sizeof(*rv
));
2597 static void format_tlv_router_cap(const struct isis_router_cap
*router_cap
,
2598 struct sbuf
*buf
, int indent
)
2600 char addrbuf
[INET_ADDRSTRLEN
];
2605 /* Router ID and Flags */
2606 inet_ntop(AF_INET
, &router_cap
->router_id
, addrbuf
, sizeof(addrbuf
));
2607 sbuf_push(buf
, indent
, "Router Capability:");
2608 sbuf_push(buf
, indent
, " %s , D:%c, S:%c\n", addrbuf
,
2609 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_D
? '1' : '0',
2610 router_cap
->flags
& ISIS_ROUTER_CAP_FLAG_S
? '1' : '0');
2612 /* SR Global Block */
2613 if (router_cap
->srgb
.range_size
!= 0)
2614 sbuf_push(buf
, indent
,
2615 " Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n",
2616 IS_SR_IPV4(router_cap
->srgb
) ? "1" : "0",
2617 IS_SR_IPV6(router_cap
->srgb
) ? "1" : "0",
2618 router_cap
->srgb
.lower_bound
,
2619 router_cap
->srgb
.range_size
);
2622 if (router_cap
->algo
[0] != SR_ALGORITHM_UNSET
) {
2623 sbuf_push(buf
, indent
, " Algorithm: %s",
2624 router_cap
->algo
[0] == 0 ? "0: SPF"
2626 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
2627 if (router_cap
->algo
[i
] != SR_ALGORITHM_UNSET
)
2628 sbuf_push(buf
, indent
, " %s",
2629 router_cap
->algo
[1] == 0
2632 sbuf_push(buf
, indent
, "\n");
2636 if (router_cap
->msd
!= 0)
2637 sbuf_push(buf
, indent
, " Node MSD: %d\n", router_cap
->msd
);
2640 static void free_tlv_router_cap(struct isis_router_cap
*router_cap
)
2642 XFREE(MTYPE_ISIS_TLV
, router_cap
);
2645 static int pack_tlv_router_cap(const struct isis_router_cap
*router_cap
,
2648 size_t tlv_len
= ISIS_ROUTER_CAP_SIZE
;
2655 /* Compute Maximum TLV size */
2656 tlv_len
+= ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
2657 + ISIS_SUBTLV_HDR_SIZE
2658 + ISIS_SUBTLV_ALGORITHM_SIZE
2659 + ISIS_SUBTLV_NODE_MSD_SIZE
;
2661 if (STREAM_WRITEABLE(s
) < (unsigned int)(2 + tlv_len
))
2664 /* Add Router Capability TLV 242 with Router ID and Flags */
2665 stream_putc(s
, ISIS_TLV_ROUTER_CAPABILITY
);
2666 /* Real length will be adjusted later */
2667 len_pos
= stream_get_endp(s
);
2668 stream_putc(s
, tlv_len
);
2669 stream_put_ipv4(s
, router_cap
->router_id
.s_addr
);
2670 stream_putc(s
, router_cap
->flags
);
2672 /* Add SRGB if set */
2673 if ((router_cap
->srgb
.range_size
!= 0)
2674 && (router_cap
->srgb
.lower_bound
!= 0)) {
2675 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE
);
2676 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
);
2677 stream_putc(s
, router_cap
->srgb
.flags
);
2678 stream_put3(s
, router_cap
->srgb
.range_size
);
2679 stream_putc(s
, ISIS_SUBTLV_SID_LABEL
);
2680 stream_putc(s
, ISIS_SUBTLV_SID_LABEL_SIZE
);
2681 stream_put3(s
, router_cap
->srgb
.lower_bound
);
2683 /* Then SR Algorithm if set */
2684 for (nb_algo
= 0; nb_algo
< SR_ALGORITHM_COUNT
; nb_algo
++)
2685 if (router_cap
->algo
[nb_algo
] == SR_ALGORITHM_UNSET
)
2688 stream_putc(s
, ISIS_SUBTLV_ALGORITHM
);
2689 stream_putc(s
, nb_algo
);
2690 for (int i
= 0; i
< nb_algo
; i
++)
2691 stream_putc(s
, router_cap
->algo
[i
]);
2693 /* And finish with MSD if set */
2694 if (router_cap
->msd
!= 0) {
2695 stream_putc(s
, ISIS_SUBTLV_NODE_MSD
);
2696 stream_putc(s
, ISIS_SUBTLV_NODE_MSD_SIZE
);
2697 stream_putc(s
, MSD_TYPE_BASE_MPLS_IMPOSITION
);
2698 stream_putc(s
, router_cap
->msd
);
2702 /* Adjust TLV length which depends on subTLVs presence */
2703 tlv_len
= stream_get_endp(s
) - len_pos
- 1;
2704 stream_putc_at(s
, len_pos
, tlv_len
);
2709 static int unpack_tlv_router_cap(enum isis_tlv_context context
,
2710 uint8_t tlv_type
, uint8_t tlv_len
,
2711 struct stream
*s
, struct sbuf
*log
,
2712 void *dest
, int indent
)
2714 struct isis_tlvs
*tlvs
= dest
;
2720 sbuf_push(log
, indent
, "Unpacking Router Capability TLV...\n");
2721 if (tlv_len
< ISIS_ROUTER_CAP_SIZE
) {
2722 sbuf_push(log
, indent
, "WARNING: Unexpected TLV size\n");
2723 stream_forward_getp(s
, tlv_len
);
2727 if (tlvs
->router_cap
) {
2728 sbuf_push(log
, indent
,
2729 "WARNING: Router Capability TLV present multiple times.\n");
2730 stream_forward_getp(s
, tlv_len
);
2734 /* Allocate router cap structure and initialize SR Algorithms */
2735 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
2736 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
2737 tlvs
->router_cap
->algo
[i
] = SR_ALGORITHM_UNSET
;
2739 /* Get Router ID and Flags */
2740 tlvs
->router_cap
->router_id
.s_addr
= stream_get_ipv4(s
);
2741 tlvs
->router_cap
->flags
= stream_getc(s
);
2743 /* Parse remaining part of the TLV if present */
2744 subtlv_len
= tlv_len
- ISIS_ROUTER_CAP_SIZE
;
2745 while (subtlv_len
> 2) {
2746 struct isis_router_cap
*rc
= tlvs
->router_cap
;
2749 type
= stream_getc(s
);
2750 length
= stream_getc(s
);
2752 case ISIS_SUBTLV_SID_LABEL_RANGE
:
2753 rc
->srgb
.flags
= stream_getc(s
);
2754 rc
->srgb
.range_size
= stream_get3(s
);
2755 /* Skip Type and get Length of SID Label */
2757 sid_len
= stream_getc(s
);
2758 if (sid_len
== ISIS_SUBTLV_SID_LABEL_SIZE
)
2759 rc
->srgb
.lower_bound
= stream_get3(s
);
2761 rc
->srgb
.lower_bound
= stream_getl(s
);
2763 /* SRGB sanity checks. */
2764 if (rc
->srgb
.range_size
== 0
2765 || (rc
->srgb
.lower_bound
<= MPLS_LABEL_RESERVED_MAX
)
2766 || ((rc
->srgb
.lower_bound
+ rc
->srgb
.range_size
- 1)
2767 > MPLS_LABEL_UNRESERVED_MAX
)) {
2768 sbuf_push(log
, indent
, "Invalid label range. Reset SRGB\n");
2769 rc
->srgb
.lower_bound
= 0;
2770 rc
->srgb
.range_size
= 0;
2773 case ISIS_SUBTLV_ALGORITHM
:
2774 /* Only 2 algorithms are supported: SPF & Strict SPF */
2775 stream_get(&rc
->algo
, s
,
2776 length
> SR_ALGORITHM_COUNT
2777 ? SR_ALGORITHM_COUNT
2779 if (length
> SR_ALGORITHM_COUNT
)
2780 stream_forward_getp(
2781 s
, length
- SR_ALGORITHM_COUNT
);
2783 case ISIS_SUBTLV_NODE_MSD
:
2784 msd_type
= stream_getc(s
);
2785 rc
->msd
= stream_getc(s
);
2786 /* Only BMI-MSD type has been defined in RFC 8491 */
2787 if (msd_type
!= MSD_TYPE_BASE_MPLS_IMPOSITION
)
2791 stream_forward_getp(s
, length
);
2794 subtlv_len
= subtlv_len
- length
- 2;
2799 /* Functions related to TLV 10 Authentication */
2800 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
2802 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2803 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2805 rv
->type
= auth
->type
;
2806 rv
->length
= auth
->length
;
2807 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
2808 return (struct isis_item
*)rv
;
2811 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
2812 struct sbuf
*buf
, int indent
)
2814 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2817 sbuf_push(buf
, indent
, "Authentication:\n");
2818 switch (auth
->type
) {
2819 case ISIS_PASSWD_TYPE_CLEARTXT
:
2820 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
2821 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
2823 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2824 for (unsigned int j
= 0; j
< 16; j
++) {
2825 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
,
2826 "%02" PRIx8
, auth
->value
[j
]);
2828 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
2831 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
2836 static void free_item_auth(struct isis_item
*i
)
2838 XFREE(MTYPE_ISIS_TLV
, i
);
2841 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
2843 struct isis_auth
*auth
= (struct isis_auth
*)i
;
2845 if (STREAM_WRITEABLE(s
) < 1)
2847 stream_putc(s
, auth
->type
);
2849 switch (auth
->type
) {
2850 case ISIS_PASSWD_TYPE_CLEARTXT
:
2851 if (STREAM_WRITEABLE(s
) < auth
->length
)
2853 stream_put(s
, auth
->passwd
, auth
->length
);
2855 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2856 if (STREAM_WRITEABLE(s
) < 16)
2858 auth
->offset
= stream_get_endp(s
);
2859 stream_put(s
, NULL
, 16);
2868 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
2869 struct sbuf
*log
, void *dest
, int indent
)
2871 struct isis_tlvs
*tlvs
= dest
;
2873 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
2877 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
2883 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2885 rv
->type
= stream_getc(s
);
2886 rv
->length
= len
- 1;
2888 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
2891 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
2894 XFREE(MTYPE_ISIS_TLV
, rv
);
2898 rv
->offset
= stream_get_getp(s
);
2899 stream_get(rv
->value
, s
, rv
->length
);
2900 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2901 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
2905 /* Functions related to TLV 13 Purge Originator */
2907 static struct isis_purge_originator
*copy_tlv_purge_originator(
2908 struct isis_purge_originator
*poi
)
2913 struct isis_purge_originator
*rv
;
2915 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2916 rv
->sender_set
= poi
->sender_set
;
2917 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
2918 if (poi
->sender_set
)
2919 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
2923 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
2924 struct sbuf
*buf
, int indent
)
2929 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
2930 sbuf_push(buf
, indent
, " Generator: %s\n",
2931 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
2932 if (poi
->sender_set
) {
2933 sbuf_push(buf
, indent
, " Received-From: %s\n",
2934 isis_format_id(poi
->sender
, sizeof(poi
->sender
)));
2938 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
2940 XFREE(MTYPE_ISIS_TLV
, poi
);
2943 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
2949 uint8_t data_len
= 1 + sizeof(poi
->generator
);
2951 if (poi
->sender_set
)
2952 data_len
+= sizeof(poi
->sender
);
2954 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
2957 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
2958 stream_putc(s
, data_len
);
2959 stream_putc(s
, poi
->sender_set
? 2 : 1);
2960 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
2961 if (poi
->sender_set
)
2962 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
2966 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
2967 uint8_t tlv_type
, uint8_t tlv_len
,
2968 struct stream
*s
, struct sbuf
*log
,
2969 void *dest
, int indent
)
2971 struct isis_tlvs
*tlvs
= dest
;
2972 struct isis_purge_originator poi
= {};
2974 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
2976 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %"
2977 PRIu8
")\n", tlv_len
);
2981 uint8_t number_of_ids
= stream_getc(s
);
2983 if (number_of_ids
== 1) {
2984 poi
.sender_set
= false;
2985 } else if (number_of_ids
== 2) {
2986 poi
.sender_set
= true;
2988 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %"
2989 PRIu8
")\n", number_of_ids
);
2993 if (tlv_len
!= 1 + 6 * number_of_ids
) {
2994 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
2998 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
3000 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
3002 if (tlvs
->purge_originator
) {
3003 sbuf_push(log
, indent
,
3004 "WARNING: Purge originator present multiple times, ignoring.\n");
3008 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
3013 /* Functions relating to item TLVs */
3015 static void init_item_list(struct isis_item_list
*items
)
3018 items
->tail
= &items
->head
;
3022 static struct isis_item
*copy_item(enum isis_tlv_context context
,
3023 enum isis_tlv_type type
,
3024 struct isis_item
*item
)
3026 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3028 if (ops
&& ops
->copy_item
)
3029 return ops
->copy_item(item
);
3031 assert(!"Unknown item tlv type!");
3035 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3036 struct isis_item_list
*src
, struct isis_item_list
*dest
)
3038 struct isis_item
*item
;
3040 init_item_list(dest
);
3042 for (item
= src
->head
; item
; item
= item
->next
) {
3043 append_item(dest
, copy_item(context
, type
, item
));
3047 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
3048 enum isis_tlv_type type
, struct isis_item
*i
,
3049 struct sbuf
*buf
, int indent
)
3051 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3053 if (ops
&& ops
->format_item
) {
3054 ops
->format_item(mtid
, i
, buf
, indent
);
3058 assert(!"Unknown item tlv type!");
3061 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
3062 enum isis_tlv_type type
, struct isis_item_list
*items
,
3063 struct sbuf
*buf
, int indent
)
3065 struct isis_item
*i
;
3067 for (i
= items
->head
; i
; i
= i
->next
)
3068 format_item(mtid
, context
, type
, i
, buf
, indent
);
3071 static void free_item(enum isis_tlv_context tlv_context
,
3072 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
3074 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
3076 if (ops
&& ops
->free_item
) {
3077 ops
->free_item(item
);
3081 assert(!"Unknown item tlv type!");
3084 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3085 struct isis_item_list
*items
)
3087 struct isis_item
*item
, *next_item
;
3089 for (item
= items
->head
; item
; item
= next_item
) {
3090 next_item
= item
->next
;
3091 free_item(context
, type
, item
);
3095 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
3096 struct isis_item
*i
, struct stream
*s
,
3097 struct isis_tlvs
**fragment_tlvs
,
3098 const struct pack_order_entry
*pe
, uint16_t mtid
)
3100 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
3102 if (ops
&& ops
->pack_item
) {
3103 return ops
->pack_item(i
, s
);
3106 assert(!"Unknown item tlv type!");
3110 static void add_item_to_fragment(struct isis_item
*i
,
3111 const struct pack_order_entry
*pe
,
3112 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
3114 struct isis_item_list
*l
;
3116 if (pe
->how_to_pack
== ISIS_ITEMS
) {
3117 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
3119 struct isis_mt_item_list
*m
;
3120 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
3121 l
= isis_get_mt_items(m
, mtid
);
3124 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
3127 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
3128 enum isis_tlv_type type
, struct isis_item_list
*items
,
3129 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
3130 const struct pack_order_entry
*pe
,
3131 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3132 struct list
*new_fragment_arg
)
3134 size_t len_pos
, last_len
, len
;
3135 struct isis_item
*item
= NULL
;
3142 if (STREAM_WRITEABLE(s
) < 2)
3145 stream_putc(s
, type
);
3146 len_pos
= stream_get_endp(s
);
3147 stream_putc(s
, 0); /* Put 0 as length for now */
3149 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
3150 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
3151 if (STREAM_WRITEABLE(s
) < 2)
3153 stream_putw(s
, mtid
);
3156 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
3157 if (STREAM_WRITEABLE(s
) < 1)
3159 stream_putc(s
, 0); /* Virtual flag is set to 0 */
3163 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
3164 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
3168 len
= stream_get_endp(s
) - len_pos
- 1;
3170 /* Multiple auths don't go into one TLV, so always break */
3171 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
3176 /* Multiple prefix-sids don't go into one TLV, so always break */
3177 if (type
== ISIS_SUBTLV_PREFIX_SID
3178 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
3179 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
3185 if (!last_len
) /* strange, not a single item fit */
3187 /* drop last tlv, otherwise, its too long */
3188 stream_set_endp(s
, len_pos
+ 1 + last_len
);
3194 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
3199 stream_putc_at(s
, len_pos
, len
);
3208 *fragment_tlvs
= new_fragment(new_fragment_arg
);
3211 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
3213 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
3216 dest
->tail
= &(*dest
->tail
)->next
;
3220 static void delete_item(struct isis_item_list
*dest
, struct isis_item
*del
)
3222 struct isis_item
*item
, *prev
= NULL
, *next
;
3225 if ((dest
== NULL
) || (del
== NULL
))
3229 * TODO: delete is tricky because "dest" is a singly linked list.
3230 * We need to switch a doubly linked list.
3232 for (item
= dest
->head
; item
; item
= next
) {
3233 if (item
->next
== del
) {
3240 prev
->next
= del
->next
;
3241 if (dest
->head
== del
)
3242 dest
->head
= del
->next
;
3243 if ((struct isis_item
*)dest
->tail
== del
) {
3246 dest
->tail
= &(*dest
->tail
)->next
;
3248 dest
->tail
= &dest
->head
;
3253 static struct isis_item
*last_item(struct isis_item_list
*list
)
3255 return container_of(list
->tail
, struct isis_item
, next
);
3258 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
3259 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
3260 struct sbuf
*log
, void *dest
, int indent
)
3262 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
3264 if (ops
&& ops
->unpack_item
)
3265 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
3267 assert(!"Unknown item tlv type!");
3268 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
3272 static int unpack_tlv_with_items(enum isis_tlv_context context
,
3273 uint8_t tlv_type
, uint8_t tlv_len
,
3274 struct stream
*s
, struct sbuf
*log
, void *dest
,
3282 tlv_start
= stream_get_getp(s
);
3285 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
3287 sbuf_push(log
, indent
,
3288 "TLV is too short to contain MTID\n");
3291 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
3293 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
3294 isis_mtid2str(mtid
));
3296 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
3297 mtid
= ISIS_MT_IPV4_UNICAST
;
3300 if (context
== ISIS_CONTEXT_LSP
3301 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
3302 if (tlv_len
- tlv_pos
< 1) {
3303 sbuf_push(log
, indent
,
3304 "TLV is too short for old style reach\n");
3307 stream_forward_getp(s
, 1);
3311 if (context
== ISIS_CONTEXT_LSP
3312 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
3313 struct isis_tlvs
*tlvs
= dest
;
3314 dest
= &tlvs
->oldstyle_ip_reach
;
3315 } else if (context
== ISIS_CONTEXT_LSP
3316 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
3317 struct isis_tlvs
*tlvs
= dest
;
3318 dest
= &tlvs
->oldstyle_ip_reach_ext
;
3321 if (context
== ISIS_CONTEXT_LSP
3322 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
3323 struct isis_tlvs
*tlvs
= dest
;
3324 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
3327 while (tlv_pos
< (size_t)tlv_len
) {
3328 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
3329 log
, dest
, indent
+ 2);
3333 tlv_pos
= stream_get_getp(s
) - tlv_start
;
3339 /* Functions to manipulate mt_item_lists */
3341 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
3342 const struct isis_item_list
*b
)
3344 if (a
->mtid
< b
->mtid
)
3346 if (a
->mtid
> b
->mtid
)
3351 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
3352 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
3354 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
3357 struct isis_item_list
*rv
;
3359 rv
= isis_lookup_mt_items(m
, mtid
);
3361 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
3364 RB_INSERT(isis_mt_item_list
, m
, rv
);
3370 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
3373 struct isis_item_list key
= {.mtid
= mtid
};
3375 return RB_FIND(isis_mt_item_list
, m
, &key
);
3378 static void free_mt_items(enum isis_tlv_context context
,
3379 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
3381 struct isis_item_list
*n
, *nnext
;
3383 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
3384 free_items(context
, type
, n
);
3385 RB_REMOVE(isis_mt_item_list
, m
, n
);
3386 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
3390 static void format_mt_items(enum isis_tlv_context context
,
3391 enum isis_tlv_type type
,
3392 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
3395 struct isis_item_list
*n
;
3397 RB_FOREACH (n
, isis_mt_item_list
, m
) {
3398 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
3402 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
3403 struct isis_mt_item_list
*m
, struct stream
*s
,
3404 struct isis_tlvs
**fragment_tlvs
,
3405 const struct pack_order_entry
*pe
,
3406 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3407 struct list
*new_fragment_arg
)
3409 struct isis_item_list
*n
;
3411 RB_FOREACH (n
, isis_mt_item_list
, m
) {
3414 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
3415 pe
, new_fragment
, new_fragment_arg
);
3423 static void copy_mt_items(enum isis_tlv_context context
,
3424 enum isis_tlv_type type
,
3425 struct isis_mt_item_list
*src
,
3426 struct isis_mt_item_list
*dest
)
3428 struct isis_item_list
*n
;
3430 RB_INIT(isis_mt_item_list
, dest
);
3432 RB_FOREACH (n
, isis_mt_item_list
, src
) {
3433 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
3437 /* Functions related to tlvs in general */
3439 struct isis_tlvs
*isis_alloc_tlvs(void)
3441 struct isis_tlvs
*result
;
3443 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
3445 init_item_list(&result
->isis_auth
);
3446 init_item_list(&result
->area_addresses
);
3447 init_item_list(&result
->mt_router_info
);
3448 init_item_list(&result
->oldstyle_reach
);
3449 init_item_list(&result
->lan_neighbor
);
3450 init_item_list(&result
->lsp_entries
);
3451 init_item_list(&result
->extended_reach
);
3452 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
3453 init_item_list(&result
->oldstyle_ip_reach
);
3454 init_item_list(&result
->oldstyle_ip_reach_ext
);
3455 init_item_list(&result
->ipv4_address
);
3456 init_item_list(&result
->ipv6_address
);
3457 init_item_list(&result
->extended_ip_reach
);
3458 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
3459 init_item_list(&result
->ipv6_reach
);
3460 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
3465 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
3467 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
3469 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
3472 rv
->purge_originator
=
3473 copy_tlv_purge_originator(tlvs
->purge_originator
);
3475 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3476 &tlvs
->area_addresses
, &rv
->area_addresses
);
3478 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3479 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
3481 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
3483 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3484 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
3486 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3487 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
3489 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
3492 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3493 &tlvs
->extended_reach
, &rv
->extended_reach
);
3495 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
3498 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3499 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
3501 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
3502 &rv
->protocols_supported
);
3504 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3505 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
3507 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
3510 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
3513 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
3515 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3516 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
3518 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3519 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
3521 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
3523 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
3526 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3527 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
3529 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
3531 rv
->router_cap
= copy_tlv_router_cap(tlvs
->router_cap
);
3533 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
3538 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
3540 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
3542 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
3545 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, indent
);
3547 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3548 &tlvs
->area_addresses
, buf
, indent
);
3550 if (tlvs
->mt_router_info_empty
) {
3551 sbuf_push(buf
, indent
, "MT Router Info: None\n");
3553 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3554 &tlvs
->mt_router_info
, buf
, indent
);
3557 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3558 &tlvs
->oldstyle_reach
, buf
, indent
);
3560 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3561 &tlvs
->lan_neighbor
, buf
, indent
);
3563 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
3566 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
3567 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
3568 format_tlv_router_cap(tlvs
->router_cap
, buf
, indent
);
3570 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3571 &tlvs
->extended_reach
, buf
, indent
);
3573 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
3576 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3577 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
3579 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3580 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
3582 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
3583 &tlvs
->ipv4_address
, buf
, indent
);
3585 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
3586 &tlvs
->ipv6_address
, buf
, indent
);
3588 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3589 &tlvs
->extended_ip_reach
, buf
, indent
);
3591 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3592 &tlvs
->mt_ip_reach
, buf
, indent
);
3594 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
3597 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3598 &tlvs
->mt_ipv6_reach
, buf
, indent
);
3600 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
3602 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, indent
);
3605 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
3607 static struct sbuf buf
;
3609 if (!sbuf_buf(&buf
))
3610 sbuf_init(&buf
, NULL
, 0);
3613 format_tlvs(tlvs
, &buf
, 0);
3614 return sbuf_buf(&buf
);
3617 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
3622 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
3623 free_tlv_purge_originator(tlvs
->purge_originator
);
3624 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3625 &tlvs
->area_addresses
);
3626 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3627 &tlvs
->mt_router_info
);
3628 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
3629 &tlvs
->oldstyle_reach
);
3630 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
3631 &tlvs
->lan_neighbor
);
3632 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
3633 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
3634 &tlvs
->extended_reach
);
3635 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
3636 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
3637 &tlvs
->oldstyle_ip_reach
);
3638 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
3639 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
3640 &tlvs
->oldstyle_ip_reach_ext
);
3641 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
3642 &tlvs
->ipv4_address
);
3643 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
3644 &tlvs
->ipv6_address
);
3645 free_tlv_te_router_id(tlvs
->te_router_id
);
3646 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
3647 &tlvs
->extended_ip_reach
);
3648 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
3649 &tlvs
->mt_ip_reach
);
3650 free_tlv_dynamic_hostname(tlvs
->hostname
);
3651 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
3652 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
3653 &tlvs
->mt_ipv6_reach
);
3654 free_tlv_threeway_adj(tlvs
->threeway_adj
);
3655 free_tlv_router_cap(tlvs
->router_cap
);
3656 free_tlv_spine_leaf(tlvs
->spine_leaf
);
3658 XFREE(MTYPE_ISIS_TLV
, tlvs
);
3661 static void add_padding(struct stream
*s
)
3663 while (STREAM_WRITEABLE(s
)) {
3664 if (STREAM_WRITEABLE(s
) == 1)
3666 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
3668 if (padding_len
> 255) {
3669 if (padding_len
== 256)
3675 stream_putc(s
, ISIS_TLV_PADDING
);
3676 stream_putc(s
, padding_len
);
3677 stream_put(s
, NULL
, padding_len
);
3681 #define LSP_REM_LIFETIME_OFF 10
3682 #define LSP_CHECKSUM_OFF 24
3683 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
3684 uint16_t *rem_lifetime
)
3686 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
3687 sizeof(*rem_lifetime
));
3688 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
3689 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
3690 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
3693 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
3694 uint16_t rem_lifetime
)
3696 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
3697 sizeof(rem_lifetime
));
3698 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
3701 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
3705 uint16_t checksum
, rem_lifetime
;
3708 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
3710 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
3711 #ifdef CRYPTO_OPENSSL
3712 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
3713 auth
->plength
, STREAM_DATA(s
),
3714 stream_get_endp(s
), NULL
, NULL
);
3716 memcpy(digest
, result
, 16);
3717 #elif CRYPTO_INTERNAL
3718 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
3719 auth
->plength
, digest
);
3721 memcpy(auth
->value
, digest
, 16);
3722 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
3725 restore_auth_md5(s
, checksum
, rem_lifetime
);
3728 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
3730 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
3732 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
3733 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
3734 update_auth_hmac_md5(auth
, s
, is_lsp
);
3738 static int handle_pack_entry(const struct pack_order_entry
*pe
,
3739 struct isis_tlvs
*tlvs
, struct stream
*stream
,
3740 struct isis_tlvs
**fragment_tlvs
,
3741 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3742 struct list
*new_fragment_arg
)
3746 if (pe
->how_to_pack
== ISIS_ITEMS
) {
3747 struct isis_item_list
*l
;
3748 l
= (struct isis_item_list
*)(((char *)tlvs
)
3749 + pe
->what_to_pack
);
3750 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
3751 pe
, new_fragment
, new_fragment_arg
);
3753 struct isis_mt_item_list
*l
;
3754 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
3755 + pe
->what_to_pack
);
3756 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
3757 fragment_tlvs
, pe
, new_fragment
,
3764 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
3765 struct isis_tlvs
*fragment_tlvs
,
3766 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
3767 struct list
*new_fragment_arg
)
3771 /* When fragmenting, don't add auth as it's already accounted for in the
3772 * size we are given. */
3773 if (!fragment_tlvs
) {
3774 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
3775 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
3781 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
3784 if (fragment_tlvs
) {
3785 fragment_tlvs
->purge_originator
=
3786 copy_tlv_purge_originator(tlvs
->purge_originator
);
3789 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
3792 if (fragment_tlvs
) {
3793 copy_tlv_protocols_supported(
3794 &tlvs
->protocols_supported
,
3795 &fragment_tlvs
->protocols_supported
);
3798 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3799 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
3802 if (fragment_tlvs
) {
3803 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
3804 &tlvs
->area_addresses
,
3805 &fragment_tlvs
->area_addresses
);
3809 if (tlvs
->mt_router_info_empty
) {
3810 if (STREAM_WRITEABLE(stream
) < 2)
3812 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
3813 stream_putc(stream
, 0);
3815 fragment_tlvs
->mt_router_info_empty
= true;
3817 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3818 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
3822 if (fragment_tlvs
) {
3823 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
3824 &tlvs
->mt_router_info
,
3825 &fragment_tlvs
->mt_router_info
);
3829 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
3833 fragment_tlvs
->hostname
=
3834 copy_tlv_dynamic_hostname(tlvs
->hostname
);
3836 rv
= pack_tlv_router_cap(tlvs
->router_cap
, stream
);
3839 if (fragment_tlvs
) {
3840 fragment_tlvs
->router_cap
=
3841 copy_tlv_router_cap(tlvs
->router_cap
);
3844 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
3847 if (fragment_tlvs
) {
3848 fragment_tlvs
->te_router_id
=
3849 copy_tlv_te_router_id(tlvs
->te_router_id
);
3852 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
3855 if (fragment_tlvs
) {
3856 fragment_tlvs
->threeway_adj
=
3857 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
3860 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
3863 if (fragment_tlvs
) {
3864 fragment_tlvs
->spine_leaf
=
3865 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
3868 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
3870 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
3871 fragment_tlvs
? &fragment_tlvs
: NULL
,
3872 new_fragment
, new_fragment_arg
);
3881 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
3882 size_t len_pointer
, bool pad
, bool is_lsp
)
3886 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
3891 add_padding(stream
);
3893 if (len_pointer
!= (size_t)-1) {
3894 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
3897 update_auth(tlvs
, stream
, is_lsp
);
3902 static struct isis_tlvs
*new_fragment(struct list
*l
)
3904 struct isis_tlvs
*rv
= isis_alloc_tlvs();
3906 listnode_add(l
, rv
);
3910 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
3912 struct stream
*dummy_stream
= stream_new(size
);
3913 struct list
*rv
= list_new();
3914 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
3916 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
3917 struct listnode
*node
;
3918 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
3919 isis_free_tlvs(fragment_tlvs
);
3923 stream_free(dummy_stream
);
3927 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
3928 uint8_t tlv_len
, struct stream
*s
,
3929 struct sbuf
*log
, int indent
)
3931 stream_forward_getp(s
, tlv_len
);
3932 sbuf_push(log
, indent
,
3933 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
3938 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
3939 struct stream
*stream
, struct sbuf
*log
, void *dest
,
3940 int indent
, bool *unpacked_known_tlvs
)
3942 uint8_t tlv_type
, tlv_len
;
3943 const struct tlv_ops
*ops
;
3945 sbuf_push(log
, indent
, "Unpacking TLV...\n");
3947 if (avail_len
< 2) {
3950 "Available data %zu too short to contain a TLV header.\n",
3955 tlv_type
= stream_getc(stream
);
3956 tlv_len
= stream_getc(stream
);
3958 sbuf_push(log
, indent
+ 2,
3959 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
3962 if (avail_len
< ((size_t)tlv_len
) + 2) {
3963 sbuf_push(log
, indent
+ 2,
3964 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
3965 avail_len
- 2, tlv_len
);
3969 ops
= tlv_table
[context
][tlv_type
];
3970 if (ops
&& ops
->unpack
) {
3971 if (unpacked_known_tlvs
)
3972 *unpacked_known_tlvs
= true;
3973 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
3977 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
3981 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
3982 struct stream
*stream
, struct sbuf
*log
, void *dest
,
3983 int indent
, bool *unpacked_known_tlvs
)
3986 size_t tlv_start
, tlv_pos
;
3988 tlv_start
= stream_get_getp(stream
);
3991 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
3992 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
3994 while (tlv_pos
< avail_len
) {
3995 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
3996 indent
+ 2, unpacked_known_tlvs
);
4000 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
4006 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
4007 struct isis_tlvs
**dest
, const char **log
)
4009 static struct sbuf logbuf
;
4012 struct isis_tlvs
*result
;
4014 if (!sbuf_buf(&logbuf
))
4015 sbuf_init(&logbuf
, NULL
, 0);
4017 sbuf_reset(&logbuf
);
4018 if (avail_len
> STREAM_READABLE(stream
)) {
4019 sbuf_push(&logbuf
, indent
,
4020 "Stream doesn't contain sufficient data. "
4021 "Claimed %zu, available %zu\n",
4022 avail_len
, STREAM_READABLE(stream
));
4026 result
= isis_alloc_tlvs();
4027 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
4030 *log
= sbuf_buf(&logbuf
);
4036 #define TLV_OPS(_name_, _desc_) \
4037 static const struct tlv_ops tlv_##_name_##_ops = { \
4038 .name = _desc_, .unpack = unpack_tlv_##_name_, \
4041 #define ITEM_TLV_OPS(_name_, _desc_) \
4042 static const struct tlv_ops tlv_##_name_##_ops = { \
4044 .unpack = unpack_tlv_with_items, \
4046 .pack_item = pack_item_##_name_, \
4047 .free_item = free_item_##_name_, \
4048 .unpack_item = unpack_item_##_name_, \
4049 .format_item = format_item_##_name_, \
4050 .copy_item = copy_item_##_name_}
4052 #define SUBTLV_OPS(_name_, _desc_) \
4053 static const struct tlv_ops subtlv_##_name_##_ops = { \
4054 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
4057 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
4058 ITEM_TLV_OPS(_name_, _desc_)
4060 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
4061 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
4062 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
4063 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
4064 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
4065 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
4066 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
4067 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
4068 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
4069 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
4070 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
4071 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
4072 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
4073 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
4074 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
4075 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
4076 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
4077 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
4078 TLV_OPS(router_cap
, "TLV 242 Router Capability");
4080 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
4081 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
4083 static const struct tlv_ops
*const tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
4084 [ISIS_CONTEXT_LSP
] = {
4085 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
4086 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
4087 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
4088 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
4089 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
4090 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
4091 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
4092 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
4093 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
4094 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
4095 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
4096 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
4097 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
4098 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
4099 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
4100 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
4101 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
4102 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
4103 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
4104 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
4105 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
4106 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
4107 [ISIS_TLV_ROUTER_CAPABILITY
] = &tlv_router_cap_ops
,
4109 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
4110 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
4111 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
4113 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
4114 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
4115 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
4119 /* Accessor functions */
4121 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
4123 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
4124 init_item_list(&tlvs
->isis_auth
);
4126 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
4129 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
4131 auth
->type
= passwd
->type
;
4133 auth
->plength
= passwd
->len
;
4134 memcpy(auth
->passwd
, passwd
->passwd
,
4135 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
4137 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
4138 auth
->length
= passwd
->len
;
4139 memcpy(auth
->value
, passwd
->passwd
,
4140 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
4143 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
4146 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
4147 struct list
*addresses
)
4149 struct listnode
*node
;
4150 struct area_addr
*area_addr
;
4152 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
4153 struct isis_area_address
*a
=
4154 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4156 a
->len
= area_addr
->addr_len
;
4157 memcpy(a
->addr
, area_addr
->area_addr
, 20);
4158 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
4162 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
4164 struct listnode
*node
;
4167 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
4168 struct isis_lan_neighbor
*n
=
4169 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
4171 memcpy(n
->mac
, snpa
, 6);
4172 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
4176 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
4177 struct nlpids
*nlpids
)
4179 tlvs
->protocols_supported
.count
= nlpids
->count
;
4180 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
4181 if (nlpids
->count
) {
4182 tlvs
->protocols_supported
.protocols
=
4183 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
4184 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
4187 tlvs
->protocols_supported
.protocols
= NULL
;
4191 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4192 bool overload
, bool attached
)
4194 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
4196 i
->overload
= overload
;
4197 i
->attached
= attached
;
4199 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
4202 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
4204 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4206 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
4210 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
4211 struct list
*addresses
)
4213 struct listnode
*node
;
4214 struct prefix_ipv4
*ip_addr
;
4215 unsigned int addr_count
= 0;
4217 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
4218 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
4220 if (addr_count
>= 63)
4225 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
4226 struct list
*addresses
)
4228 struct listnode
*node
;
4229 struct prefix_ipv6
*ip_addr
;
4230 unsigned int addr_count
= 0;
4232 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
4233 if (addr_count
>= 15)
4236 struct isis_ipv6_address
*a
=
4237 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
4239 a
->addr
= ip_addr
->prefix
;
4240 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
4245 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
4246 struct stream
*stream
,
4247 struct isis_auth
*auth
, bool is_lsp
);
4249 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
4250 struct stream
*stream
,
4251 struct isis_auth
*auth
, bool is_lsp
)
4253 return (auth
->length
== passwd
->len
4254 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
4257 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
4258 struct stream
*stream
,
4259 struct isis_auth
*auth
, bool is_lsp
)
4263 uint16_t rem_lifetime
;
4266 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
4268 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
4269 #ifdef CRYPTO_OPENSSL
4270 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
4271 passwd
->len
, STREAM_DATA(stream
),
4272 stream_get_endp(stream
), NULL
, NULL
);
4274 memcpy(digest
, result
, 16);
4275 #elif CRYPTO_INTERNAL
4276 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
4277 passwd
->len
, digest
);
4279 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
4281 bool rv
= !memcmp(digest
, auth
->value
, 16);
4284 restore_auth_md5(stream
, checksum
, rem_lifetime
);
4289 static const auth_validator_func auth_validators
[] = {
4290 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
4291 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
4294 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
4295 struct stream
*stream
, bool is_lsp
)
4297 /* If no auth is set, always pass authentication */
4299 return ISIS_AUTH_OK
;
4301 /* If we don't known how to validate the auth, return invalid */
4302 if (passwd
->type
>= array_size(auth_validators
)
4303 || !auth_validators
[passwd
->type
])
4304 return ISIS_AUTH_NO_VALIDATOR
;
4306 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
4307 struct isis_auth
*auth
;
4308 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
4309 if (auth
->type
== passwd
->type
)
4313 /* If matching auth TLV could not be found, return invalid */
4315 return ISIS_AUTH_TYPE_FAILURE
;
4318 /* Perform validation and return result */
4319 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
4320 return ISIS_AUTH_OK
;
4322 return ISIS_AUTH_FAILURE
;
4325 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
4326 struct list
*addresses
)
4328 struct isis_area_address
*addr_head
;
4330 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
4331 for (struct isis_area_address
*addr
= addr_head
; addr
;
4332 addr
= addr
->next
) {
4333 struct listnode
*node
;
4334 struct area_addr
*a
;
4336 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
4337 if (a
->addr_len
== addr
->len
4338 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
4346 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
4347 struct isis_adjacency
*adj
,
4350 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
4352 adj
->area_address_count
= tlvs
->area_addresses
.count
;
4353 adj
->area_addresses
= XREALLOC(
4354 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
4355 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
4358 struct isis_area_address
*addr
= NULL
;
4359 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
4361 addr
= (struct isis_area_address
*)
4362 tlvs
->area_addresses
.head
;
4366 if (adj
->area_addresses
[i
].addr_len
== addr
->len
4367 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
4373 adj
->area_addresses
[i
].addr_len
= addr
->len
;
4374 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
4378 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
4379 struct isis_adjacency
*adj
,
4382 bool ipv4_supported
= false, ipv6_supported
= false;
4384 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
4385 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
4386 ipv4_supported
= true;
4387 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
4388 ipv6_supported
= true;
4391 struct nlpids reduced
= {};
4393 if (ipv4_supported
&& ipv6_supported
) {
4395 reduced
.nlpids
[0] = NLPID_IP
;
4396 reduced
.nlpids
[1] = NLPID_IPV6
;
4397 } else if (ipv4_supported
) {
4399 reduced
.nlpids
[0] = NLPID_IP
;
4400 } else if (ipv6_supported
) {
4402 reduced
.nlpids
[0] = NLPID_IPV6
;
4407 if (adj
->nlpids
.count
== reduced
.count
4408 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
4412 adj
->nlpids
.count
= reduced
.count
;
4413 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
4416 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
4417 struct isis_adjacency
*adj
,
4420 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
4422 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
4423 adj
->ipv4_addresses
= XREALLOC(
4424 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
4425 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
4428 struct isis_ipv4_address
*addr
= NULL
;
4429 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
4431 addr
= (struct isis_ipv4_address
*)
4432 tlvs
->ipv4_address
.head
;
4436 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
4437 sizeof(addr
->addr
)))
4441 adj
->ipv4_addresses
[i
] = addr
->addr
;
4445 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
4446 struct isis_adjacency
*adj
,
4449 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
4451 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
4452 adj
->ipv6_addresses
= XREALLOC(
4453 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
4454 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
4457 struct isis_ipv6_address
*addr
= NULL
;
4458 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
4460 addr
= (struct isis_ipv6_address
*)
4461 tlvs
->ipv6_address
.head
;
4465 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
4466 sizeof(addr
->addr
)))
4470 adj
->ipv6_addresses
[i
] = addr
->addr
;
4474 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
4479 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
4480 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
4481 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
4482 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
4485 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
4487 struct isis_lan_neighbor
*ne_head
;
4489 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
4490 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
4491 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
4498 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
4500 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
4502 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
4503 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
4504 entry
->checksum
= lsp
->hdr
.checksum
;
4505 entry
->seqno
= lsp
->hdr
.seqno
;
4508 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
4511 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
4512 uint8_t *stop_id
, uint16_t num_lsps
,
4513 struct lspdb_head
*head
,
4514 struct isis_lsp
**last_lsp
)
4516 struct isis_lsp searchfor
;
4517 struct isis_lsp
*first
, *lsp
;
4519 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
4520 first
= lspdb_find_gteq(head
, &searchfor
);
4524 frr_each_from (lspdb
, head
, lsp
, first
) {
4525 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
4526 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
4529 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
4534 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
4535 const char *hostname
)
4537 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
4539 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
4542 /* Set Router Capability TLV parameters */
4543 void isis_tlvs_set_router_capability(struct isis_tlvs
*tlvs
,
4544 const struct isis_router_cap
*cap
)
4546 XFREE(MTYPE_ISIS_TLV
, tlvs
->router_cap
);
4550 tlvs
->router_cap
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->router_cap
));
4551 *tlvs
->router_cap
= *cap
;
4554 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
4555 const struct in_addr
*id
)
4557 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
4560 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
4561 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
4564 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
4565 struct prefix_ipv4
*dest
, uint8_t metric
)
4567 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4570 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4571 apply_mask_ipv4(&r
->prefix
);
4572 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
4575 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs
*exts
,
4576 struct isis_adj_sid
*adj
)
4578 append_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
4579 SET_SUBTLV(exts
, EXT_ADJ_SID
);
4582 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs
*exts
,
4583 struct isis_adj_sid
*adj
)
4585 delete_item(&exts
->adj_sid
, (struct isis_item
*)adj
);
4586 XFREE(MTYPE_ISIS_SUBTLV
, adj
);
4587 if (exts
->adj_sid
.count
== 0)
4588 UNSET_SUBTLV(exts
, EXT_ADJ_SID
);
4591 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
4592 struct isis_lan_adj_sid
*lan
)
4594 append_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
4595 SET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
4598 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs
*exts
,
4599 struct isis_lan_adj_sid
*lan
)
4601 delete_item(&exts
->lan_sid
, (struct isis_item
*)lan
);
4602 XFREE(MTYPE_ISIS_SUBTLV
, lan
);
4603 if (exts
->lan_sid
.count
== 0)
4604 UNSET_SUBTLV(exts
, EXT_LAN_ADJ_SID
);
4607 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
4608 struct prefix_ipv4
*dest
, uint32_t metric
)
4610 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4613 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4614 apply_mask_ipv4(&r
->prefix
);
4615 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
4618 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4619 struct prefix_ipv6
*dest
, uint32_t metric
)
4621 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4624 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
4625 apply_mask_ipv6(&r
->prefix
);
4627 struct isis_item_list
*l
;
4628 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
4630 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
4631 append_item(l
, (struct isis_item
*)r
);
4634 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4635 struct prefix_ipv6
*dest
,
4636 struct prefix_ipv6
*src
,
4639 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
);
4640 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
4643 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
4644 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
4645 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
4646 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
4649 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
4652 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4655 memcpy(r
->id
, id
, sizeof(r
->id
));
4656 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
4659 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
4660 uint8_t *id
, uint32_t metric
,
4661 struct isis_ext_subtlvs
*exts
)
4663 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
4665 memcpy(r
->id
, id
, sizeof(r
->id
));
4668 r
->subtlvs
= copy_item_ext_subtlvs(exts
, mtid
);
4670 struct isis_item_list
*l
;
4671 if (mtid
== ISIS_MT_IPV4_UNICAST
)
4672 l
= &tlvs
->extended_reach
;
4674 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
4675 append_item(l
, (struct isis_item
*)r
);
4678 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
4679 enum isis_threeway_state state
,
4680 uint32_t local_circuit_id
,
4681 const uint8_t *neighbor_id
,
4682 uint32_t neighbor_circuit_id
)
4684 assert(!tlvs
->threeway_adj
);
4686 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
4687 tlvs
->threeway_adj
->state
= state
;
4688 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
4691 tlvs
->threeway_adj
->neighbor_set
= true;
4692 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
4693 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
4697 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
4698 bool has_tier
, bool is_leaf
, bool is_spine
,
4701 assert(!tlvs
->spine_leaf
);
4703 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
4706 tlvs
->spine_leaf
->tier
= tier
;
4709 tlvs
->spine_leaf
->has_tier
= has_tier
;
4710 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
4711 tlvs
->spine_leaf
->is_spine
= is_spine
;
4712 tlvs
->spine_leaf
->is_backup
= is_backup
;
4715 struct isis_mt_router_info
*
4716 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
4718 if (tlvs
->mt_router_info_empty
)
4721 struct isis_mt_router_info
*rv
;
4722 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
4724 if (rv
->mtid
== mtid
)
4731 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
4732 const uint8_t *generator
,
4733 const uint8_t *sender
)
4735 assert(!tlvs
->purge_originator
);
4737 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
4738 sizeof(*tlvs
->purge_originator
));
4739 memcpy(tlvs
->purge_originator
->generator
, generator
,
4740 sizeof(tlvs
->purge_originator
->generator
));
4742 tlvs
->purge_originator
->sender_set
= true;
4743 memcpy(tlvs
->purge_originator
->sender
, sender
,
4744 sizeof(tlvs
->purge_originator
->sender
));