]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_tlvs.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / isisd / isis_tlvs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS TLV Serializer/Deserializer
4 *
5 * Copyright (C) 2015,2017 Christian Franke
6 *
7 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
8 */
9
10 #include <zebra.h>
11 #include <json-c/json_object.h>
12
13 #ifdef CRYPTO_INTERNAL
14 #include "md5.h"
15 #endif
16 #include "memory.h"
17 #include "stream.h"
18 #include "sbuf.h"
19 #include "network.h"
20
21 #include "isisd/isisd.h"
22 #include "isisd/isis_tlvs.h"
23 #include "isisd/isis_common.h"
24 #include "isisd/isis_mt.h"
25 #include "isisd/isis_misc.h"
26 #include "isisd/isis_adjacency.h"
27 #include "isisd/isis_circuit.h"
28 #include "isisd/isis_pdu.h"
29 #include "isisd/isis_lsp.h"
30 #include "isisd/isis_te.h"
31 #include "isisd/isis_sr.h"
32 #include "isisd/isis_flex_algo.h"
33
34 #define TLV_SIZE_MISMATCH(log, indent, target) \
35 sbuf_push(log, indent, \
36 "TLV size does not match expected size for " target "!\n")
37
38 DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs");
39 DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs");
40 DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBSUBTLV, "ISIS Sub-Sub-TLVs");
41 DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists");
42
43 typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
44 uint8_t tlv_len, struct stream *s,
45 struct sbuf *log, void *dest, int indent);
46 typedef int (*pack_item_func)(struct isis_item *item, struct stream *s,
47 size_t *min_length);
48 typedef void (*free_item_func)(struct isis_item *i);
49 typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
50 struct sbuf *log, void *dest, int indent);
51 typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i,
52 struct sbuf *buf, struct json_object *json,
53 int indent);
54 typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
55
56 struct tlv_ops {
57 const char *name;
58 unpack_tlv_func unpack;
59
60 pack_item_func pack_item;
61 free_item_func free_item;
62 unpack_item_func unpack_item;
63 format_item_func format_item;
64 copy_item_func copy_item;
65 };
66
67 enum how_to_pack {
68 ISIS_ITEMS,
69 ISIS_MT_ITEMS,
70 };
71
72 struct pack_order_entry {
73 enum isis_tlv_context context;
74 enum isis_tlv_type type;
75 enum how_to_pack how_to_pack;
76 size_t what_to_pack;
77 };
78 #define PACK_ENTRY(t, h, w) \
79 { \
80 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
81 .how_to_pack = (h), \
82 .what_to_pack = offsetof(struct isis_tlvs, w), \
83 }
84
85 static const struct pack_order_entry pack_order[] = {
86 PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach),
87 PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor),
88 PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries),
89 PACK_ENTRY(EXTENDED_REACH, ISIS_ITEMS, extended_reach),
90 PACK_ENTRY(MT_REACH, ISIS_MT_ITEMS, mt_reach),
91 PACK_ENTRY(OLDSTYLE_IP_REACH, ISIS_ITEMS, oldstyle_ip_reach),
92 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext),
93 PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address),
94 PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address),
95 PACK_ENTRY(GLOBAL_IPV6_ADDRESS, ISIS_ITEMS, global_ipv6_address),
96 PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
97 PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
98 PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
99 PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)
100 };
101
102 /* This is a forward definition. The table is actually initialized
103 * in at the bottom. */
104 static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
105
106 /* End of _ops forward definition. */
107
108 /* Prototypes */
109 static void append_item(struct isis_item_list *dest, struct isis_item *item);
110 static void init_item_list(struct isis_item_list *items);
111
112 /* For tests/isisd, TLV text requires ipv4-unicast instead of standard */
113 static const char *isis_mtid2str_fake(uint16_t mtid)
114 {
115 if (mtid == ISIS_MT_STANDARD)
116 return "ipv4-unicast";
117 return isis_mtid2str(mtid);
118 }
119
120 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
121 struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
122 {
123 struct isis_ext_subtlvs *ext;
124
125 ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs));
126 init_item_list(&ext->adj_sid);
127 init_item_list(&ext->lan_sid);
128 ext->aslas = list_new();
129
130 admin_group_init(&ext->ext_admin_group);
131
132 return ext;
133 }
134
135 void isis_del_ext_subtlvs(struct isis_ext_subtlvs *ext)
136 {
137 struct isis_item *item, *next_item;
138 struct listnode *node, *nnode;
139 struct isis_asla_subtlvs *asla;
140
141 if (!ext)
142 return;
143
144 /* First, free Adj SID and LAN Adj SID list if needed */
145 for (item = ext->adj_sid.head; item; item = next_item) {
146 next_item = item->next;
147 XFREE(MTYPE_ISIS_SUBTLV, item);
148 }
149 for (item = ext->lan_sid.head; item; item = next_item) {
150 next_item = item->next;
151 XFREE(MTYPE_ISIS_SUBTLV, item);
152 }
153
154 for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla))
155 isis_tlvs_del_asla_flex_algo(ext, asla);
156
157 list_delete(&ext->aslas);
158
159 admin_group_term(&ext->ext_admin_group);
160
161 XFREE(MTYPE_ISIS_SUBTLV, ext);
162 }
163
164 /*
165 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
166 * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
167 * that MT is disabled i.e. IS-IS is working with a Single Topology.
168 */
169 static struct isis_ext_subtlvs *
170 copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid)
171 {
172 struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
173 struct isis_adj_sid *adj;
174 struct isis_lan_adj_sid *lan;
175 struct listnode *node, *nnode;
176 struct isis_asla_subtlvs *new_asla, *asla;
177
178 /* Copy the Extended IS main part */
179 memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
180
181 /* Disable IPv4 / IPv6 advertisement in function of MTID */
182 if (mtid == ISIS_MT_IPV4_UNICAST) {
183 UNSET_SUBTLV(rv, EXT_LOCAL_ADDR6);
184 UNSET_SUBTLV(rv, EXT_NEIGH_ADDR6);
185 }
186 if (mtid == ISIS_MT_IPV6_UNICAST) {
187 UNSET_SUBTLV(rv, EXT_LOCAL_ADDR);
188 UNSET_SUBTLV(rv, EXT_NEIGH_ADDR);
189 }
190
191 /* Prepare (LAN)-Adjacency Segment Routing ID*/
192 init_item_list(&rv->adj_sid);
193 init_item_list(&rv->lan_sid);
194
195 UNSET_SUBTLV(rv, EXT_ADJ_SID);
196 UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID);
197
198 /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
199 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL;
200 adj = adj->next) {
201 if ((mtid != ISIS_MT_DISABLE)
202 && (((mtid == ISIS_MT_IPV4_UNICAST)
203 && (adj->family != AF_INET))
204 || ((mtid == ISIS_MT_IPV6_UNICAST)
205 && (adj->family != AF_INET6))))
206 continue;
207
208 struct isis_adj_sid *new;
209
210 new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid));
211 new->family = adj->family;
212 new->flags = adj->flags;
213 new->weight = adj->weight;
214 new->sid = adj->sid;
215 append_item(&rv->adj_sid, (struct isis_item *)new);
216 SET_SUBTLV(rv, EXT_ADJ_SID);
217 }
218
219 /* Same for LAN Adj SID */
220 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL;
221 lan = lan->next) {
222 if ((mtid != ISIS_MT_DISABLE)
223 && (((mtid == ISIS_MT_IPV4_UNICAST)
224 && (lan->family != AF_INET))
225 || ((mtid == ISIS_MT_IPV6_UNICAST)
226 && (lan->family != AF_INET6))))
227 continue;
228
229 struct isis_lan_adj_sid *new;
230
231 new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid));
232 new->family = lan->family;
233 new->flags = lan->flags;
234 new->weight = lan->weight;
235 memcpy(new->neighbor_id, lan->neighbor_id, 6);
236 new->sid = lan->sid;
237 append_item(&rv->lan_sid, (struct isis_item *)new);
238 SET_SUBTLV(rv, EXT_LAN_ADJ_SID);
239 }
240
241 rv->aslas = list_new();
242
243 for (ALL_LIST_ELEMENTS(exts->aslas, node, nnode, asla)) {
244 new_asla = XCALLOC(MTYPE_ISIS_SUBTLV,
245 sizeof(struct isis_asla_subtlvs));
246 memcpy(new_asla, asla, sizeof(struct isis_asla_subtlvs));
247
248 new_asla->ext_admin_group.bitmap.data = NULL;
249 admin_group_copy(&new_asla->ext_admin_group,
250 &asla->ext_admin_group);
251
252 listnode_add(rv->aslas, new_asla);
253 }
254
255 rv->ext_admin_group.bitmap.data = NULL;
256 admin_group_copy(&rv->ext_admin_group, &exts->ext_admin_group);
257
258 return rv;
259 }
260
261 static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla,
262 struct sbuf *buf, int indent)
263 {
264 char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE];
265
266 sbuf_push(buf, indent, "Application Specific Link Attributes:\n");
267 sbuf_push(buf, indent + 2,
268 "L flag: %u, SA-Length: %u, UDA-Length: %u\n", asla->legacy,
269 asla->standard_apps_length, asla->user_def_apps_length);
270 sbuf_push(buf, indent + 2, "Standard Applications: 0x%02x",
271 asla->standard_apps);
272 if (asla->standard_apps) {
273 uint8_t bit = asla->standard_apps;
274 if (bit & ISIS_SABM_FLAG_R)
275 sbuf_push(buf, 0, " RSVP-TE");
276 if (bit & ISIS_SABM_FLAG_S)
277 sbuf_push(buf, 0, " SR-Policy");
278 if (bit & ISIS_SABM_FLAG_L)
279 sbuf_push(buf, 0, " Loop-Free-Alternate");
280 if (bit & ISIS_SABM_FLAG_X)
281 sbuf_push(buf, 0, " Flex-Algo");
282 }
283 sbuf_push(buf, 0, "\n");
284 sbuf_push(buf, indent + 2, "User Defined Applications: 0x%02x\n",
285 asla->user_def_apps);
286
287 if (IS_SUBTLV(asla, EXT_ADM_GRP)) {
288 sbuf_push(buf, indent + 2, "Admin Group: 0x%08x\n",
289 asla->admin_group);
290 sbuf_push(buf, indent + 4, "Bit positions: %s\n",
291 admin_group_standard_print(
292 admin_group_buf,
293 indent + 2 + strlen("Admin Group: "),
294 asla->admin_group));
295 }
296 if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) &&
297 admin_group_nb_words(&asla->ext_admin_group) != 0) {
298 sbuf_push(buf, indent + 2, "Ext Admin Group: %s\n",
299 admin_group_string(
300 admin_group_buf, ADMIN_GROUP_PRINT_MAX_SIZE,
301 indent + 2 + strlen("Ext Admin Group: "),
302 &asla->ext_admin_group));
303 admin_group_print(admin_group_buf,
304 indent + 2 + strlen("Ext Admin Group: "),
305 &asla->ext_admin_group);
306 if (admin_group_buf[0] != '\0' &&
307 (buf->pos + strlen(admin_group_buf) +
308 SBUF_DEFAULT_SIZE / 2) < buf->size)
309 sbuf_push(buf, indent + 4, "Bit positions: %s\n",
310 admin_group_buf);
311 }
312 if (IS_SUBTLV(asla, EXT_MAX_BW))
313 sbuf_push(buf, indent + 2,
314 "Maximum Bandwidth: %g (Bytes/sec)\n", asla->max_bw);
315 if (IS_SUBTLV(asla, EXT_MAX_RSV_BW))
316 sbuf_push(buf, indent + 2,
317 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
318 asla->max_rsv_bw);
319 if (IS_SUBTLV(asla, EXT_UNRSV_BW)) {
320 sbuf_push(buf, indent + 2, "Unreserved Bandwidth:\n");
321 for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
322 sbuf_push(
323 buf, indent + 2,
324 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
325 j, asla->unrsv_bw[j], j + 1,
326 asla->unrsv_bw[j + 1]);
327 }
328 }
329 if (IS_SUBTLV(asla, EXT_TE_METRIC))
330 sbuf_push(buf, indent + 2, "Traffic Engineering Metric: %u\n",
331 asla->te_metric);
332 /* Extended metrics */
333 if (IS_SUBTLV(asla, EXT_DELAY))
334 sbuf_push(buf, indent + 2,
335 "%s Average Link Delay: %u (micro-sec)\n",
336 IS_ANORMAL(asla->delay) ? "Anomalous" : "Normal",
337 asla->delay);
338 if (IS_SUBTLV(asla, EXT_MM_DELAY)) {
339 sbuf_push(buf, indent + 2,
340 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
341 IS_ANORMAL(asla->min_delay) ? "Anomalous" : "Normal",
342 asla->min_delay & TE_EXT_MASK,
343 asla->max_delay & TE_EXT_MASK);
344 }
345 if (IS_SUBTLV(asla, EXT_DELAY_VAR)) {
346 sbuf_push(buf, indent + 2, "Delay Variation: %u (micro-sec)\n",
347 asla->delay_var & TE_EXT_MASK);
348 }
349 if (IS_SUBTLV(asla, EXT_PKT_LOSS))
350 sbuf_push(buf, indent + 2, "%s Link Packet Loss: %g (%%)\n",
351 IS_ANORMAL(asla->pkt_loss) ? "Anomalous" : "Normal",
352 (float)((asla->pkt_loss & TE_EXT_MASK) *
353 LOSS_PRECISION));
354 if (IS_SUBTLV(asla, EXT_RES_BW))
355 sbuf_push(buf, indent + 2,
356 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
357 asla->res_bw);
358 if (IS_SUBTLV(asla, EXT_AVA_BW))
359 sbuf_push(buf, indent + 2,
360 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
361 asla->ava_bw);
362 if (IS_SUBTLV(asla, EXT_USE_BW))
363 sbuf_push(buf, indent + 2,
364 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
365 asla->use_bw);
366 }
367
368 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
369 static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
370 struct sbuf *buf, struct json_object *json,
371 int indent, uint16_t mtid)
372 {
373 char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE];
374 char aux_buf[255];
375 char cnt_buf[255];
376 struct isis_asla_subtlvs *asla;
377 struct listnode *node;
378
379 /* Standard metrics */
380 if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
381 if (json) {
382 snprintfrr(aux_buf, sizeof(aux_buf), "0x%x",
383 exts->adm_group);
384 json_object_string_add(json, "adm-group", aux_buf);
385 } else {
386 sbuf_push(buf, indent, "Admin Group: 0x%08x\n",
387 exts->adm_group);
388 sbuf_push(buf, indent + 2, "Bit positions: %s\n",
389 admin_group_standard_print(
390 admin_group_buf,
391 indent + strlen("Admin Group: "),
392 exts->adm_group));
393 }
394 }
395
396 if (IS_SUBTLV(exts, EXT_EXTEND_ADM_GRP) &&
397 admin_group_nb_words(&exts->ext_admin_group) != 0) {
398 if (!json) {
399 /* TODO json after fix show database detail json */
400 sbuf_push(buf, indent, "Ext Admin Group: %s\n",
401 admin_group_string(
402 admin_group_buf,
403 ADMIN_GROUP_PRINT_MAX_SIZE,
404 indent + strlen("Ext Admin Group: "),
405 &exts->ext_admin_group));
406 admin_group_print(admin_group_buf,
407 indent + strlen("Ext Admin Group: "),
408 &exts->ext_admin_group);
409 if (admin_group_buf[0] != '\0' &&
410 (buf->pos + strlen(admin_group_buf) +
411 SBUF_DEFAULT_SIZE / 2) < buf->size)
412 sbuf_push(buf, indent + 2,
413 "Bit positions: %s\n",
414 admin_group_buf);
415 }
416 }
417 if (IS_SUBTLV(exts, EXT_LLRI)) {
418 if (json) {
419 json_object_int_add(json, "link-local-id",
420 exts->local_llri);
421 json_object_int_add(json, "link-remote-id",
422 exts->remote_llri);
423 } else {
424 sbuf_push(buf, indent, "Link Local ID: %u\n",
425 exts->local_llri);
426 sbuf_push(buf, indent, "Link Remote ID: %u\n",
427 exts->remote_llri);
428 }
429 }
430 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
431 if (json) {
432 inet_ntop(AF_INET, &exts->local_addr, aux_buf,
433 sizeof(aux_buf));
434 json_object_string_add(json, "local-iface-ip", aux_buf);
435 } else
436 sbuf_push(buf, indent,
437 "Local Interface IP Address(es): %pI4\n",
438 &exts->local_addr);
439 }
440 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
441 if (json) {
442 inet_ntop(AF_INET, &exts->neigh_addr, aux_buf,
443 sizeof(aux_buf));
444 json_object_string_add(json, "remote-iface-ip",
445 aux_buf);
446 } else
447 sbuf_push(buf, indent,
448 "Remote Interface IP Address(es): %pI4\n",
449 &exts->neigh_addr);
450 }
451 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
452 if (json) {
453 inet_ntop(AF_INET6, &exts->local_addr6, aux_buf,
454 sizeof(aux_buf));
455 json_object_string_add(json, "local-iface-ipv6",
456 aux_buf);
457 } else
458 sbuf_push(buf, indent,
459 "Local Interface IPv6 Address(es): %pI6\n",
460 &exts->local_addr6);
461 }
462 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
463 if (json) {
464 inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf,
465 sizeof(aux_buf));
466 json_object_string_add(json, "remote-iface-ipv6",
467 aux_buf);
468 } else
469 sbuf_push(buf, indent,
470 "Remote Interface IPv6 Address(es): %pI6\n",
471 &exts->neigh_addr6);
472 }
473 if (IS_SUBTLV(exts, EXT_MAX_BW)) {
474 if (json) {
475 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
476 exts->max_bw);
477 json_object_string_add(json, "max-bandwith-bytes-sec",
478 aux_buf);
479 } else
480 sbuf_push(buf, indent,
481 "Maximum Bandwidth: %g (Bytes/sec)\n",
482 exts->max_bw);
483 }
484 if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
485 if (json) {
486 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
487 exts->max_rsv_bw);
488 json_object_string_add(
489 json, "max-res-bandwith-bytes-sec", aux_buf);
490 } else
491 sbuf_push(
492 buf, indent,
493 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
494 exts->max_rsv_bw);
495 }
496 if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
497 if (json) {
498 struct json_object *unrsv_json;
499 unrsv_json = json_object_new_object();
500 json_object_object_add(json, "unrsv-bandwith-bytes-sec",
501 unrsv_json);
502 for (int j = 0; j < MAX_CLASS_TYPE; j += 1) {
503 snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j);
504 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
505 exts->unrsv_bw[j]);
506 json_object_string_add(unrsv_json, cnt_buf,
507 aux_buf);
508 }
509 } else {
510 sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
511 for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
512 sbuf_push(
513 buf, indent + 2,
514 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
515 j, exts->unrsv_bw[j], j + 1,
516 exts->unrsv_bw[j + 1]);
517 }
518 }
519 }
520 if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
521 if (json) {
522 json_object_int_add(json, "te-metric", exts->te_metric);
523 } else
524 sbuf_push(buf, indent,
525 "Traffic Engineering Metric: %u\n",
526 exts->te_metric);
527 }
528 if (IS_SUBTLV(exts, EXT_RMT_AS)) {
529 if (json) {
530 json_object_int_add(json, "inter-as-te-remote-as",
531 exts->remote_as);
532 } else
533 sbuf_push(buf, indent,
534 "Inter-AS TE Remote AS number: %u\n",
535 exts->remote_as);
536 }
537 if (IS_SUBTLV(exts, EXT_RMT_IP)) {
538 if (json) {
539 inet_ntop(AF_INET6, &exts->remote_ip, aux_buf,
540 sizeof(aux_buf));
541 json_object_string_add(
542 json, "inter-as-te-remote-asbr-ip", aux_buf);
543 } else
544 sbuf_push(buf, indent,
545 "Inter-AS TE Remote ASBR IP address: %pI4\n",
546 &exts->remote_ip);
547 }
548 /* Extended metrics */
549 if (IS_SUBTLV(exts, EXT_DELAY)) {
550 if (json) {
551 struct json_object *avg_json;
552 avg_json = json_object_new_object();
553 json_object_object_add(json, "avg-delay", avg_json);
554 json_object_string_add(avg_json, "delay",
555 IS_ANORMAL(exts->delay)
556 ? "Anomalous"
557 : "Normal");
558 json_object_int_add(avg_json, "micro-sec", exts->delay);
559 } else
560 sbuf_push(buf, indent,
561 "%s Average Link Delay: %u (micro-sec)\n",
562 IS_ANORMAL(exts->delay) ? "Anomalous"
563 : "Normal",
564 exts->delay & TE_EXT_MASK);
565 }
566 if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
567 if (json) {
568 struct json_object *avg_json;
569 avg_json = json_object_new_object();
570 json_object_object_add(json, "max-min-delay", avg_json);
571 json_object_string_add(avg_json, "delay",
572 IS_ANORMAL(exts->min_delay)
573 ? "Anomalous"
574 : "Normal");
575 snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u",
576 exts->min_delay & TE_EXT_MASK,
577 exts->max_delay & TE_EXT_MASK);
578 json_object_string_add(avg_json, "micro-sec", aux_buf);
579
580 } else
581 sbuf_push(
582 buf, indent,
583 "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
584 IS_ANORMAL(exts->min_delay) ? "Anomalous"
585 : "Normal",
586 exts->min_delay & TE_EXT_MASK,
587 exts->max_delay & TE_EXT_MASK);
588 }
589 if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
590 if (json) {
591 json_object_int_add(json, "delay-variation-micro-sec",
592 exts->delay_var & TE_EXT_MASK);
593 } else
594 sbuf_push(buf, indent,
595 "Delay Variation: %u (micro-sec)\n",
596 exts->delay_var & TE_EXT_MASK);
597 }
598 if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
599 if (json) {
600 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
601 (float)((exts->pkt_loss & TE_EXT_MASK) *
602 LOSS_PRECISION));
603 struct json_object *link_json;
604 link_json = json_object_new_object();
605 json_object_object_add(json, "link-packet-loss",
606 link_json);
607 json_object_string_add(link_json, "loss",
608 IS_ANORMAL(exts->pkt_loss)
609 ? "Anomalous"
610 : "Normal");
611 json_object_string_add(link_json, "percentaje",
612 aux_buf);
613 } else
614 sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
615 IS_ANORMAL(exts->pkt_loss) ? "Anomalous"
616 : "Normal",
617 (float)((exts->pkt_loss & TE_EXT_MASK) *
618 LOSS_PRECISION));
619 }
620 if (IS_SUBTLV(exts, EXT_RES_BW)) {
621 if (json) {
622 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
623 (exts->res_bw));
624 json_object_string_add(json,
625 "unidir-residual-band-bytes-sec",
626 aux_buf);
627 } else
628 sbuf_push(
629 buf, indent,
630 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
631 exts->res_bw);
632 }
633 if (IS_SUBTLV(exts, EXT_AVA_BW)) {
634 if (json) {
635 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
636 (exts->ava_bw));
637 json_object_string_add(
638 json, "unidir-available-band-bytes-sec",
639 aux_buf);
640 } else
641 sbuf_push(
642 buf, indent,
643 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
644 exts->ava_bw);
645 }
646 if (IS_SUBTLV(exts, EXT_USE_BW)) {
647 if (json) {
648 snprintfrr(aux_buf, sizeof(aux_buf), "%g",
649 (exts->use_bw));
650 json_object_string_add(json,
651 "unidir-utilized-band-bytes-sec",
652 aux_buf);
653 } else
654 sbuf_push(
655 buf, indent,
656 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
657 exts->use_bw);
658 }
659 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
660 if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
661 struct isis_adj_sid *adj;
662
663 if (json) {
664 struct json_object *arr_adj_json, *flags_json;
665 arr_adj_json = json_object_new_array();
666 json_object_object_add(json, "adj-sid", arr_adj_json);
667 for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
668 adj; adj = adj->next) {
669 snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
670 adj->sid);
671 flags_json = json_object_new_object();
672 json_object_int_add(flags_json, "sid",
673 adj->sid);
674 json_object_int_add(flags_json, "weight",
675 adj->weight);
676 json_object_string_add(
677 flags_json, "flag-f",
678 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
679 ? "1"
680 : "0");
681 json_object_string_add(
682 flags_json, "flag-b",
683 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
684 ? "1"
685 : "0");
686 json_object_string_add(
687 flags_json, "flag-v",
688 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
689 ? "1"
690 : "0");
691 json_object_string_add(
692 flags_json, "flag-l",
693 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
694 ? "1"
695 : "0");
696 json_object_string_add(
697 flags_json, "flag-s",
698 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
699 ? "1"
700 : "0");
701 json_object_string_add(
702 flags_json, "flag-p",
703 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
704 ? "1"
705 : "0");
706 json_object_array_add(arr_adj_json, flags_json);
707 }
708 } else
709 for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
710 adj; adj = adj->next) {
711 sbuf_push(
712 buf, indent,
713 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
714 adj->sid, adj->weight,
715 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
716 ? '1'
717 : '0',
718 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
719 ? '1'
720 : '0',
721 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
722 ? '1'
723 : '0',
724 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
725 ? '1'
726 : '0',
727 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
728 ? '1'
729 : '0',
730 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
731 ? '1'
732 : '0');
733 }
734 }
735 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
736 if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
737 struct isis_lan_adj_sid *lan;
738 if (json) {
739 struct json_object *arr_adj_json, *flags_json;
740 arr_adj_json = json_object_new_array();
741 json_object_object_add(json, "lan-adj-sid",
742 arr_adj_json);
743 for (lan = (struct isis_lan_adj_sid *)
744 exts->adj_sid.head;
745 lan; lan = lan->next) {
746 if (((mtid == ISIS_MT_IPV4_UNICAST) &&
747 (lan->family != AF_INET)) ||
748 ((mtid == ISIS_MT_IPV6_UNICAST) &&
749 (lan->family != AF_INET6)))
750 continue;
751 snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
752 lan->sid);
753 flags_json = json_object_new_object();
754 json_object_int_add(flags_json, "sid",
755 lan->sid);
756 json_object_int_add(flags_json, "weight",
757 lan->weight);
758 json_object_string_add(
759 flags_json, "flag-f",
760 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
761 ? "1"
762 : "0");
763 json_object_string_add(
764 flags_json, "flag-b",
765 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
766 ? "1"
767 : "0");
768 json_object_string_add(
769 flags_json, "flag-v",
770 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
771 ? "1"
772 : "0");
773 json_object_string_add(
774 flags_json, "flag-l",
775 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
776 ? "1"
777 : "0");
778 json_object_string_add(
779 flags_json, "flag-s",
780 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
781 ? "1"
782 : "0");
783 json_object_string_add(
784 flags_json, "flag-p",
785 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
786 ? "1"
787 : "0");
788 json_object_array_add(arr_adj_json, flags_json);
789 }
790 } else
791
792 for (lan = (struct isis_lan_adj_sid *)
793 exts->lan_sid.head;
794 lan; lan = lan->next) {
795 if (((mtid == ISIS_MT_IPV4_UNICAST) &&
796 (lan->family != AF_INET)) ||
797 ((mtid == ISIS_MT_IPV6_UNICAST) &&
798 (lan->family != AF_INET6)))
799 continue;
800 sbuf_push(
801 buf, indent,
802 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
803 " Neighbor-ID: %pSY\n",
804 lan->sid, lan->weight,
805 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
806 ? '1'
807 : '0',
808 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
809 ? '1'
810 : '0',
811 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
812 ? '1'
813 : '0',
814 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
815 ? '1'
816 : '0',
817 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
818 ? '1'
819 : '0',
820 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
821 ? '1'
822 : '0',
823 lan->neighbor_id);
824 }
825 }
826 for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla))
827 format_item_asla_subtlvs(asla, buf, indent);
828 }
829
830 static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts)
831 {
832 isis_del_ext_subtlvs(exts);
833 }
834
835 static int pack_item_ext_subtlv_asla(struct isis_asla_subtlvs *asla,
836 struct stream *s, size_t *min_len)
837 {
838 size_t subtlv_len;
839 size_t subtlv_len_pos;
840
841 /* Sub TLV header */
842 stream_putc(s, ISIS_SUBTLV_ASLA);
843
844 subtlv_len_pos = stream_get_endp(s);
845 stream_putc(s, 0); /* length will be filled later */
846
847 /* SABM Flag/Length */
848 if (asla->legacy)
849 stream_putc(s, ASLA_LEGACY_FLAG | asla->standard_apps_length);
850 else
851 stream_putc(s, asla->standard_apps_length);
852 stream_putc(s, asla->user_def_apps_length); /* UDABM Flag/Length */
853 stream_putc(s, asla->standard_apps);
854 stream_putc(s, asla->user_def_apps);
855
856 /* Administrative Group */
857 if (IS_SUBTLV(asla, EXT_ADM_GRP)) {
858 stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
859 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
860 stream_putl(s, asla->admin_group);
861 }
862
863 /* Extended Administrative Group */
864 if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) &&
865 admin_group_nb_words(&asla->ext_admin_group) != 0) {
866 size_t ag_length;
867 size_t ag_length_pos;
868 struct admin_group *ag;
869
870 stream_putc(s, ISIS_SUBTLV_EXT_ADMIN_GRP);
871 ag_length_pos = stream_get_endp(s);
872 stream_putc(s, 0); /* length will be filled later*/
873
874 ag = &asla->ext_admin_group;
875 for (size_t i = 0; i < admin_group_nb_words(ag); i++)
876 stream_putl(s, ag->bitmap.data[i]);
877
878 ag_length = stream_get_endp(s) - ag_length_pos - 1;
879 stream_putc_at(s, ag_length_pos, ag_length);
880 }
881
882 if (IS_SUBTLV(asla, EXT_MAX_BW)) {
883 stream_putc(s, ISIS_SUBTLV_MAX_BW);
884 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
885 stream_putf(s, asla->max_bw);
886 }
887 if (IS_SUBTLV(asla, EXT_MAX_RSV_BW)) {
888 stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
889 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
890 stream_putf(s, asla->max_rsv_bw);
891 }
892 if (IS_SUBTLV(asla, EXT_UNRSV_BW)) {
893 stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
894 stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
895 for (int j = 0; j < MAX_CLASS_TYPE; j++)
896 stream_putf(s, asla->unrsv_bw[j]);
897 }
898 if (IS_SUBTLV(asla, EXT_TE_METRIC)) {
899 stream_putc(s, ISIS_SUBTLV_TE_METRIC);
900 stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
901 stream_put3(s, asla->te_metric);
902 }
903 if (IS_SUBTLV(asla, EXT_DELAY)) {
904 stream_putc(s, ISIS_SUBTLV_AV_DELAY);
905 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
906 stream_putl(s, asla->delay);
907 }
908 if (IS_SUBTLV(asla, EXT_MM_DELAY)) {
909 stream_putc(s, ISIS_SUBTLV_MM_DELAY);
910 stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
911 stream_putl(s, asla->min_delay);
912 stream_putl(s, asla->max_delay);
913 }
914 if (IS_SUBTLV(asla, EXT_DELAY_VAR)) {
915 stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
916 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
917 stream_putl(s, asla->delay_var);
918 }
919 if (IS_SUBTLV(asla, EXT_PKT_LOSS)) {
920 stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
921 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
922 stream_putl(s, asla->pkt_loss);
923 }
924 if (IS_SUBTLV(asla, EXT_RES_BW)) {
925 stream_putc(s, ISIS_SUBTLV_RES_BW);
926 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
927 stream_putf(s, asla->res_bw);
928 }
929 if (IS_SUBTLV(asla, EXT_AVA_BW)) {
930 stream_putc(s, ISIS_SUBTLV_AVA_BW);
931 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
932 stream_putf(s, asla->ava_bw);
933 }
934 if (IS_SUBTLV(asla, EXT_USE_BW)) {
935 stream_putc(s, ISIS_SUBTLV_USE_BW);
936 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
937 stream_putf(s, asla->use_bw);
938 }
939
940 subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
941 stream_putc_at(s, subtlv_len_pos, subtlv_len);
942
943 return 0;
944 }
945
946 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
947 struct stream *s, size_t *min_len)
948 {
949 struct isis_asla_subtlvs *asla;
950 struct listnode *node;
951 uint8_t size;
952 int ret;
953
954 if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) {
955 *min_len = ISIS_SUBTLV_MAX_SIZE;
956 return 1;
957 }
958
959 if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
960 stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
961 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
962 stream_putl(s, exts->adm_group);
963 }
964 if (IS_SUBTLV(exts, EXT_EXTEND_ADM_GRP) &&
965 admin_group_nb_words(&exts->ext_admin_group) != 0) {
966 /* Extended Administrative Group */
967 size_t ag_length;
968 size_t ag_length_pos;
969 struct admin_group *ag;
970
971 stream_putc(s, ISIS_SUBTLV_EXT_ADMIN_GRP);
972 ag_length_pos = stream_get_endp(s);
973 stream_putc(s, 0); /* length will be filled later*/
974
975 ag = &exts->ext_admin_group;
976 for (size_t i = 0; i < admin_group_nb_words(ag); i++)
977 stream_putl(s, ag->bitmap.data[i]);
978
979 ag_length = stream_get_endp(s) - ag_length_pos - 1;
980 stream_putc_at(s, ag_length_pos, ag_length);
981 }
982 if (IS_SUBTLV(exts, EXT_LLRI)) {
983 stream_putc(s, ISIS_SUBTLV_LLRI);
984 stream_putc(s, ISIS_SUBTLV_LLRI_SIZE);
985 stream_putl(s, exts->local_llri);
986 stream_putl(s, exts->remote_llri);
987 }
988 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
989 stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR);
990 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
991 stream_put(s, &exts->local_addr.s_addr, 4);
992 }
993 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
994 stream_putc(s, ISIS_SUBTLV_RMT_IPADDR);
995 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
996 stream_put(s, &exts->neigh_addr.s_addr, 4);
997 }
998 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
999 stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6);
1000 stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
1001 stream_put(s, &exts->local_addr6, 16);
1002 }
1003 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
1004 stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6);
1005 stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
1006 stream_put(s, &exts->neigh_addr6, 16);
1007 }
1008 if (IS_SUBTLV(exts, EXT_MAX_BW)) {
1009 stream_putc(s, ISIS_SUBTLV_MAX_BW);
1010 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1011 stream_putf(s, exts->max_bw);
1012 }
1013 if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
1014 stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
1015 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1016 stream_putf(s, exts->max_rsv_bw);
1017 }
1018 if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
1019 stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
1020 stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
1021 for (int j = 0; j < MAX_CLASS_TYPE; j++)
1022 stream_putf(s, exts->unrsv_bw[j]);
1023 }
1024 if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
1025 stream_putc(s, ISIS_SUBTLV_TE_METRIC);
1026 stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
1027 stream_put3(s, exts->te_metric);
1028 }
1029 if (IS_SUBTLV(exts, EXT_RMT_AS)) {
1030 stream_putc(s, ISIS_SUBTLV_RAS);
1031 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1032 stream_putl(s, exts->remote_as);
1033 }
1034 if (IS_SUBTLV(exts, EXT_RMT_IP)) {
1035 stream_putc(s, ISIS_SUBTLV_RIP);
1036 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1037 stream_put(s, &exts->remote_ip.s_addr, 4);
1038 }
1039 if (IS_SUBTLV(exts, EXT_DELAY)) {
1040 stream_putc(s, ISIS_SUBTLV_AV_DELAY);
1041 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1042 stream_putl(s, exts->delay);
1043 }
1044 if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
1045 stream_putc(s, ISIS_SUBTLV_MM_DELAY);
1046 stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
1047 stream_putl(s, exts->min_delay);
1048 stream_putl(s, exts->max_delay);
1049 }
1050 if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
1051 stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
1052 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1053 stream_putl(s, exts->delay_var);
1054 }
1055 if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
1056 stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
1057 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1058 stream_putl(s, exts->pkt_loss);
1059 }
1060 if (IS_SUBTLV(exts, EXT_RES_BW)) {
1061 stream_putc(s, ISIS_SUBTLV_RES_BW);
1062 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1063 stream_putf(s, exts->res_bw);
1064 }
1065 if (IS_SUBTLV(exts, EXT_AVA_BW)) {
1066 stream_putc(s, ISIS_SUBTLV_AVA_BW);
1067 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1068 stream_putf(s, exts->ava_bw);
1069 }
1070 if (IS_SUBTLV(exts, EXT_USE_BW)) {
1071 stream_putc(s, ISIS_SUBTLV_USE_BW);
1072 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
1073 stream_putf(s, exts->use_bw);
1074 }
1075 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1076 if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
1077 struct isis_adj_sid *adj;
1078
1079 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
1080 adj = adj->next) {
1081 stream_putc(s, ISIS_SUBTLV_ADJ_SID);
1082 size = ISIS_SUBTLV_ADJ_SID_SIZE;
1083 if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1084 size++;
1085 stream_putc(s, size);
1086 stream_putc(s, adj->flags);
1087 stream_putc(s, adj->weight);
1088 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
1089 stream_put3(s, adj->sid);
1090 else
1091 stream_putl(s, adj->sid);
1092
1093 }
1094 }
1095 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
1096 if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
1097 struct isis_lan_adj_sid *lan;
1098
1099 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan;
1100 lan = lan->next) {
1101 stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID);
1102 size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE;
1103 if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1104 size++;
1105 stream_putc(s, size);
1106 stream_putc(s, lan->flags);
1107 stream_putc(s, lan->weight);
1108 stream_put(s, lan->neighbor_id, 6);
1109 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
1110 stream_put3(s, lan->sid);
1111 else
1112 stream_putl(s, lan->sid);
1113 }
1114 }
1115
1116 for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla)) {
1117 ret = pack_item_ext_subtlv_asla(asla, s, min_len);
1118 if (ret < 0)
1119 return ret;
1120 }
1121
1122 return 0;
1123 }
1124
1125 static int unpack_item_ext_subtlv_asla(uint16_t mtid, uint8_t subtlv_len,
1126 struct stream *s, struct sbuf *log,
1127 int indent,
1128 struct isis_ext_subtlvs *exts)
1129 {
1130 /* Standard App Identifier Bit Flags/Length */
1131 uint8_t sabm_flag_len;
1132 /* User-defined App Identifier Bit Flags/Length */
1133 uint8_t uabm_flag_len;
1134 uint8_t sabm[ASLA_APP_IDENTIFIER_BIT_LENGTH] = {0};
1135 uint8_t uabm[ASLA_APP_IDENTIFIER_BIT_LENGTH] = {0};
1136 uint8_t readable;
1137 uint8_t subsubtlv_type;
1138 uint8_t subsubtlv_len;
1139 size_t nb_groups;
1140 struct isis_asla_subtlvs *asla;
1141
1142 if (subtlv_len < ISIS_SUBSUBTLV_HDR_SIZE) {
1143 TLV_SIZE_MISMATCH(log, indent, "ASLA");
1144 return -1;
1145 }
1146
1147
1148 asla = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*asla));
1149
1150 admin_group_init(&asla->ext_admin_group);
1151
1152
1153 sabm_flag_len = stream_getc(s);
1154 uabm_flag_len = stream_getc(s);
1155 asla->legacy = CHECK_FLAG(sabm_flag_len, ASLA_LEGACY_FLAG);
1156 asla->standard_apps_length = ASLA_APPS_LENGTH_MASK & sabm_flag_len;
1157 asla->user_def_apps_length = ASLA_APPS_LENGTH_MASK & uabm_flag_len;
1158
1159 for (int i = 0; i < asla->standard_apps_length; i++)
1160 sabm[i] = stream_getc(s);
1161 for (int i = 0; i < asla->user_def_apps_length; i++)
1162 uabm[i] = stream_getc(s);
1163
1164 asla->standard_apps = sabm[0];
1165 asla->user_def_apps = uabm[0];
1166
1167 readable = subtlv_len - 4;
1168 while (readable > 0) {
1169 if (readable < ISIS_SUBSUBTLV_HDR_SIZE) {
1170 TLV_SIZE_MISMATCH(log, indent, "ASLA Sub TLV");
1171 return -1;
1172 }
1173
1174 subsubtlv_type = stream_getc(s);
1175 subsubtlv_len = stream_getc(s);
1176 readable -= ISIS_SUBSUBTLV_HDR_SIZE;
1177
1178
1179 switch (subsubtlv_type) {
1180 case ISIS_SUBTLV_ADMIN_GRP:
1181 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1182 TLV_SIZE_MISMATCH(log, indent,
1183 "ASLA Adm Group");
1184 stream_forward_getp(s, subsubtlv_len);
1185 } else {
1186 asla->admin_group = stream_getl(s);
1187 SET_SUBTLV(asla, EXT_ADM_GRP);
1188 }
1189 break;
1190
1191 case ISIS_SUBTLV_EXT_ADMIN_GRP:
1192 nb_groups = subsubtlv_len / sizeof(uint32_t);
1193 for (size_t i = 0; i < nb_groups; i++) {
1194 uint32_t val = stream_getl(s);
1195
1196 admin_group_bulk_set(&asla->ext_admin_group,
1197 val, i);
1198 }
1199 SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
1200 break;
1201 case ISIS_SUBTLV_MAX_BW:
1202 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1203 TLV_SIZE_MISMATCH(log, indent,
1204 "Maximum Bandwidth");
1205 stream_forward_getp(s, subsubtlv_len);
1206 } else {
1207 asla->max_bw = stream_getf(s);
1208 SET_SUBTLV(asla, EXT_MAX_BW);
1209 }
1210 break;
1211 case ISIS_SUBTLV_MAX_RSV_BW:
1212 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1213 TLV_SIZE_MISMATCH(
1214 log, indent,
1215 "Maximum Reservable Bandwidth");
1216 stream_forward_getp(s, subsubtlv_len);
1217 } else {
1218 asla->max_rsv_bw = stream_getf(s);
1219 SET_SUBTLV(asla, EXT_MAX_RSV_BW);
1220 }
1221 break;
1222 case ISIS_SUBTLV_UNRSV_BW:
1223 if (subsubtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
1224 TLV_SIZE_MISMATCH(log, indent,
1225 "Unreserved Bandwidth");
1226 stream_forward_getp(s, subsubtlv_len);
1227 } else {
1228 for (int i = 0; i < MAX_CLASS_TYPE; i++)
1229 asla->unrsv_bw[i] = stream_getf(s);
1230 SET_SUBTLV(asla, EXT_UNRSV_BW);
1231 }
1232 break;
1233 case ISIS_SUBTLV_TE_METRIC:
1234 if (subsubtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
1235 TLV_SIZE_MISMATCH(log, indent,
1236 "Traffic Engineering Metric");
1237 stream_forward_getp(s, subsubtlv_len);
1238 } else {
1239 asla->te_metric = stream_get3(s);
1240 SET_SUBTLV(asla, EXT_TE_METRIC);
1241 }
1242 break;
1243 /* Extended Metrics as defined in RFC 7810 */
1244 case ISIS_SUBTLV_AV_DELAY:
1245 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1246 TLV_SIZE_MISMATCH(log, indent,
1247 "Average Link Delay");
1248 stream_forward_getp(s, subsubtlv_len);
1249 } else {
1250 asla->delay = stream_getl(s);
1251 SET_SUBTLV(asla, EXT_DELAY);
1252 }
1253 break;
1254 case ISIS_SUBTLV_MM_DELAY:
1255 if (subsubtlv_len != ISIS_SUBTLV_MM_DELAY_SIZE) {
1256 TLV_SIZE_MISMATCH(log, indent,
1257 "Min/Max Link Delay");
1258 stream_forward_getp(s, subsubtlv_len);
1259 } else {
1260 asla->min_delay = stream_getl(s);
1261 asla->max_delay = stream_getl(s);
1262 SET_SUBTLV(asla, EXT_MM_DELAY);
1263 }
1264 break;
1265 case ISIS_SUBTLV_DELAY_VAR:
1266 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1267 TLV_SIZE_MISMATCH(log, indent,
1268 "Delay Variation");
1269 stream_forward_getp(s, subsubtlv_len);
1270 } else {
1271 asla->delay_var = stream_getl(s);
1272 SET_SUBTLV(asla, EXT_DELAY_VAR);
1273 }
1274 break;
1275 case ISIS_SUBTLV_PKT_LOSS:
1276 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1277 TLV_SIZE_MISMATCH(log, indent,
1278 "Link Packet Loss");
1279 stream_forward_getp(s, subsubtlv_len);
1280 } else {
1281 asla->pkt_loss = stream_getl(s);
1282 SET_SUBTLV(asla, EXT_PKT_LOSS);
1283 }
1284 break;
1285 case ISIS_SUBTLV_RES_BW:
1286 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1287 TLV_SIZE_MISMATCH(
1288 log, indent,
1289 "Unidirectional Residual Bandwidth");
1290 stream_forward_getp(s, subsubtlv_len);
1291 } else {
1292 asla->res_bw = stream_getf(s);
1293 SET_SUBTLV(asla, EXT_RES_BW);
1294 }
1295 break;
1296 case ISIS_SUBTLV_AVA_BW:
1297 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1298 TLV_SIZE_MISMATCH(
1299 log, indent,
1300 "Unidirectional Available Bandwidth");
1301 stream_forward_getp(s, subsubtlv_len);
1302 } else {
1303 asla->ava_bw = stream_getf(s);
1304 SET_SUBTLV(asla, EXT_AVA_BW);
1305 }
1306 break;
1307 case ISIS_SUBTLV_USE_BW:
1308 if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1309 TLV_SIZE_MISMATCH(
1310 log, indent,
1311 "Unidirectional Utilized Bandwidth");
1312 stream_forward_getp(s, subsubtlv_len);
1313 } else {
1314 asla->use_bw = stream_getf(s);
1315 SET_SUBTLV(asla, EXT_USE_BW);
1316 }
1317 break;
1318 default:
1319 zlog_debug("unknown (t,l)=(%u,%u)", subsubtlv_type,
1320 subsubtlv_len);
1321 stream_forward_getp(s, subsubtlv_len);
1322 break;
1323 }
1324 readable -= subsubtlv_len;
1325 }
1326
1327 listnode_add(exts->aslas, asla);
1328
1329 return 0;
1330 }
1331
1332 static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
1333 struct sbuf *log, void *dest, int indent)
1334 {
1335 uint8_t sum = 0;
1336 uint8_t subtlv_type;
1337 uint8_t subtlv_len;
1338 size_t nb_groups;
1339 uint32_t val;
1340
1341 struct isis_extended_reach *rv = dest;
1342 struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs();
1343
1344 rv->subtlvs = exts;
1345
1346 /*
1347 * Parse subTLVs until reach subTLV length
1348 * Check that it remains at least 2 bytes: subTLV Type & Length
1349 */
1350 while (len > sum + 2) {
1351 /* Read SubTLV Type and Length */
1352 subtlv_type = stream_getc(s);
1353 subtlv_len = stream_getc(s);
1354 if (subtlv_len > len - sum - ISIS_SUBTLV_HDR_SIZE) {
1355 sbuf_push(
1356 log, indent,
1357 "TLV %hhu: Available data %u is less than TLV size %u !\n",
1358 subtlv_type, len - sum - ISIS_SUBTLV_HDR_SIZE,
1359 subtlv_len);
1360 return 1;
1361 }
1362
1363 switch (subtlv_type) {
1364 /* Standard Metric as defined in RFC5305 */
1365 case ISIS_SUBTLV_ADMIN_GRP:
1366 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1367 TLV_SIZE_MISMATCH(log, indent,
1368 "Administrative Group");
1369 stream_forward_getp(s, subtlv_len);
1370 } else {
1371 exts->adm_group = stream_getl(s);
1372 SET_SUBTLV(exts, EXT_ADM_GRP);
1373 }
1374 break;
1375 case ISIS_SUBTLV_EXT_ADMIN_GRP:
1376 nb_groups = subtlv_len / sizeof(uint32_t);
1377 for (size_t i = 0; i < nb_groups; i++) {
1378 val = stream_getl(s);
1379 admin_group_bulk_set(&exts->ext_admin_group,
1380 val, i);
1381 }
1382 SET_SUBTLV(exts, EXT_EXTEND_ADM_GRP);
1383 break;
1384 case ISIS_SUBTLV_LLRI:
1385 if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) {
1386 TLV_SIZE_MISMATCH(log, indent, "Link ID");
1387 stream_forward_getp(s, subtlv_len);
1388 } else {
1389 exts->local_llri = stream_getl(s);
1390 exts->remote_llri = stream_getl(s);
1391 SET_SUBTLV(exts, EXT_LLRI);
1392 }
1393 break;
1394 case ISIS_SUBTLV_LOCAL_IPADDR:
1395 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1396 TLV_SIZE_MISMATCH(log, indent,
1397 "Local IP address");
1398 stream_forward_getp(s, subtlv_len);
1399 } else {
1400 stream_get(&exts->local_addr.s_addr, s, 4);
1401 SET_SUBTLV(exts, EXT_LOCAL_ADDR);
1402 }
1403 break;
1404 case ISIS_SUBTLV_RMT_IPADDR:
1405 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1406 TLV_SIZE_MISMATCH(log, indent,
1407 "Remote IP address");
1408 stream_forward_getp(s, subtlv_len);
1409 } else {
1410 stream_get(&exts->neigh_addr.s_addr, s, 4);
1411 SET_SUBTLV(exts, EXT_NEIGH_ADDR);
1412 }
1413 break;
1414 case ISIS_SUBTLV_LOCAL_IPADDR6:
1415 if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
1416 TLV_SIZE_MISMATCH(log, indent,
1417 "Local IPv6 address");
1418 stream_forward_getp(s, subtlv_len);
1419 } else {
1420 stream_get(&exts->local_addr6, s, 16);
1421 SET_SUBTLV(exts, EXT_LOCAL_ADDR6);
1422 }
1423 break;
1424 case ISIS_SUBTLV_RMT_IPADDR6:
1425 if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
1426 TLV_SIZE_MISMATCH(log, indent,
1427 "Remote IPv6 address");
1428 stream_forward_getp(s, subtlv_len);
1429 } else {
1430 stream_get(&exts->neigh_addr6, s, 16);
1431 SET_SUBTLV(exts, EXT_NEIGH_ADDR6);
1432 }
1433 break;
1434 case ISIS_SUBTLV_MAX_BW:
1435 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1436 TLV_SIZE_MISMATCH(log, indent,
1437 "Maximum Bandwidth");
1438 stream_forward_getp(s, subtlv_len);
1439 } else {
1440 exts->max_bw = stream_getf(s);
1441 SET_SUBTLV(exts, EXT_MAX_BW);
1442 }
1443 break;
1444 case ISIS_SUBTLV_MAX_RSV_BW:
1445 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1446 TLV_SIZE_MISMATCH(
1447 log, indent,
1448 "Maximum Reservable Bandwidth");
1449 stream_forward_getp(s, subtlv_len);
1450 } else {
1451 exts->max_rsv_bw = stream_getf(s);
1452 SET_SUBTLV(exts, EXT_MAX_RSV_BW);
1453 }
1454 break;
1455 case ISIS_SUBTLV_UNRSV_BW:
1456 if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
1457 TLV_SIZE_MISMATCH(log, indent,
1458 "Unreserved Bandwidth");
1459 stream_forward_getp(s, subtlv_len);
1460 } else {
1461 for (int i = 0; i < MAX_CLASS_TYPE; i++)
1462 exts->unrsv_bw[i] = stream_getf(s);
1463 SET_SUBTLV(exts, EXT_UNRSV_BW);
1464 }
1465 break;
1466 case ISIS_SUBTLV_TE_METRIC:
1467 if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
1468 TLV_SIZE_MISMATCH(log, indent,
1469 "Traffic Engineering Metric");
1470 stream_forward_getp(s, subtlv_len);
1471 } else {
1472 exts->te_metric = stream_get3(s);
1473 SET_SUBTLV(exts, EXT_TE_METRIC);
1474 }
1475 break;
1476 case ISIS_SUBTLV_RAS:
1477 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1478 TLV_SIZE_MISMATCH(log, indent,
1479 "Remote AS number");
1480 stream_forward_getp(s, subtlv_len);
1481 } else {
1482 exts->remote_as = stream_getl(s);
1483 SET_SUBTLV(exts, EXT_RMT_AS);
1484 }
1485 break;
1486 case ISIS_SUBTLV_RIP:
1487 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1488 TLV_SIZE_MISMATCH(log, indent,
1489 "Remote ASBR IP Address");
1490 stream_forward_getp(s, subtlv_len);
1491 } else {
1492 stream_get(&exts->remote_ip.s_addr, s, 4);
1493 SET_SUBTLV(exts, EXT_RMT_IP);
1494 }
1495 break;
1496 /* Extended Metrics as defined in RFC 7810 */
1497 case ISIS_SUBTLV_AV_DELAY:
1498 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1499 TLV_SIZE_MISMATCH(log, indent,
1500 "Average Link Delay");
1501 stream_forward_getp(s, subtlv_len);
1502 } else {
1503 exts->delay = stream_getl(s);
1504 SET_SUBTLV(exts, EXT_DELAY);
1505 }
1506 break;
1507 case ISIS_SUBTLV_MM_DELAY:
1508 if (subtlv_len != ISIS_SUBTLV_MM_DELAY_SIZE) {
1509 TLV_SIZE_MISMATCH(log, indent,
1510 "Min/Max Link Delay");
1511 stream_forward_getp(s, subtlv_len);
1512 } else {
1513 exts->min_delay = stream_getl(s);
1514 exts->max_delay = stream_getl(s);
1515 SET_SUBTLV(exts, EXT_MM_DELAY);
1516 }
1517 break;
1518 case ISIS_SUBTLV_DELAY_VAR:
1519 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1520 TLV_SIZE_MISMATCH(log, indent,
1521 "Delay Variation");
1522 stream_forward_getp(s, subtlv_len);
1523 } else {
1524 exts->delay_var = stream_getl(s);
1525 SET_SUBTLV(exts, EXT_DELAY_VAR);
1526 }
1527 break;
1528 case ISIS_SUBTLV_PKT_LOSS:
1529 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1530 TLV_SIZE_MISMATCH(log, indent,
1531 "Link Packet Loss");
1532 stream_forward_getp(s, subtlv_len);
1533 } else {
1534 exts->pkt_loss = stream_getl(s);
1535 SET_SUBTLV(exts, EXT_PKT_LOSS);
1536 }
1537 break;
1538 case ISIS_SUBTLV_RES_BW:
1539 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1540 TLV_SIZE_MISMATCH(
1541 log, indent,
1542 "Unidirectional Residual Bandwidth");
1543 stream_forward_getp(s, subtlv_len);
1544 } else {
1545 exts->res_bw = stream_getf(s);
1546 SET_SUBTLV(exts, EXT_RES_BW);
1547 }
1548 break;
1549 case ISIS_SUBTLV_AVA_BW:
1550 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1551 TLV_SIZE_MISMATCH(
1552 log, indent,
1553 "Unidirectional Available Bandwidth");
1554 stream_forward_getp(s, subtlv_len);
1555 } else {
1556 exts->ava_bw = stream_getf(s);
1557 SET_SUBTLV(exts, EXT_AVA_BW);
1558 }
1559 break;
1560 case ISIS_SUBTLV_USE_BW:
1561 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
1562 TLV_SIZE_MISMATCH(
1563 log, indent,
1564 "Unidirectional Utilized Bandwidth");
1565 stream_forward_getp(s, subtlv_len);
1566 } else {
1567 exts->use_bw = stream_getf(s);
1568 SET_SUBTLV(exts, EXT_USE_BW);
1569 }
1570 break;
1571 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1572 case ISIS_SUBTLV_ADJ_SID:
1573 if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
1574 && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
1575 TLV_SIZE_MISMATCH(log, indent, "Adjacency SID");
1576 stream_forward_getp(s, subtlv_len);
1577 } else {
1578 struct isis_adj_sid *adj;
1579
1580 adj = XCALLOC(MTYPE_ISIS_SUBTLV,
1581 sizeof(struct isis_adj_sid));
1582 adj->flags = stream_getc(s);
1583 adj->weight = stream_getc(s);
1584 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
1585 && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE) {
1586 TLV_SIZE_MISMATCH(log, indent,
1587 "Adjacency SID");
1588 stream_forward_getp(s, subtlv_len - 2);
1589 XFREE(MTYPE_ISIS_SUBTLV, adj);
1590 break;
1591 }
1592
1593 if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
1594 && subtlv_len
1595 != ISIS_SUBTLV_ADJ_SID_SIZE
1596 + 1) {
1597 TLV_SIZE_MISMATCH(log, indent,
1598 "Adjacency SID");
1599 stream_forward_getp(s, subtlv_len - 2);
1600 XFREE(MTYPE_ISIS_SUBTLV, adj);
1601 break;
1602 }
1603
1604 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
1605 adj->sid = stream_get3(s);
1606 adj->sid &= MPLS_LABEL_VALUE_MASK;
1607 } else {
1608 adj->sid = stream_getl(s);
1609 }
1610 if (mtid == ISIS_MT_IPV4_UNICAST)
1611 adj->family = AF_INET;
1612 if (mtid == ISIS_MT_IPV6_UNICAST)
1613 adj->family = AF_INET6;
1614 append_item(&exts->adj_sid,
1615 (struct isis_item *)adj);
1616 SET_SUBTLV(exts, EXT_ADJ_SID);
1617 }
1618 break;
1619 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1620 case ISIS_SUBTLV_LAN_ADJ_SID:
1621 if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1622 && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
1623 TLV_SIZE_MISMATCH(log, indent,
1624 "LAN-Adjacency SID");
1625 stream_forward_getp(s, subtlv_len);
1626 } else {
1627 struct isis_lan_adj_sid *lan;
1628
1629 lan = XCALLOC(MTYPE_ISIS_SUBTLV,
1630 sizeof(struct isis_lan_adj_sid));
1631 lan->flags = stream_getc(s);
1632 lan->weight = stream_getc(s);
1633 stream_get(&(lan->neighbor_id), s,
1634 ISIS_SYS_ID_LEN);
1635
1636 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
1637 && subtlv_len
1638 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE) {
1639 TLV_SIZE_MISMATCH(log, indent,
1640 "LAN-Adjacency SID");
1641 stream_forward_getp(
1642 s, subtlv_len - 2
1643 - ISIS_SYS_ID_LEN);
1644 XFREE(MTYPE_ISIS_SUBTLV, lan);
1645 break;
1646 }
1647
1648 if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
1649 && subtlv_len
1650 != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
1651 + 1) {
1652 TLV_SIZE_MISMATCH(log, indent,
1653 "LAN-Adjacency SID");
1654 stream_forward_getp(
1655 s, subtlv_len - 2
1656 - ISIS_SYS_ID_LEN);
1657 XFREE(MTYPE_ISIS_SUBTLV, lan);
1658 break;
1659 }
1660
1661 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
1662 lan->sid = stream_get3(s);
1663 lan->sid &= MPLS_LABEL_VALUE_MASK;
1664 } else {
1665 lan->sid = stream_getl(s);
1666 }
1667 if (mtid == ISIS_MT_IPV4_UNICAST)
1668 lan->family = AF_INET;
1669 if (mtid == ISIS_MT_IPV6_UNICAST)
1670 lan->family = AF_INET6;
1671 append_item(&exts->lan_sid,
1672 (struct isis_item *)lan);
1673 SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
1674 }
1675 break;
1676 case ISIS_SUBTLV_ASLA:
1677 if (unpack_item_ext_subtlv_asla(mtid, subtlv_len, s,
1678 log, indent,
1679 exts) < 0) {
1680 sbuf_push(log, indent, "TLV parse error");
1681 }
1682 break;
1683 default:
1684 /* Skip unknown TLV */
1685 stream_forward_getp(s, subtlv_len);
1686 break;
1687 }
1688 sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE;
1689 }
1690
1691 return 0;
1692 }
1693
1694 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
1695 static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
1696 {
1697 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
1698 struct isis_prefix_sid *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
1699
1700 rv->flags = sid->flags;
1701 rv->algorithm = sid->algorithm;
1702 rv->value = sid->value;
1703 return (struct isis_item *)rv;
1704 }
1705
1706 static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
1707 struct sbuf *buf, struct json_object *json,
1708 int indent)
1709 {
1710 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
1711
1712 if (json) {
1713 struct json_object *sr_json;
1714 sr_json = json_object_new_object();
1715 json_object_object_add(json, "sr", sr_json);
1716 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
1717 json_object_int_add(sr_json, "label", sid->value);
1718 } else {
1719 json_object_int_add(sr_json, "index", sid->value);
1720 }
1721 json_object_int_add(sr_json, "alg", sid->algorithm);
1722 json_object_string_add(
1723 sr_json, "readvertised",
1724 ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes"
1725 : ""));
1726 json_object_string_add(
1727 sr_json, "node",
1728 ((sid->flags & ISIS_PREFIX_SID_NODE) ? "yes" : ""));
1729 json_object_string_add(sr_json, "php",
1730 ((sid->flags & ISIS_PREFIX_SID_NO_PHP)
1731 ? "no-php"
1732 : "php"));
1733 json_object_string_add(
1734 sr_json, "explicit-null",
1735 ((sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL) ? "yes"
1736 : ""));
1737 json_object_string_add(
1738 sr_json, "value",
1739 ((sid->flags & ISIS_PREFIX_SID_VALUE) ? "yes" : ""));
1740 json_object_string_add(
1741 sr_json, "local",
1742 ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : ""));
1743
1744 } else {
1745 sbuf_push(buf, indent, "SR Prefix-SID ");
1746 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
1747 sbuf_push(buf, 0, "Label: %u, ", sid->value);
1748 } else {
1749 sbuf_push(buf, 0, "Index: %u, ", sid->value);
1750 }
1751 sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm);
1752 sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
1753 sid->flags & ISIS_PREFIX_SID_READVERTISED
1754 ? " READVERTISED"
1755 : "",
1756 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
1757 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP"
1758 : " PHP",
1759 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL
1760 ? " EXPLICIT-NULL"
1761 : "",
1762 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
1763 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
1764 }
1765 }
1766
1767 static void free_item_prefix_sid(struct isis_item *i)
1768 {
1769 XFREE(MTYPE_ISIS_SUBTLV, i);
1770 }
1771
1772 static int pack_item_prefix_sid(struct isis_item *i, struct stream *s,
1773 size_t *min_len)
1774 {
1775 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
1776
1777 uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
1778
1779 if (STREAM_WRITEABLE(s) < size) {
1780 *min_len = size;
1781 return 1;
1782 }
1783
1784 stream_putc(s, sid->flags);
1785 stream_putc(s, sid->algorithm);
1786
1787 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
1788 stream_put3(s, sid->value);
1789 } else {
1790 stream_putl(s, sid->value);
1791 }
1792
1793 return 0;
1794 }
1795
1796 static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
1797 struct sbuf *log, void *dest, int indent)
1798 {
1799 struct isis_subtlvs *subtlvs = dest;
1800 struct isis_prefix_sid sid = {
1801 };
1802
1803 sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
1804
1805 if (len < 5) {
1806 sbuf_push(log, indent,
1807 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
1808 len);
1809 return 1;
1810 }
1811
1812 sid.flags = stream_getc(s);
1813 if (!!(sid.flags & ISIS_PREFIX_SID_VALUE)
1814 != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) {
1815 sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n");
1816 return 1;
1817 }
1818
1819 sid.algorithm = stream_getc(s);
1820
1821 uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE)
1822 ? ISIS_SUBTLV_PREFIX_SID_SIZE
1823 : ISIS_SUBTLV_PREFIX_SID_SIZE + 1;
1824 if (len != expected_size) {
1825 sbuf_push(log, indent,
1826 "TLV size differs from expected size. (expected %u but got %hhu)\n",
1827 expected_size, len);
1828 return 1;
1829 }
1830
1831 if (sid.flags & ISIS_PREFIX_SID_VALUE) {
1832 sid.value = stream_get3(s);
1833 if (!IS_MPLS_UNRESERVED_LABEL(sid.value)) {
1834 sbuf_push(log, indent, "Invalid absolute SID %u\n",
1835 sid.value);
1836 return 1;
1837 }
1838 } else {
1839 sid.value = stream_getl(s);
1840 }
1841
1842 format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, NULL, indent + 2);
1843 append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
1844 return 0;
1845 }
1846
1847 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
1848
1849 static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
1850 {
1851 if (!p)
1852 return NULL;
1853
1854 struct prefix_ipv6 *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
1855 rv->family = p->family;
1856 rv->prefixlen = p->prefixlen;
1857 memcpy(&rv->prefix, &p->prefix, sizeof(rv->prefix));
1858 return rv;
1859 }
1860
1861 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
1862 struct sbuf *buf,
1863 struct json_object *json,
1864 int indent)
1865 {
1866 if (!p)
1867 return;
1868
1869 char prefixbuf[PREFIX2STR_BUFFER];
1870 if (json) {
1871 prefix2str(p, prefixbuf, sizeof(prefixbuf));
1872 json_object_string_add(json, "ipv6-src-prefix", prefixbuf);
1873 } else {
1874 sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
1875 prefix2str(p, prefixbuf, sizeof(prefixbuf)));
1876 }
1877 }
1878
1879 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
1880 struct stream *s)
1881 {
1882 if (!p)
1883 return 0;
1884
1885 if (STREAM_WRITEABLE(s) < 3 + (unsigned)PSIZE(p->prefixlen))
1886 return 1;
1887
1888 stream_putc(s, ISIS_SUBTLV_IPV6_SOURCE_PREFIX);
1889 stream_putc(s, 1 + PSIZE(p->prefixlen));
1890 stream_putc(s, p->prefixlen);
1891 stream_put(s, &p->prefix, PSIZE(p->prefixlen));
1892 return 0;
1893 }
1894
1895 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
1896 uint8_t tlv_type, uint8_t tlv_len,
1897 struct stream *s, struct sbuf *log,
1898 void *dest, int indent)
1899 {
1900 struct isis_subtlvs *subtlvs = dest;
1901 struct prefix_ipv6 p = {
1902 .family = AF_INET6,
1903 };
1904
1905 sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
1906
1907 if (tlv_len < 1) {
1908 sbuf_push(log, indent,
1909 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
1910 tlv_len);
1911 return 1;
1912 }
1913
1914 p.prefixlen = stream_getc(s);
1915 if (p.prefixlen > IPV6_MAX_BITLEN) {
1916 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
1917 p.prefixlen);
1918 return 1;
1919 }
1920
1921 if (tlv_len != 1 + PSIZE(p.prefixlen)) {
1922 sbuf_push(
1923 log, indent,
1924 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
1925 1 + PSIZE(p.prefixlen), tlv_len);
1926 return 1;
1927 }
1928
1929 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
1930
1931 if (subtlvs->source_prefix) {
1932 sbuf_push(
1933 log, indent,
1934 "WARNING: source prefix Sub-TLV present multiple times.\n");
1935 /* Ignore all but first occurrence of the source prefix Sub-TLV
1936 */
1937 return 0;
1938 }
1939
1940 subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(p));
1941 memcpy(subtlvs->source_prefix, &p, sizeof(p));
1942 return 0;
1943 }
1944
1945 static struct isis_item *copy_item(enum isis_tlv_context context,
1946 enum isis_tlv_type type,
1947 struct isis_item *item);
1948 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
1949 struct isis_item_list *src, struct isis_item_list *dest);
1950 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
1951 enum isis_tlv_type type, struct isis_item_list *items,
1952 struct sbuf *buf, struct json_object *json,
1953 int indent);
1954 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1955 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
1956 struct isis_item_list *items);
1957 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
1958 enum isis_tlv_type type, struct isis_item_list *items,
1959 struct stream *s, struct isis_tlvs **fragment_tlvs,
1960 const struct pack_order_entry *pe,
1961 struct isis_tlvs *(*new_fragment)(struct list *l),
1962 struct list *new_fragment_arg);
1963 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1964
1965 /* Functions related to subtlvs */
1966
1967 static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context)
1968 {
1969 struct isis_subtlvs *result;
1970
1971 result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
1972 result->context = context;
1973
1974 init_item_list(&result->prefix_sids);
1975
1976 return result;
1977 }
1978
1979 static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
1980 {
1981 if (!subtlvs)
1982 return NULL;
1983
1984 struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
1985
1986 rv->context = subtlvs->context;
1987
1988 copy_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1989 &subtlvs->prefix_sids, &rv->prefix_sids);
1990
1991 rv->source_prefix =
1992 copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
1993 return rv;
1994 }
1995
1996 static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
1997 struct json_object *json, int indent)
1998 {
1999 format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
2000 &subtlvs->prefix_sids, buf, json, indent);
2001
2002 format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, json, indent);
2003 }
2004
2005 static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
2006 {
2007 if (!subtlvs)
2008 return;
2009
2010 free_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
2011 &subtlvs->prefix_sids);
2012
2013 XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
2014
2015 XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
2016 }
2017
2018 static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
2019 {
2020 int rv;
2021 size_t subtlv_len_pos = stream_get_endp(s);
2022
2023 if (STREAM_WRITEABLE(s) < 1)
2024 return 1;
2025
2026 stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
2027
2028 rv = pack_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
2029 &subtlvs->prefix_sids, s, NULL, NULL, NULL, NULL);
2030 if (rv)
2031 return rv;
2032
2033 rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
2034 if (rv)
2035 return rv;
2036
2037 size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
2038 if (subtlv_len > 255)
2039 return 1;
2040
2041 stream_putc_at(s, subtlv_len_pos, subtlv_len);
2042 return 0;
2043 }
2044
2045 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
2046 struct stream *stream, struct sbuf *log, void *dest,
2047 int indent, bool *unpacked_known_tlvs);
2048
2049 /* Functions related to TLVs 1 Area Addresses */
2050
2051 static struct isis_item *copy_item_area_address(struct isis_item *i)
2052 {
2053 struct isis_area_address *addr = (struct isis_area_address *)i;
2054 struct isis_area_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2055
2056 rv->len = addr->len;
2057 memcpy(rv->addr, addr->addr, addr->len);
2058 return (struct isis_item *)rv;
2059 }
2060
2061 static void format_item_area_address(uint16_t mtid, struct isis_item *i,
2062 struct sbuf *buf, struct json_object *json,
2063 int indent)
2064 {
2065 struct isis_area_address *addr = (struct isis_area_address *)i;
2066 struct iso_address iso_addr;
2067
2068 memcpy(iso_addr.area_addr, addr->addr, ISO_ADDR_SIZE);
2069 iso_addr.addr_len = addr->len;
2070 if (json)
2071 json_object_string_addf(json, "area-addr", "%pIS", &iso_addr);
2072 else
2073 sbuf_push(buf, indent, "Area Address: %pIS\n", &iso_addr);
2074 }
2075
2076 static void free_item_area_address(struct isis_item *i)
2077 {
2078 XFREE(MTYPE_ISIS_TLV, i);
2079 }
2080
2081 static int pack_item_area_address(struct isis_item *i, struct stream *s,
2082 size_t *min_len)
2083 {
2084 struct isis_area_address *addr = (struct isis_area_address *)i;
2085
2086 if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len) {
2087 *min_len = (unsigned)1 + addr->len;
2088 return 1;
2089 }
2090 stream_putc(s, addr->len);
2091 stream_put(s, addr->addr, addr->len);
2092 return 0;
2093 }
2094
2095 static int unpack_item_area_address(uint16_t mtid, uint8_t len,
2096 struct stream *s, struct sbuf *log,
2097 void *dest, int indent)
2098 {
2099 struct isis_tlvs *tlvs = dest;
2100 struct isis_area_address *rv = NULL;
2101
2102 sbuf_push(log, indent, "Unpack area address...\n");
2103 if (len < 1) {
2104 sbuf_push(
2105 log, indent,
2106 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
2107 len);
2108 goto out;
2109 }
2110
2111 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2112 rv->len = stream_getc(s);
2113
2114 if (len < 1 + rv->len) {
2115 sbuf_push(log, indent, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
2116 rv->len, len - 1);
2117 goto out;
2118 }
2119
2120 if (rv->len < 1 || rv->len > 20) {
2121 sbuf_push(log, indent,
2122 "Implausible area address length %hhu\n",
2123 rv->len);
2124 goto out;
2125 }
2126
2127 stream_get(rv->addr, s, rv->len);
2128
2129 format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv,
2130 log, NULL, indent + 2);
2131 append_item(&tlvs->area_addresses, (struct isis_item *)rv);
2132 return 0;
2133 out:
2134 XFREE(MTYPE_ISIS_TLV, rv);
2135 return 1;
2136 }
2137
2138 /* Functions related to TLV 2 (Old-Style) IS Reach */
2139 static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i)
2140 {
2141 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
2142 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2143
2144 memcpy(rv->id, r->id, 7);
2145 rv->metric = r->metric;
2146 return (struct isis_item *)rv;
2147 }
2148
2149 static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
2150 struct sbuf *buf,
2151 struct json_object *json, int indent)
2152 {
2153 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
2154 char sys_id[ISO_SYSID_STRLEN];
2155
2156 snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pPN", r->id);
2157 if (json) {
2158 struct json_object *old_json;
2159 old_json = json_object_new_object();
2160 json_object_object_add(json, "old-reach-style", old_json);
2161 json_object_string_add(old_json, "is-reach", sys_id);
2162 json_object_int_add(old_json, "metric", r->metric);
2163 } else
2164 sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n",
2165 sys_id, r->metric);
2166 }
2167
2168 static void free_item_oldstyle_reach(struct isis_item *i)
2169 {
2170 XFREE(MTYPE_ISIS_TLV, i);
2171 }
2172
2173 static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s,
2174 size_t *min_len)
2175 {
2176 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
2177
2178 if (STREAM_WRITEABLE(s) < 11) {
2179 *min_len = 11;
2180 return 1;
2181 }
2182
2183 stream_putc(s, r->metric);
2184 stream_putc(s, 0x80); /* delay metric - unsupported */
2185 stream_putc(s, 0x80); /* expense metric - unsupported */
2186 stream_putc(s, 0x80); /* error metric - unsupported */
2187 stream_put(s, r->id, 7);
2188
2189 return 0;
2190 }
2191
2192 static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len,
2193 struct stream *s, struct sbuf *log,
2194 void *dest, int indent)
2195 {
2196 struct isis_tlvs *tlvs = dest;
2197
2198 sbuf_push(log, indent, "Unpack oldstyle reach...\n");
2199 if (len < 11) {
2200 sbuf_push(
2201 log, indent,
2202 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
2203 len);
2204 return 1;
2205 }
2206
2207 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2208 rv->metric = stream_getc(s);
2209 if ((rv->metric & 0x3f) != rv->metric) {
2210 sbuf_push(log, indent, "Metric has unplausible format\n");
2211 rv->metric &= 0x3f;
2212 }
2213 stream_forward_getp(s, 3); /* Skip other metrics */
2214 stream_get(rv->id, s, 7);
2215
2216 format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, NULL,
2217 indent + 2);
2218 append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv);
2219 return 0;
2220 }
2221
2222 /* Functions related to TLV 6 LAN Neighbors */
2223 static struct isis_item *copy_item_lan_neighbor(struct isis_item *i)
2224 {
2225 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
2226 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2227
2228 memcpy(rv->mac, n->mac, 6);
2229 return (struct isis_item *)rv;
2230 }
2231
2232 static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
2233 struct sbuf *buf, struct json_object *json,
2234 int indent)
2235 {
2236 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
2237 char sys_id[ISO_SYSID_STRLEN];
2238
2239 snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", n->mac);
2240 if (json)
2241 json_object_string_add(json, "lan-neighbor", sys_id);
2242 else
2243 sbuf_push(buf, indent, "LAN Neighbor: %s\n", sys_id);
2244 }
2245
2246 static void free_item_lan_neighbor(struct isis_item *i)
2247 {
2248 XFREE(MTYPE_ISIS_TLV, i);
2249 }
2250
2251 static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s,
2252 size_t *min_len)
2253 {
2254 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
2255
2256 if (STREAM_WRITEABLE(s) < 6) {
2257 *min_len = 6;
2258 return 1;
2259 }
2260
2261 stream_put(s, n->mac, 6);
2262
2263 return 0;
2264 }
2265
2266 static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len,
2267 struct stream *s, struct sbuf *log,
2268 void *dest, int indent)
2269 {
2270 struct isis_tlvs *tlvs = dest;
2271
2272 sbuf_push(log, indent, "Unpack LAN neighbor...\n");
2273 if (len < 6) {
2274 sbuf_push(
2275 log, indent,
2276 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
2277 len);
2278 return 1;
2279 }
2280
2281 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2282 stream_get(rv->mac, s, 6);
2283
2284 format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
2285 append_item(&tlvs->lan_neighbor, (struct isis_item *)rv);
2286 return 0;
2287 }
2288
2289 /* Functions related to TLV 9 LSP Entry */
2290 static struct isis_item *copy_item_lsp_entry(struct isis_item *i)
2291 {
2292 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
2293 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2294
2295 rv->rem_lifetime = e->rem_lifetime;
2296 memcpy(rv->id, e->id, sizeof(rv->id));
2297 rv->seqno = e->seqno;
2298 rv->checksum = e->checksum;
2299
2300 return (struct isis_item *)rv;
2301 }
2302
2303 static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
2304 struct sbuf *buf, struct json_object *json,
2305 int indent)
2306 {
2307 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
2308 char sys_id[ISO_SYSID_STRLEN];
2309
2310 snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pLS", e->id);
2311 if (json) {
2312 char buf[255];
2313 struct json_object *lsp_json;
2314 lsp_json = json_object_new_object();
2315 json_object_object_add(json, "lsp-entry", lsp_json);
2316 json_object_string_add(lsp_json, "id", sys_id);
2317 snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno);
2318 json_object_string_add(lsp_json, "seq", buf);
2319 snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum);
2320 json_object_string_add(lsp_json, "chksum", buf);
2321 json_object_int_add(lsp_json, "lifetime", e->checksum);
2322 } else
2323 sbuf_push(
2324 buf, indent,
2325 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
2326 sys_id, e->seqno, e->checksum, e->rem_lifetime);
2327 }
2328
2329 static void free_item_lsp_entry(struct isis_item *i)
2330 {
2331 XFREE(MTYPE_ISIS_TLV, i);
2332 }
2333
2334 static int pack_item_lsp_entry(struct isis_item *i, struct stream *s,
2335 size_t *min_len)
2336 {
2337 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
2338
2339 if (STREAM_WRITEABLE(s) < 16) {
2340 *min_len = 16;
2341 return 1;
2342 }
2343
2344 stream_putw(s, e->rem_lifetime);
2345 stream_put(s, e->id, 8);
2346 stream_putl(s, e->seqno);
2347 stream_putw(s, e->checksum);
2348
2349 return 0;
2350 }
2351
2352 static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s,
2353 struct sbuf *log, void *dest, int indent)
2354 {
2355 struct isis_tlvs *tlvs = dest;
2356
2357 sbuf_push(log, indent, "Unpack LSP entry...\n");
2358 if (len < 16) {
2359 sbuf_push(
2360 log, indent,
2361 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
2362 len);
2363 return 1;
2364 }
2365
2366 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2367 rv->rem_lifetime = stream_getw(s);
2368 stream_get(rv->id, s, 8);
2369 rv->seqno = stream_getl(s);
2370 rv->checksum = stream_getw(s);
2371
2372 format_item_lsp_entry(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
2373 append_item(&tlvs->lsp_entries, (struct isis_item *)rv);
2374 return 0;
2375 }
2376
2377 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
2378
2379 static struct isis_item *copy_item_extended_reach(struct isis_item *i)
2380 {
2381 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
2382 struct isis_extended_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2383
2384 memcpy(rv->id, r->id, 7);
2385 rv->metric = r->metric;
2386
2387 if (r->subtlvs)
2388 rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1);
2389
2390 return (struct isis_item *)rv;
2391 }
2392
2393 static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
2394 struct sbuf *buf,
2395 struct json_object *json, int indent)
2396 {
2397 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
2398 char sys_id[ISO_SYSID_STRLEN];
2399
2400 snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pPN", r->id);
2401 if (json) {
2402 struct json_object *reach_json;
2403 reach_json = json_object_new_object();
2404 json_object_object_add(json, "ext-reach", reach_json);
2405 json_object_string_add(
2406 reach_json, "mt-id",
2407 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT");
2408 json_object_string_add(reach_json, "id", sys_id);
2409 json_object_int_add(reach_json, "metric", r->metric);
2410 if (mtid != ISIS_MT_IPV4_UNICAST)
2411 json_object_string_add(reach_json, "mt-name",
2412 isis_mtid2str(mtid));
2413
2414 if (r->subtlvs)
2415 format_item_ext_subtlvs(r->subtlvs, NULL, json,
2416 indent + 2, mtid);
2417 } else {
2418 sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
2419 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
2420 sys_id, r->metric);
2421 if (mtid != ISIS_MT_IPV4_UNICAST)
2422 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
2423 sbuf_push(buf, 0, "\n");
2424
2425 if (r->subtlvs)
2426 format_item_ext_subtlvs(r->subtlvs, buf, NULL,
2427 indent + 2, mtid);
2428 }
2429 }
2430
2431 static void free_item_extended_reach(struct isis_item *i)
2432 {
2433 struct isis_extended_reach *item = (struct isis_extended_reach *)i;
2434
2435 if (item->subtlvs != NULL)
2436 free_item_ext_subtlvs(item->subtlvs);
2437 XFREE(MTYPE_ISIS_TLV, item);
2438 }
2439
2440 static int pack_item_extended_reach(struct isis_item *i, struct stream *s,
2441 size_t *min_len)
2442 {
2443 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
2444 size_t len;
2445 size_t len_pos;
2446
2447 if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE) {
2448 *min_len = 11 + ISIS_SUBTLV_MAX_SIZE;
2449 return 1;
2450 }
2451
2452 stream_put(s, r->id, sizeof(r->id));
2453 stream_put3(s, r->metric);
2454 len_pos = stream_get_endp(s);
2455 /* Real length will be adjust after adding subTLVs */
2456 stream_putc(s, 11);
2457 if (r->subtlvs)
2458 pack_item_ext_subtlvs(r->subtlvs, s, min_len);
2459 /* Adjust length */
2460 len = stream_get_endp(s) - len_pos - 1;
2461 stream_putc_at(s, len_pos, len);
2462 return 0;
2463 }
2464
2465 static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
2466 struct stream *s, struct sbuf *log,
2467 void *dest, int indent)
2468 {
2469 struct isis_tlvs *tlvs = dest;
2470 struct isis_extended_reach *rv = NULL;
2471 uint8_t subtlv_len;
2472 struct isis_item_list *items;
2473
2474 if (mtid == ISIS_MT_IPV4_UNICAST) {
2475 items = &tlvs->extended_reach;
2476 } else {
2477 items = isis_get_mt_items(&tlvs->mt_reach, mtid);
2478 }
2479
2480 sbuf_push(log, indent, "Unpacking %s reachability...\n",
2481 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
2482
2483 if (len < 11) {
2484 sbuf_push(log, indent,
2485 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
2486 len);
2487 goto out;
2488 }
2489
2490 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2491 stream_get(rv->id, s, 7);
2492 rv->metric = stream_get3(s);
2493 subtlv_len = stream_getc(s);
2494
2495 if ((size_t)len < ((size_t)11) + subtlv_len) {
2496 sbuf_push(log, indent,
2497 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
2498 subtlv_len, len - 11);
2499 goto out;
2500 }
2501
2502 sbuf_push(log, indent, "Storing %hhu bytes of subtlvs\n",
2503 subtlv_len);
2504
2505 if (subtlv_len) {
2506 if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv,
2507 indent + 4)) {
2508 goto out;
2509 }
2510 }
2511
2512 format_item_extended_reach(mtid, (struct isis_item *)rv, log, NULL,
2513 indent + 2);
2514 append_item(items, (struct isis_item *)rv);
2515 return 0;
2516 out:
2517 if (rv)
2518 free_item_extended_reach((struct isis_item *)rv);
2519
2520 return 1;
2521 }
2522
2523 /* Functions related to TLV 128 (Old-Style) IP Reach */
2524 static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i)
2525 {
2526 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
2527 struct isis_oldstyle_ip_reach *rv =
2528 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2529
2530 rv->metric = r->metric;
2531 rv->prefix = r->prefix;
2532 return (struct isis_item *)rv;
2533 }
2534
2535 static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
2536 struct sbuf *buf,
2537 struct json_object *json, int indent)
2538 {
2539 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
2540 char prefixbuf[PREFIX2STR_BUFFER];
2541
2542 if (json) {
2543 struct json_object *old_json;
2544 old_json = json_object_new_object();
2545 json_object_object_add(json, "old-ip-reach-style", old_json);
2546 json_object_string_add(old_json, "prefix",
2547 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
2548 json_object_int_add(old_json, "metric", r->metric);
2549 } else
2550 sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n",
2551 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
2552 r->metric);
2553 }
2554
2555 static void free_item_oldstyle_ip_reach(struct isis_item *i)
2556 {
2557 XFREE(MTYPE_ISIS_TLV, i);
2558 }
2559
2560 static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s,
2561 size_t *min_len)
2562 {
2563 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
2564
2565 if (STREAM_WRITEABLE(s) < 12) {
2566 *min_len = 12;
2567 return 1;
2568 }
2569
2570 stream_putc(s, r->metric);
2571 stream_putc(s, 0x80); /* delay metric - unsupported */
2572 stream_putc(s, 0x80); /* expense metric - unsupported */
2573 stream_putc(s, 0x80); /* error metric - unsupported */
2574 stream_put(s, &r->prefix.prefix, 4);
2575
2576 struct in_addr mask;
2577 masklen2ip(r->prefix.prefixlen, &mask);
2578 stream_put(s, &mask, sizeof(mask));
2579
2580 return 0;
2581 }
2582
2583 static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len,
2584 struct stream *s, struct sbuf *log,
2585 void *dest, int indent)
2586 {
2587 sbuf_push(log, indent, "Unpack oldstyle ip reach...\n");
2588 if (len < 12) {
2589 sbuf_push(
2590 log, indent,
2591 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
2592 len);
2593 return 1;
2594 }
2595
2596 struct isis_oldstyle_ip_reach *rv =
2597 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2598 rv->metric = stream_getc(s);
2599 if ((rv->metric & 0x7f) != rv->metric) {
2600 sbuf_push(log, indent, "Metric has unplausible format\n");
2601 rv->metric &= 0x7f;
2602 }
2603 stream_forward_getp(s, 3); /* Skip other metrics */
2604 rv->prefix.family = AF_INET;
2605 stream_get(&rv->prefix.prefix, s, 4);
2606
2607 struct in_addr mask;
2608 stream_get(&mask, s, 4);
2609 rv->prefix.prefixlen = ip_masklen(mask);
2610
2611 format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, NULL,
2612 indent + 2);
2613 append_item(dest, (struct isis_item *)rv);
2614 return 0;
2615 }
2616
2617
2618 /* Functions related to TLV 129 protocols supported */
2619
2620 static void copy_tlv_protocols_supported(struct isis_protocols_supported *src,
2621 struct isis_protocols_supported *dest)
2622 {
2623 if (!src->protocols || !src->count)
2624 return;
2625 dest->count = src->count;
2626 dest->protocols = XCALLOC(MTYPE_ISIS_TLV, src->count);
2627 memcpy(dest->protocols, src->protocols, src->count);
2628 }
2629
2630 static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
2631 struct sbuf *buf,
2632 struct json_object *json, int indent)
2633 {
2634 if (!p || !p->count || !p->protocols)
2635 return;
2636
2637 if (json) {
2638 struct json_object *protocol_json;
2639 char buf[255];
2640
2641 protocol_json = json_object_new_object();
2642 json_object_object_add(json, "protocols-supported",
2643 protocol_json);
2644 for (uint8_t i = 0; i < p->count; i++) {
2645 snprintfrr(buf, sizeof(buf), "%d", i);
2646 json_object_string_add(protocol_json, buf,
2647 nlpid2str(p->protocols[i]));
2648 }
2649 } else {
2650 sbuf_push(buf, indent, "Protocols Supported: ");
2651 for (uint8_t i = 0; i < p->count; i++) {
2652 sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
2653 (i + 1 < p->count) ? ", " : "");
2654 }
2655 sbuf_push(buf, 0, "\n");
2656 }
2657 }
2658
2659 static void free_tlv_protocols_supported(struct isis_protocols_supported *p)
2660 {
2661 XFREE(MTYPE_ISIS_TLV, p->protocols);
2662 }
2663
2664 static int pack_tlv_protocols_supported(struct isis_protocols_supported *p,
2665 struct stream *s)
2666 {
2667 if (!p || !p->count || !p->protocols)
2668 return 0;
2669
2670 if (STREAM_WRITEABLE(s) < (unsigned)(p->count + 2))
2671 return 1;
2672
2673 stream_putc(s, ISIS_TLV_PROTOCOLS_SUPPORTED);
2674 stream_putc(s, p->count);
2675 stream_put(s, p->protocols, p->count);
2676 return 0;
2677 }
2678
2679 static int unpack_tlv_protocols_supported(enum isis_tlv_context context,
2680 uint8_t tlv_type, uint8_t tlv_len,
2681 struct stream *s, struct sbuf *log,
2682 void *dest, int indent)
2683 {
2684 struct isis_tlvs *tlvs = dest;
2685
2686 sbuf_push(log, indent, "Unpacking Protocols Supported TLV...\n");
2687 if (!tlv_len) {
2688 sbuf_push(log, indent, "WARNING: No protocols included\n");
2689 return 0;
2690 }
2691 if (tlvs->protocols_supported.protocols) {
2692 sbuf_push(
2693 log, indent,
2694 "WARNING: protocols supported TLV present multiple times.\n");
2695 stream_forward_getp(s, tlv_len);
2696 return 0;
2697 }
2698
2699 tlvs->protocols_supported.count = tlv_len;
2700 tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len);
2701 stream_get(tlvs->protocols_supported.protocols, s, tlv_len);
2702
2703 format_tlv_protocols_supported(&tlvs->protocols_supported, log, NULL,
2704 indent + 2);
2705 return 0;
2706 }
2707
2708 /* Functions related to TLV 132 IPv4 Interface addresses */
2709 static struct isis_item *copy_item_ipv4_address(struct isis_item *i)
2710 {
2711 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
2712 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2713
2714 rv->addr = a->addr;
2715 return (struct isis_item *)rv;
2716 }
2717
2718 static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i,
2719 struct sbuf *buf, struct json_object *json,
2720 int indent)
2721 {
2722 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
2723 char addrbuf[INET_ADDRSTRLEN];
2724
2725 inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf));
2726 if (json) {
2727 json_object_string_add(json, "ipv4", addrbuf);
2728 } else {
2729 sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
2730 }
2731 }
2732
2733 static void free_item_ipv4_address(struct isis_item *i)
2734 {
2735 XFREE(MTYPE_ISIS_TLV, i);
2736 }
2737
2738 static int pack_item_ipv4_address(struct isis_item *i, struct stream *s,
2739 size_t *min_len)
2740 {
2741 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
2742
2743 if (STREAM_WRITEABLE(s) < 4) {
2744 *min_len = 4;
2745 return 1;
2746 }
2747
2748 stream_put(s, &a->addr, 4);
2749
2750 return 0;
2751 }
2752
2753 static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len,
2754 struct stream *s, struct sbuf *log,
2755 void *dest, int indent)
2756 {
2757 struct isis_tlvs *tlvs = dest;
2758
2759 sbuf_push(log, indent, "Unpack IPv4 Interface address...\n");
2760 if (len < 4) {
2761 sbuf_push(
2762 log, indent,
2763 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
2764 len);
2765 return 1;
2766 }
2767
2768 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2769 stream_get(&rv->addr, s, 4);
2770
2771 format_item_ipv4_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
2772 append_item(&tlvs->ipv4_address, (struct isis_item *)rv);
2773 return 0;
2774 }
2775
2776
2777 /* Functions related to TLV 232 IPv6 Interface addresses */
2778 static struct isis_item *copy_item_ipv6_address(struct isis_item *i)
2779 {
2780 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
2781 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2782
2783 rv->addr = a->addr;
2784 return (struct isis_item *)rv;
2785 }
2786
2787 static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i,
2788 struct sbuf *buf, struct json_object *json,
2789 int indent)
2790 {
2791 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
2792 char addrbuf[INET6_ADDRSTRLEN];
2793
2794 inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
2795 if (json)
2796 json_object_string_add(json, "ipv6", addrbuf);
2797 else
2798 sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
2799 }
2800
2801 static void free_item_ipv6_address(struct isis_item *i)
2802 {
2803 XFREE(MTYPE_ISIS_TLV, i);
2804 }
2805
2806 static int pack_item_ipv6_address(struct isis_item *i, struct stream *s,
2807 size_t *min_len)
2808 {
2809 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
2810
2811 if (STREAM_WRITEABLE(s) < IPV6_MAX_BYTELEN) {
2812 *min_len = IPV6_MAX_BYTELEN;
2813 return 1;
2814 }
2815
2816 stream_put(s, &a->addr, IPV6_MAX_BYTELEN);
2817
2818 return 0;
2819 }
2820
2821 static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
2822 struct stream *s, struct sbuf *log,
2823 void *dest, int indent)
2824 {
2825 struct isis_tlvs *tlvs = dest;
2826
2827 sbuf_push(log, indent, "Unpack IPv6 Interface address...\n");
2828 if (len < 16) {
2829 sbuf_push(
2830 log, indent,
2831 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2832 len);
2833 return 1;
2834 }
2835
2836 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2837 stream_get(&rv->addr, s, IPV6_MAX_BYTELEN);
2838
2839 format_item_ipv6_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
2840 append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
2841 return 0;
2842 }
2843
2844
2845 /* Functions related to TLV 233 Global IPv6 Interface addresses */
2846 static struct isis_item *copy_item_global_ipv6_address(struct isis_item *i)
2847 {
2848 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
2849 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2850
2851 rv->addr = a->addr;
2852 return (struct isis_item *)rv;
2853 }
2854
2855 static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i,
2856 struct sbuf *buf,
2857 struct json_object *json,
2858 int indent)
2859 {
2860 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
2861 char addrbuf[INET6_ADDRSTRLEN];
2862
2863 inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
2864 if (json)
2865 json_object_string_add(json, "global-ipv6", addrbuf);
2866 else
2867 sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n",
2868 addrbuf);
2869 }
2870
2871 static void free_item_global_ipv6_address(struct isis_item *i)
2872 {
2873 XFREE(MTYPE_ISIS_TLV, i);
2874 }
2875
2876 static int pack_item_global_ipv6_address(struct isis_item *i, struct stream *s,
2877 size_t *min_len)
2878 {
2879 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
2880
2881 if (STREAM_WRITEABLE(s) < IPV6_MAX_BYTELEN) {
2882 *min_len = IPV6_MAX_BYTELEN;
2883 return 1;
2884 }
2885
2886 stream_put(s, &a->addr, IPV6_MAX_BYTELEN);
2887
2888 return 0;
2889 }
2890
2891 static int unpack_item_global_ipv6_address(uint16_t mtid, uint8_t len,
2892 struct stream *s, struct sbuf *log,
2893 void *dest, int indent)
2894 {
2895 struct isis_tlvs *tlvs = dest;
2896
2897 sbuf_push(log, indent, "Unpack Global IPv6 Interface address...\n");
2898 if (len < IPV6_MAX_BYTELEN) {
2899 sbuf_push(
2900 log, indent,
2901 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
2902 len);
2903 return 1;
2904 }
2905
2906 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2907 stream_get(&rv->addr, s, IPV6_MAX_BYTELEN);
2908
2909 format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log, NULL,
2910 indent + 2);
2911 append_item(&tlvs->global_ipv6_address, (struct isis_item *)rv);
2912 return 0;
2913 }
2914
2915 /* Functions related to TLV 229 MT Router information */
2916 static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
2917 {
2918 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
2919 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2920
2921 rv->overload = info->overload;
2922 rv->attached = info->attached;
2923 rv->mtid = info->mtid;
2924 return (struct isis_item *)rv;
2925 }
2926
2927 static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
2928 struct sbuf *buf,
2929 struct json_object *json, int indent)
2930 {
2931 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
2932
2933 if (json) {
2934 struct json_object *mt_json;
2935 mt_json = json_object_new_object();
2936 json_object_object_add(json, "mt", mt_json);
2937 json_object_int_add(mt_json, "mtid", info->mtid);
2938 json_object_string_add(mt_json, "overload", info->overload?"true":"false");
2939 json_object_string_add(mt_json, "attached", info->attached?"true":"false");
2940 } else
2941 sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
2942 isis_mtid2str_fake(info->mtid),
2943 info->overload ? " Overload" : "",
2944 info->attached ? " Attached" : "");
2945 }
2946
2947 static void free_item_mt_router_info(struct isis_item *i)
2948 {
2949 XFREE(MTYPE_ISIS_TLV, i);
2950 }
2951
2952 static int pack_item_mt_router_info(struct isis_item *i, struct stream *s,
2953 size_t *min_len)
2954 {
2955 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
2956
2957 if (STREAM_WRITEABLE(s) < 2) {
2958 *min_len = 2;
2959 return 1;
2960 }
2961
2962 uint16_t entry = info->mtid;
2963
2964 if (info->overload)
2965 entry |= ISIS_MT_OL_MASK;
2966 if (info->attached)
2967 entry |= ISIS_MT_AT_MASK;
2968
2969 stream_putw(s, entry);
2970
2971 return 0;
2972 }
2973
2974 static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len,
2975 struct stream *s, struct sbuf *log,
2976 void *dest, int indent)
2977 {
2978 struct isis_tlvs *tlvs = dest;
2979
2980 sbuf_push(log, indent, "Unpack MT Router info...\n");
2981 if (len < 2) {
2982 sbuf_push(
2983 log, indent,
2984 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
2985 len);
2986 return 1;
2987 }
2988
2989 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2990
2991 uint16_t entry = stream_getw(s);
2992 rv->overload = entry & ISIS_MT_OL_MASK;
2993 rv->attached = entry & ISIS_MT_AT_MASK;
2994 rv->mtid = entry & ISIS_MT_MASK;
2995
2996 format_item_mt_router_info(mtid, (struct isis_item *)rv, log, NULL,
2997 indent + 2);
2998 append_item(&tlvs->mt_router_info, (struct isis_item *)rv);
2999 return 0;
3000 }
3001
3002 /* Functions related to TLV 134 TE Router ID */
3003
3004 static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id)
3005 {
3006 if (!id)
3007 return NULL;
3008
3009 struct in_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3010 memcpy(rv, id, sizeof(*rv));
3011 return rv;
3012 }
3013
3014 static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
3015 struct json_object *json, int indent)
3016 {
3017 if (!id)
3018 return;
3019
3020 char addrbuf[INET_ADDRSTRLEN];
3021 inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
3022 if (json)
3023 json_object_string_add(json, "te-router-id", addrbuf);
3024 else
3025 sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
3026 }
3027
3028 static void free_tlv_te_router_id(struct in_addr *id)
3029 {
3030 XFREE(MTYPE_ISIS_TLV, id);
3031 }
3032
3033 static int pack_tlv_te_router_id(const struct in_addr *id, struct stream *s)
3034 {
3035 if (!id)
3036 return 0;
3037
3038 if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
3039 return 1;
3040
3041 stream_putc(s, ISIS_TLV_TE_ROUTER_ID);
3042 stream_putc(s, 4);
3043 stream_put(s, id, 4);
3044 return 0;
3045 }
3046
3047 static int unpack_tlv_te_router_id(enum isis_tlv_context context,
3048 uint8_t tlv_type, uint8_t tlv_len,
3049 struct stream *s, struct sbuf *log,
3050 void *dest, int indent)
3051 {
3052 struct isis_tlvs *tlvs = dest;
3053
3054 sbuf_push(log, indent, "Unpacking TE Router ID TLV...\n");
3055 if (tlv_len != 4) {
3056 sbuf_push(log, indent, "WARNING: Length invalid\n");
3057 return 1;
3058 }
3059
3060 if (tlvs->te_router_id) {
3061 sbuf_push(log, indent,
3062 "WARNING: TE Router ID present multiple times.\n");
3063 stream_forward_getp(s, tlv_len);
3064 return 0;
3065 }
3066
3067 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4);
3068 stream_get(tlvs->te_router_id, s, 4);
3069 format_tlv_te_router_id(tlvs->te_router_id, log, NULL, indent + 2);
3070 return 0;
3071 }
3072
3073
3074 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
3075
3076 static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
3077 {
3078 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
3079 struct isis_extended_ip_reach *rv =
3080 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3081
3082 rv->metric = r->metric;
3083 rv->down = r->down;
3084 rv->prefix = r->prefix;
3085 rv->subtlvs = copy_subtlvs(r->subtlvs);
3086
3087 return (struct isis_item *)rv;
3088 }
3089
3090 static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
3091 struct sbuf *buf,
3092 struct json_object *json, int indent)
3093 {
3094 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
3095 char prefixbuf[PREFIX2STR_BUFFER];
3096
3097 if (json) {
3098 struct json_object *ext_json;
3099 ext_json = json_object_new_object();
3100 json_object_object_add(json, "ext-ip-reach", ext_json);
3101 json_object_string_add(
3102 json, "mt-id",
3103 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT");
3104 json_object_string_add(
3105 json, "ip-reach",
3106 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
3107 json_object_int_add(json, "ip-reach-metric", r->metric);
3108 json_object_string_add(json, "down", r->down ? "yes" : "");
3109 if (mtid != ISIS_MT_IPV4_UNICAST)
3110 json_object_string_add(json, "mt-name",
3111 isis_mtid2str(mtid));
3112 if (r->subtlvs) {
3113 struct json_object *subtlv_json;
3114 subtlv_json = json_object_new_object();
3115 json_object_object_add(json, "subtlvs", subtlv_json);
3116 format_subtlvs(r->subtlvs, NULL, subtlv_json, 0);
3117 }
3118 } else {
3119 sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
3120 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
3121 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
3122 r->metric, r->down ? " Down" : "");
3123 if (mtid != ISIS_MT_IPV4_UNICAST)
3124 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
3125 sbuf_push(buf, 0, "\n");
3126
3127 if (r->subtlvs) {
3128 sbuf_push(buf, indent, " Subtlvs:\n");
3129 format_subtlvs(r->subtlvs, buf, NULL, indent + 4);
3130 }
3131 }
3132 }
3133
3134 static void free_item_extended_ip_reach(struct isis_item *i)
3135 {
3136 struct isis_extended_ip_reach *item =
3137 (struct isis_extended_ip_reach *)i;
3138 isis_free_subtlvs(item->subtlvs);
3139 XFREE(MTYPE_ISIS_TLV, item);
3140 }
3141
3142 static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s,
3143 size_t *min_len)
3144 {
3145 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
3146 uint8_t control;
3147
3148 if (STREAM_WRITEABLE(s) < 5) {
3149 *min_len = 5;
3150 return 1;
3151 }
3152 stream_putl(s, r->metric);
3153
3154 control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
3155 control |= r->prefix.prefixlen;
3156 control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
3157
3158 stream_putc(s, control);
3159
3160 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) {
3161 *min_len = 5 + (unsigned)PSIZE(r->prefix.prefixlen);
3162 return 1;
3163 }
3164 stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
3165
3166 if (r->subtlvs)
3167 return pack_subtlvs(r->subtlvs, s);
3168 return 0;
3169 }
3170
3171 static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
3172 struct stream *s, struct sbuf *log,
3173 void *dest, int indent)
3174 {
3175 struct isis_tlvs *tlvs = dest;
3176 struct isis_extended_ip_reach *rv = NULL;
3177 size_t consume;
3178 uint8_t control, subtlv_len;
3179 struct isis_item_list *items;
3180
3181 if (mtid == ISIS_MT_IPV4_UNICAST) {
3182 items = &tlvs->extended_ip_reach;
3183 } else {
3184 items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid);
3185 }
3186
3187 sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n",
3188 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
3189
3190 consume = 5;
3191 if (len < consume) {
3192 sbuf_push(log, indent,
3193 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
3194 len);
3195 goto out;
3196 }
3197
3198 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3199
3200 rv->metric = stream_getl(s);
3201 control = stream_getc(s);
3202 rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN);
3203 rv->prefix.family = AF_INET;
3204 rv->prefix.prefixlen = control & 0x3f;
3205 if (rv->prefix.prefixlen > IPV4_MAX_BITLEN) {
3206 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n",
3207 rv->prefix.prefixlen);
3208 goto out;
3209 }
3210
3211 consume += PSIZE(rv->prefix.prefixlen);
3212 if (len < consume) {
3213 sbuf_push(log, indent,
3214 "Expected %u bytes of prefix, but only %u bytes available.\n",
3215 PSIZE(rv->prefix.prefixlen), len - 5);
3216 goto out;
3217 }
3218 stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
3219 in_addr_t orig_prefix = rv->prefix.prefix.s_addr;
3220 apply_mask_ipv4(&rv->prefix);
3221 if (orig_prefix != rv->prefix.prefix.s_addr)
3222 sbuf_push(log, indent + 2,
3223 "WARNING: Prefix had hostbits set.\n");
3224 format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, NULL,
3225 indent + 2);
3226
3227 if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
3228 consume += 1;
3229 if (len < consume) {
3230 sbuf_push(log, indent,
3231 "Expected 1 byte of subtlv len, but no more data present.\n");
3232 goto out;
3233 }
3234 subtlv_len = stream_getc(s);
3235
3236 if (!subtlv_len) {
3237 sbuf_push(log, indent + 2,
3238 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
3239 }
3240 consume += subtlv_len;
3241 if (len < consume) {
3242 sbuf_push(log, indent,
3243 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3244 subtlv_len,
3245 len - 6 - PSIZE(rv->prefix.prefixlen));
3246 goto out;
3247 }
3248
3249 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
3250 bool unpacked_known_tlvs = false;
3251
3252 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
3253 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
3254 goto out;
3255 }
3256 if (!unpacked_known_tlvs) {
3257 isis_free_subtlvs(rv->subtlvs);
3258 rv->subtlvs = NULL;
3259 }
3260 }
3261
3262 append_item(items, (struct isis_item *)rv);
3263 return 0;
3264 out:
3265 if (rv)
3266 free_item_extended_ip_reach((struct isis_item *)rv);
3267 return 1;
3268 }
3269
3270 /* Functions related to TLV 137 Dynamic Hostname */
3271
3272 static char *copy_tlv_dynamic_hostname(const char *hostname)
3273 {
3274 if (!hostname)
3275 return NULL;
3276
3277 return XSTRDUP(MTYPE_ISIS_TLV, hostname);
3278 }
3279
3280 static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
3281 struct json_object *json, int indent)
3282 {
3283 if (!hostname)
3284 return;
3285
3286 if (json)
3287 json_object_string_add(json, "hostname", hostname);
3288 else
3289 sbuf_push(buf, indent, "Hostname: %s\n", hostname);
3290 }
3291
3292 static void free_tlv_dynamic_hostname(char *hostname)
3293 {
3294 XFREE(MTYPE_ISIS_TLV, hostname);
3295 }
3296
3297 static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s)
3298 {
3299 if (!hostname)
3300 return 0;
3301
3302 uint8_t name_len = strlen(hostname);
3303
3304 if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len))
3305 return 1;
3306
3307 stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME);
3308 stream_putc(s, name_len);
3309 stream_put(s, hostname, name_len);
3310 return 0;
3311 }
3312
3313 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
3314 uint8_t tlv_type, uint8_t tlv_len,
3315 struct stream *s, struct sbuf *log,
3316 void *dest, int indent)
3317 {
3318 struct isis_tlvs *tlvs = dest;
3319
3320 sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n");
3321 if (!tlv_len) {
3322 sbuf_push(log, indent, "WARNING: No hostname included\n");
3323 return 0;
3324 }
3325
3326 if (tlvs->hostname) {
3327 sbuf_push(log, indent,
3328 "WARNING: Hostname present multiple times.\n");
3329 stream_forward_getp(s, tlv_len);
3330 return 0;
3331 }
3332
3333 tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1);
3334 stream_get(tlvs->hostname, s, tlv_len);
3335 tlvs->hostname[tlv_len] = '\0';
3336
3337 bool sane = true;
3338 for (uint8_t i = 0; i < tlv_len; i++) {
3339 if ((unsigned char)tlvs->hostname[i] > 127
3340 || !isprint((unsigned char)tlvs->hostname[i])) {
3341 sane = false;
3342 tlvs->hostname[i] = '?';
3343 }
3344 }
3345 if (!sane) {
3346 sbuf_push(
3347 log, indent,
3348 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
3349 }
3350
3351 return 0;
3352 }
3353
3354 /* Functions related to TLV 140 IPv6 TE Router ID */
3355
3356 static struct in6_addr *copy_tlv_te_router_id_ipv6(const struct in6_addr *id)
3357 {
3358 if (!id)
3359 return NULL;
3360
3361 struct in6_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3362 memcpy(rv, id, sizeof(*rv));
3363 return rv;
3364 }
3365
3366 static void format_tlv_te_router_id_ipv6(const struct in6_addr *id,
3367 struct sbuf *buf,
3368 struct json_object *json, int indent)
3369 {
3370 if (!id)
3371 return;
3372
3373 char addrbuf[INET6_ADDRSTRLEN];
3374 inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf));
3375 if (json)
3376 json_object_string_add(json, "ipv6-te-router-id", addrbuf);
3377 else
3378 sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf);
3379 }
3380
3381 static void free_tlv_te_router_id_ipv6(struct in6_addr *id)
3382 {
3383 XFREE(MTYPE_ISIS_TLV, id);
3384 }
3385
3386 static int pack_tlv_te_router_id_ipv6(const struct in6_addr *id,
3387 struct stream *s)
3388 {
3389 if (!id)
3390 return 0;
3391
3392 if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
3393 return 1;
3394
3395 stream_putc(s, ISIS_TLV_TE_ROUTER_ID_IPV6);
3396 stream_putc(s, IPV6_MAX_BYTELEN);
3397 stream_put(s, id, IPV6_MAX_BYTELEN);
3398 return 0;
3399 }
3400
3401 static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context,
3402 uint8_t tlv_type, uint8_t tlv_len,
3403 struct stream *s, struct sbuf *log,
3404 void *dest, int indent)
3405 {
3406 struct isis_tlvs *tlvs = dest;
3407
3408 sbuf_push(log, indent, "Unpacking IPv6 TE Router ID TLV...\n");
3409 if (tlv_len != IPV6_MAX_BYTELEN) {
3410 sbuf_push(log, indent, "WARNING: Length invalid\n");
3411 return 1;
3412 }
3413
3414 if (tlvs->te_router_id_ipv6) {
3415 sbuf_push(
3416 log, indent,
3417 "WARNING: IPv6 TE Router ID present multiple times.\n");
3418 stream_forward_getp(s, tlv_len);
3419 return 0;
3420 }
3421
3422 tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, IPV6_MAX_BYTELEN);
3423 stream_get(tlvs->te_router_id_ipv6, s, IPV6_MAX_BYTELEN);
3424 format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, NULL, indent + 2);
3425 return 0;
3426 }
3427
3428
3429 /* Functions related to TLV 150 Spine-Leaf-Extension */
3430
3431 static struct isis_spine_leaf *copy_tlv_spine_leaf(
3432 const struct isis_spine_leaf *spine_leaf)
3433 {
3434 if (!spine_leaf)
3435 return NULL;
3436
3437 struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3438 memcpy(rv, spine_leaf, sizeof(*rv));
3439
3440 return rv;
3441 }
3442
3443 static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
3444 struct sbuf *buf, struct json_object *json,
3445 int indent)
3446 {
3447 if (!spine_leaf)
3448 return;
3449
3450 char aux_buf[255];
3451
3452 if (json) {
3453 struct json_object *spine_json;
3454 spine_json = json_object_new_object();
3455 json_object_object_add(json, "spine-leaf-extension",
3456 spine_json);
3457 if (spine_leaf->has_tier) {
3458 snprintfrr(aux_buf, sizeof(aux_buf), "%hhu",
3459 spine_leaf->tier);
3460 json_object_string_add(
3461 spine_json, "tier",
3462 (spine_leaf->tier == ISIS_TIER_UNDEFINED)
3463 ? "undefined"
3464 : aux_buf);
3465 }
3466 json_object_string_add(spine_json, "flag-leaf",
3467 spine_leaf->is_leaf ? "yes" : "");
3468 json_object_string_add(spine_json, "flag-spine",
3469 spine_leaf->is_spine ? "yes" : "");
3470 json_object_string_add(spine_json, "flag-backup",
3471 spine_leaf->is_backup ? "yes" : "");
3472 } else {
3473 sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
3474 if (spine_leaf->has_tier) {
3475 if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
3476 sbuf_push(buf, indent, " Tier: undefined\n");
3477 } else {
3478 sbuf_push(buf, indent, " Tier: %hhu\n",
3479 spine_leaf->tier);
3480 }
3481 }
3482
3483 sbuf_push(buf, indent, " Flags:%s%s%s\n",
3484 spine_leaf->is_leaf ? " LEAF" : "",
3485 spine_leaf->is_spine ? " SPINE" : "",
3486 spine_leaf->is_backup ? " BACKUP" : "");
3487 }
3488 }
3489
3490 static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
3491 {
3492 XFREE(MTYPE_ISIS_TLV, spine_leaf);
3493 }
3494
3495 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
3496 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
3497 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
3498 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
3499
3500 static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
3501 struct stream *s)
3502 {
3503 if (!spine_leaf)
3504 return 0;
3505
3506 uint8_t tlv_len = 2;
3507
3508 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
3509 return 1;
3510
3511 stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
3512 stream_putc(s, tlv_len);
3513
3514 uint16_t spine_leaf_flags = 0;
3515
3516 if (spine_leaf->has_tier) {
3517 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
3518 spine_leaf_flags |= spine_leaf->tier << 12;
3519 }
3520
3521 if (spine_leaf->is_leaf)
3522 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
3523
3524 if (spine_leaf->is_spine)
3525 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
3526
3527 if (spine_leaf->is_backup)
3528 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
3529
3530 stream_putw(s, spine_leaf_flags);
3531
3532 return 0;
3533 }
3534
3535 static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
3536 uint8_t tlv_type, uint8_t tlv_len,
3537 struct stream *s, struct sbuf *log,
3538 void *dest, int indent)
3539 {
3540 struct isis_tlvs *tlvs = dest;
3541
3542 sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
3543 if (tlv_len < 2) {
3544 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
3545 stream_forward_getp(s, tlv_len);
3546 return 0;
3547 }
3548
3549 if (tlvs->spine_leaf) {
3550 sbuf_push(log, indent,
3551 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
3552 stream_forward_getp(s, tlv_len);
3553 return 0;
3554 }
3555
3556 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
3557
3558 uint16_t spine_leaf_flags = stream_getw(s);
3559
3560 if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
3561 tlvs->spine_leaf->has_tier = true;
3562 tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
3563 }
3564
3565 tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
3566 tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
3567 tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
3568
3569 stream_forward_getp(s, tlv_len - 2);
3570 return 0;
3571 }
3572
3573 /* Functions related to TLV 240 P2P Three-Way Adjacency */
3574
3575 const char *isis_threeway_state_name(enum isis_threeway_state state)
3576 {
3577 switch (state) {
3578 case ISIS_THREEWAY_DOWN:
3579 return "Down";
3580 case ISIS_THREEWAY_INITIALIZING:
3581 return "Initializing";
3582 case ISIS_THREEWAY_UP:
3583 return "Up";
3584 default:
3585 return "Invalid!";
3586 }
3587 }
3588
3589 static struct isis_threeway_adj *copy_tlv_threeway_adj(
3590 const struct isis_threeway_adj *threeway_adj)
3591 {
3592 if (!threeway_adj)
3593 return NULL;
3594
3595 struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3596 memcpy(rv, threeway_adj, sizeof(*rv));
3597
3598 return rv;
3599 }
3600
3601 static void
3602 format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
3603 struct sbuf *buf, struct json_object *json, int indent)
3604 {
3605 char sys_id[ISO_SYSID_STRLEN];
3606
3607 if (!threeway_adj)
3608 return;
3609
3610 snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", threeway_adj->neighbor_id);
3611 if (json) {
3612 struct json_object *three_json;
3613 three_json = json_object_new_object();
3614 json_object_object_add(json, "p2p-three-way-adj", three_json);
3615 json_object_string_add(
3616 three_json, "state-name",
3617 isis_threeway_state_name(threeway_adj->state));
3618 json_object_int_add(three_json, "state", threeway_adj->state);
3619 json_object_int_add(three_json, "ext-local-circuit-id",
3620 threeway_adj->local_circuit_id);
3621 if (!threeway_adj->neighbor_set)
3622 return;
3623 json_object_string_add(three_json, "neigh-system-id", sys_id);
3624 json_object_int_add(three_json, "neigh-ext-circuit-id",
3625 threeway_adj->neighbor_circuit_id);
3626 } else {
3627 sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
3628 sbuf_push(buf, indent, " State: %s (%d)\n",
3629 isis_threeway_state_name(threeway_adj->state),
3630 threeway_adj->state);
3631 sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n",
3632 threeway_adj->local_circuit_id);
3633 if (!threeway_adj->neighbor_set)
3634 return;
3635
3636 sbuf_push(buf, indent, " Neighbor System ID: %s\n", sys_id);
3637 sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n",
3638 threeway_adj->neighbor_circuit_id);
3639 }
3640 }
3641
3642 static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
3643 {
3644 XFREE(MTYPE_ISIS_TLV, threeway_adj);
3645 }
3646
3647 static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
3648 struct stream *s)
3649 {
3650 if (!threeway_adj)
3651 return 0;
3652
3653 uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5;
3654
3655 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
3656 return 1;
3657
3658 stream_putc(s, ISIS_TLV_THREE_WAY_ADJ);
3659 stream_putc(s, tlv_len);
3660 stream_putc(s, threeway_adj->state);
3661 stream_putl(s, threeway_adj->local_circuit_id);
3662
3663 if (threeway_adj->neighbor_set) {
3664 stream_put(s, threeway_adj->neighbor_id, 6);
3665 stream_putl(s, threeway_adj->neighbor_circuit_id);
3666 }
3667
3668 return 0;
3669 }
3670
3671 static int unpack_tlv_threeway_adj(enum isis_tlv_context context,
3672 uint8_t tlv_type, uint8_t tlv_len,
3673 struct stream *s, struct sbuf *log,
3674 void *dest, int indent)
3675 {
3676 struct isis_tlvs *tlvs = dest;
3677
3678 sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n");
3679 if (tlv_len != 5 && tlv_len != 15) {
3680 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
3681 stream_forward_getp(s, tlv_len);
3682 return 0;
3683 }
3684
3685 if (tlvs->threeway_adj) {
3686 sbuf_push(log, indent,
3687 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
3688 stream_forward_getp(s, tlv_len);
3689 return 0;
3690 }
3691
3692 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
3693
3694 tlvs->threeway_adj->state = stream_getc(s);
3695 tlvs->threeway_adj->local_circuit_id = stream_getl(s);
3696
3697 if (tlv_len == 15) {
3698 tlvs->threeway_adj->neighbor_set = true;
3699 stream_get(tlvs->threeway_adj->neighbor_id, s, 6);
3700 tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s);
3701 }
3702
3703 return 0;
3704 }
3705
3706 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
3707 static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
3708 {
3709 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
3710 struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3711
3712 rv->metric = r->metric;
3713 rv->down = r->down;
3714 rv->external = r->external;
3715 rv->prefix = r->prefix;
3716 rv->subtlvs = copy_subtlvs(r->subtlvs);
3717
3718 return (struct isis_item *)rv;
3719 }
3720
3721 static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
3722 struct sbuf *buf, struct json_object *json,
3723 int indent)
3724 {
3725 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
3726 char prefixbuf[PREFIX2STR_BUFFER];
3727
3728 if (json) {
3729 struct json_object *reach_json;
3730 reach_json = json_object_new_object();
3731 json_object_object_add(json, "ipv6-reach", reach_json);
3732 json_object_string_add(reach_json, "mt-id",
3733 (mtid == ISIS_MT_IPV4_UNICAST) ? ""
3734 : "mt");
3735 json_object_string_add(
3736 reach_json, "prefix",
3737 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
3738 json_object_int_add(reach_json, "metric", r->metric);
3739 json_object_string_add(reach_json, "down",
3740 r->down ? "yes" : "");
3741 json_object_string_add(reach_json, "external",
3742 r->external ? "yes" : "");
3743 if (mtid != ISIS_MT_IPV4_UNICAST)
3744 json_object_string_add(reach_json, "mt-name",
3745 isis_mtid2str(mtid));
3746 if (r->subtlvs) {
3747 struct json_object *subtlvs_json;
3748 subtlvs_json = json_object_new_object();
3749 json_object_object_add(json, "subtlvs", subtlvs_json);
3750 format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0);
3751 }
3752 } else {
3753 sbuf_push(buf, indent,
3754 "%sIPv6 Reachability: %s (Metric: %u)%s%s",
3755 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
3756 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
3757 r->metric, r->down ? " Down" : "",
3758 r->external ? " External" : "");
3759 if (mtid != ISIS_MT_IPV4_UNICAST)
3760 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
3761 sbuf_push(buf, 0, "\n");
3762
3763 if (r->subtlvs) {
3764 sbuf_push(buf, indent, " Subtlvs:\n");
3765 format_subtlvs(r->subtlvs, buf, NULL, indent + 4);
3766 }
3767 }
3768 }
3769
3770 static void free_item_ipv6_reach(struct isis_item *i)
3771 {
3772 struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i;
3773
3774 isis_free_subtlvs(item->subtlvs);
3775 XFREE(MTYPE_ISIS_TLV, item);
3776 }
3777
3778 static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s,
3779 size_t *min_len)
3780 {
3781 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
3782 uint8_t control;
3783
3784 if (STREAM_WRITEABLE(s) < 6 + (unsigned)PSIZE(r->prefix.prefixlen)) {
3785 *min_len = 6 + (unsigned)PSIZE(r->prefix.prefixlen);
3786 return 1;
3787 }
3788 stream_putl(s, r->metric);
3789
3790 control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
3791 control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0;
3792 control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0;
3793
3794 stream_putc(s, control);
3795 stream_putc(s, r->prefix.prefixlen);
3796
3797 stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
3798
3799 if (r->subtlvs)
3800 return pack_subtlvs(r->subtlvs, s);
3801
3802 return 0;
3803 }
3804
3805 static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
3806 struct sbuf *log, void *dest, int indent)
3807 {
3808 struct isis_tlvs *tlvs = dest;
3809 struct isis_ipv6_reach *rv = NULL;
3810 size_t consume;
3811 uint8_t control, subtlv_len;
3812 struct isis_item_list *items;
3813
3814 if (mtid == ISIS_MT_IPV4_UNICAST) {
3815 items = &tlvs->ipv6_reach;
3816 } else {
3817 items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
3818 }
3819
3820 sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n",
3821 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
3822 consume = 6;
3823 if (len < consume) {
3824 sbuf_push(log, indent,
3825 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
3826 len);
3827 goto out;
3828 }
3829
3830 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3831
3832 rv->metric = stream_getl(s);
3833 control = stream_getc(s);
3834 rv->down = (control & ISIS_IPV6_REACH_DOWN);
3835 rv->external = (control & ISIS_IPV6_REACH_EXTERNAL);
3836
3837 rv->prefix.family = AF_INET6;
3838 rv->prefix.prefixlen = stream_getc(s);
3839 if (rv->prefix.prefixlen > IPV6_MAX_BITLEN) {
3840 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
3841 rv->prefix.prefixlen);
3842 goto out;
3843 }
3844
3845 consume += PSIZE(rv->prefix.prefixlen);
3846 if (len < consume) {
3847 sbuf_push(log, indent,
3848 "Expected %u bytes of prefix, but only %u bytes available.\n",
3849 PSIZE(rv->prefix.prefixlen), len - 6);
3850 goto out;
3851 }
3852 stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
3853 struct in6_addr orig_prefix = rv->prefix.prefix;
3854
3855 apply_mask_ipv6(&rv->prefix);
3856 if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
3857 sbuf_push(log, indent + 2,
3858 "WARNING: Prefix had hostbits set.\n");
3859 format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
3860
3861 if (control & ISIS_IPV6_REACH_SUBTLV) {
3862 consume += 1;
3863 if (len < consume) {
3864 sbuf_push(log, indent,
3865 "Expected 1 byte of subtlv len, but no more data persent.\n");
3866 goto out;
3867 }
3868 subtlv_len = stream_getc(s);
3869
3870 if (!subtlv_len) {
3871 sbuf_push(log, indent + 2,
3872 " WARNING: subtlv bit set, but there are no subtlvs.\n");
3873 }
3874 consume += subtlv_len;
3875 if (len < consume) {
3876 sbuf_push(log, indent,
3877 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
3878 subtlv_len,
3879 len - 6 - PSIZE(rv->prefix.prefixlen));
3880 goto out;
3881 }
3882
3883 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
3884 bool unpacked_known_tlvs = false;
3885
3886 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
3887 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
3888 goto out;
3889 }
3890 if (!unpacked_known_tlvs) {
3891 isis_free_subtlvs(rv->subtlvs);
3892 rv->subtlvs = NULL;
3893 }
3894 }
3895
3896 append_item(items, (struct isis_item *)rv);
3897 return 0;
3898 out:
3899 if (rv)
3900 free_item_ipv6_reach((struct isis_item *)rv);
3901 return 1;
3902 }
3903
3904 /* Functions related to TLV 242 Router Capability as per RFC7981 */
3905 static struct isis_router_cap *copy_tlv_router_cap(
3906 const struct isis_router_cap *router_cap)
3907 {
3908 struct isis_router_cap *rv;
3909
3910 if (!router_cap)
3911 return NULL;
3912
3913 rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3914
3915 memcpy(rv, router_cap, sizeof(*rv));
3916
3917 #ifndef FABRICD
3918 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
3919 struct isis_router_cap_fad *sc_fad;
3920 struct isis_router_cap_fad *rv_fad;
3921
3922 sc_fad = router_cap->fads[i];
3923 if (!sc_fad)
3924 continue;
3925 rv_fad = XMALLOC(MTYPE_ISIS_TLV,
3926 sizeof(struct isis_router_cap_fad));
3927 *rv_fad = *sc_fad;
3928 rv_fad->fad.admin_group_exclude_any.bitmap.data = NULL;
3929 rv_fad->fad.admin_group_include_any.bitmap.data = NULL;
3930 rv_fad->fad.admin_group_include_all.bitmap.data = NULL;
3931
3932 assert(bf_is_inited(
3933 sc_fad->fad.admin_group_exclude_any.bitmap));
3934 assert(bf_is_inited(
3935 sc_fad->fad.admin_group_include_any.bitmap));
3936 assert(bf_is_inited(
3937 sc_fad->fad.admin_group_include_all.bitmap));
3938
3939 admin_group_copy(&rv_fad->fad.admin_group_exclude_any,
3940 &sc_fad->fad.admin_group_exclude_any);
3941 admin_group_copy(&rv_fad->fad.admin_group_include_any,
3942 &sc_fad->fad.admin_group_include_any);
3943 admin_group_copy(&rv_fad->fad.admin_group_include_all,
3944 &sc_fad->fad.admin_group_include_all);
3945
3946 rv->fads[i] = rv_fad;
3947 }
3948 #endif /* ifndef FABRICD */
3949
3950 return rv;
3951 }
3952
3953 static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap,
3954 struct json_object *json)
3955 {
3956 char addrbuf[INET_ADDRSTRLEN];
3957
3958 if (!router_cap)
3959 return;
3960
3961 /* Router ID and Flags */
3962 struct json_object *cap_json;
3963 cap_json = json_object_new_object();
3964 json_object_object_add(json, "router-capability", cap_json);
3965 inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
3966 json_object_string_add(cap_json, "id", addrbuf);
3967 json_object_string_add(
3968 cap_json, "flag-d",
3969 router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? "1" : "0");
3970 json_object_string_add(
3971 cap_json, "flag-s",
3972 router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0");
3973
3974 /* Segment Routing Global Block as per RFC8667 section #3.1 */
3975 if (router_cap->srgb.range_size != 0) {
3976 struct json_object *gb_json;
3977 gb_json = json_object_new_object();
3978 json_object_object_add(json, "segment-routing-gb", gb_json);
3979 json_object_string_add(gb_json, "ipv4",
3980 IS_SR_IPV4(&router_cap->srgb) ? "1"
3981 : "0");
3982 json_object_string_add(gb_json, "ipv6",
3983 IS_SR_IPV6(&router_cap->srgb) ? "1"
3984 : "0");
3985 json_object_int_add(gb_json, "global-block-base",
3986 router_cap->srgb.lower_bound);
3987 json_object_int_add(gb_json, "global-block-range",
3988 router_cap->srgb.range_size);
3989 }
3990
3991 /* Segment Routing Local Block as per RFC8667 section #3.3 */
3992 if (router_cap->srlb.range_size != 0) {
3993 struct json_object *lb_json;
3994 lb_json = json_object_new_object();
3995 json_object_object_add(json, "segment-routing-lb", lb_json);
3996 json_object_int_add(lb_json, "global-block-base",
3997 router_cap->srlb.lower_bound);
3998 json_object_int_add(lb_json, "global-block-range",
3999 router_cap->srlb.range_size);
4000 }
4001
4002 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
4003 if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
4004 char buf[255];
4005 struct json_object *alg_json;
4006 alg_json = json_object_new_object();
4007 json_object_object_add(json, "segment-routing-algorithm",
4008 alg_json);
4009 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
4010 if (router_cap->algo[i] != SR_ALGORITHM_UNSET) {
4011 snprintfrr(buf, sizeof(buf), "%d", i);
4012 json_object_string_add(alg_json, buf,
4013 router_cap->algo[i] == 0
4014 ? "SPF"
4015 : "Strict SPF");
4016 }
4017 }
4018
4019 /* Segment Routing Node MSD as per RFC8491 section #2 */
4020 if (router_cap->msd != 0)
4021 json_object_int_add(json, "msd", router_cap->msd);
4022 }
4023
4024 static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
4025 struct sbuf *buf, int indent)
4026 {
4027 char addrbuf[INET_ADDRSTRLEN];
4028
4029 if (!router_cap)
4030 return;
4031
4032 /* Router ID and Flags */
4033 inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
4034 sbuf_push(buf, indent, "Router Capability:");
4035 sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf,
4036 router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
4037 router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
4038
4039 /* Segment Routing Global Block as per RFC8667 section #3.1 */
4040 if (router_cap->srgb.range_size != 0)
4041 sbuf_push(
4042 buf, indent,
4043 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
4044 IS_SR_IPV4(&router_cap->srgb) ? "1" : "0",
4045 IS_SR_IPV6(&router_cap->srgb) ? "1" : "0",
4046 router_cap->srgb.lower_bound,
4047 router_cap->srgb.range_size);
4048
4049 /* Segment Routing Local Block as per RFC8667 section #3.3 */
4050 if (router_cap->srlb.range_size != 0)
4051 sbuf_push(buf, indent, " SR Local Block Base: %u Range: %u\n",
4052 router_cap->srlb.lower_bound,
4053 router_cap->srlb.range_size);
4054
4055 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
4056 if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
4057 sbuf_push(buf, indent, " SR Algorithm:\n");
4058 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
4059 if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
4060 sbuf_push(buf, indent, " %u: %s\n", i,
4061 sr_algorithm_string(
4062 router_cap->algo[i]));
4063 }
4064
4065 /* Segment Routing Node MSD as per RFC8491 section #2 */
4066 if (router_cap->msd != 0)
4067 sbuf_push(buf, indent, " Node Maximum SID Depth: %u\n",
4068 router_cap->msd);
4069
4070 #ifndef FABRICD
4071 /* Flex-Algo */
4072 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
4073 char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE];
4074 int indent2;
4075 struct admin_group *admin_group;
4076 struct isis_router_cap_fad *fad;
4077
4078 fad = router_cap->fads[i];
4079 if (!fad)
4080 continue;
4081
4082 sbuf_push(buf, indent, " Flex-Algo Definition: %d\n",
4083 fad->fad.algorithm);
4084 sbuf_push(buf, indent, " Metric-Type: %d\n",
4085 fad->fad.metric_type);
4086 sbuf_push(buf, indent, " Calc-Type: %d\n",
4087 fad->fad.calc_type);
4088 sbuf_push(buf, indent, " Priority: %d\n", fad->fad.priority);
4089
4090 indent2 = indent + strlen(" Exclude-Any: ");
4091 admin_group = &fad->fad.admin_group_exclude_any;
4092 sbuf_push(buf, indent, " Exclude-Any: ");
4093 sbuf_push(buf, 0, "%s\n",
4094 admin_group_string(admin_group_buf,
4095 ADMIN_GROUP_PRINT_MAX_SIZE,
4096 indent2, admin_group));
4097
4098 indent2 = indent + strlen(" Include-Any: ");
4099 admin_group = &fad->fad.admin_group_include_any;
4100 sbuf_push(buf, indent, " Include-Any: ");
4101 sbuf_push(buf, 0, "%s\n",
4102 admin_group_string(admin_group_buf,
4103 ADMIN_GROUP_PRINT_MAX_SIZE,
4104 indent2, admin_group));
4105
4106 indent2 = indent + strlen(" Include-All: ");
4107 admin_group = &fad->fad.admin_group_include_all;
4108 sbuf_push(buf, indent, " Include-All: ");
4109 sbuf_push(buf, 0, "%s\n",
4110 admin_group_string(admin_group_buf,
4111 ADMIN_GROUP_PRINT_MAX_SIZE,
4112 indent2, admin_group));
4113
4114 sbuf_push(buf, indent, " M-Flag: %c\n",
4115 CHECK_FLAG(fad->fad.flags, FAD_FLAG_M) ? '1' : '0');
4116
4117 if (fad->fad.flags != 0 && fad->fad.flags != FAD_FLAG_M)
4118 sbuf_push(buf, indent, " Flags: 0x%x\n",
4119 fad->fad.flags);
4120 if (fad->fad.exclude_srlg)
4121 sbuf_push(buf, indent, " Exclude SRLG: Enabled\n");
4122 if (fad->fad.unsupported_subtlv)
4123 sbuf_push(buf, indent,
4124 " Got an unsupported sub-TLV: Yes\n");
4125 }
4126 #endif /* ifndef FABRICD */
4127 }
4128
4129 static void free_tlv_router_cap(struct isis_router_cap *router_cap)
4130 {
4131 if (!router_cap)
4132 return;
4133
4134 #ifndef FABRICD
4135 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
4136 struct isis_router_cap_fad *fad;
4137
4138 fad = router_cap->fads[i];
4139 if (!fad)
4140 continue;
4141 admin_group_term(&fad->fad.admin_group_exclude_any);
4142 admin_group_term(&fad->fad.admin_group_include_any);
4143 admin_group_term(&fad->fad.admin_group_include_all);
4144 XFREE(MTYPE_ISIS_TLV, fad);
4145 }
4146 #endif /* ifndef FABRICD */
4147
4148 XFREE(MTYPE_ISIS_TLV, router_cap);
4149 }
4150
4151 #ifndef FABRICD
4152 static size_t
4153 isis_router_cap_fad_sub_tlv_len(const struct isis_router_cap_fad *fad)
4154 {
4155 size_t sz = ISIS_SUBTLV_FAD_MIN_SIZE;
4156 uint32_t admin_group_length;
4157
4158 admin_group_length =
4159 admin_group_nb_words(&fad->fad.admin_group_exclude_any);
4160 if (admin_group_length)
4161 sz += sizeof(uint32_t) * admin_group_length + 2;
4162
4163 admin_group_length =
4164 admin_group_nb_words(&fad->fad.admin_group_include_any);
4165 if (admin_group_length)
4166 sz += sizeof(uint32_t) * admin_group_length + 2;
4167
4168 admin_group_length =
4169 admin_group_nb_words(&fad->fad.admin_group_include_all);
4170 if (admin_group_length)
4171 sz += sizeof(uint32_t) * admin_group_length + 2;
4172
4173 if (fad->fad.flags != 0)
4174 sz += ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE + 2;
4175
4176 /* TODO: add exclude SRLG sub-sub-TLV length when supported */
4177
4178 return sz;
4179 }
4180 #endif /* ifndef FABRICD */
4181
4182 static size_t isis_router_cap_tlv_size(const struct isis_router_cap *router_cap)
4183 {
4184 size_t sz = 2 + ISIS_ROUTER_CAP_SIZE;
4185 #ifndef FABRICD
4186 size_t fad_sz;
4187 #endif /* ifndef FABRICD */
4188 int nb_algo;
4189
4190 if ((router_cap->srgb.range_size != 0) &&
4191 (router_cap->srgb.lower_bound != 0)) {
4192 sz += 2 + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE;
4193 sz += 2 + ISIS_SUBTLV_SID_LABEL_SIZE;
4194
4195 nb_algo = isis_tlvs_sr_algo_count(router_cap);
4196 if (nb_algo != 0)
4197 sz += 2 + nb_algo;
4198
4199 if ((router_cap->srlb.range_size != 0) &&
4200 (router_cap->srlb.lower_bound != 0)) {
4201 sz += 2 + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE;
4202 sz += 2 + ISIS_SUBTLV_SID_LABEL_SIZE;
4203 }
4204
4205 if (router_cap->msd != 0)
4206 sz += 2 + ISIS_SUBTLV_NODE_MSD_SIZE;
4207 }
4208
4209 #ifndef FABRICD
4210 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
4211 if (!router_cap->fads[i])
4212 continue;
4213 fad_sz = 2 +
4214 isis_router_cap_fad_sub_tlv_len(router_cap->fads[i]);
4215 if (((sz + fad_sz) % 256) < (sz % 256))
4216 sz += 2 + ISIS_ROUTER_CAP_SIZE + fad_sz;
4217 else
4218 sz += fad_sz;
4219 }
4220 #endif /* ifndef FABRICD */
4221
4222 return sz;
4223 }
4224
4225 static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
4226 struct stream *s)
4227 {
4228 size_t tlv_len, len_pos;
4229 uint8_t nb_algo;
4230
4231 if (!router_cap)
4232 return 0;
4233
4234 if (STREAM_WRITEABLE(s) < isis_router_cap_tlv_size(router_cap))
4235 return 1;
4236
4237 /* Add Router Capability TLV 242 with Router ID and Flags */
4238 stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
4239 len_pos = stream_get_endp(s);
4240 stream_putc(s, 0); /* Real length will be adjusted later */
4241 stream_put_ipv4(s, router_cap->router_id.s_addr);
4242 stream_putc(s, router_cap->flags);
4243
4244 /* Add SRGB if set as per RFC8667 section #3.1 */
4245 if ((router_cap->srgb.range_size != 0)
4246 && (router_cap->srgb.lower_bound != 0)) {
4247 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
4248 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
4249 stream_putc(s, router_cap->srgb.flags);
4250 stream_put3(s, router_cap->srgb.range_size);
4251 stream_putc(s, ISIS_SUBTLV_SID_LABEL);
4252 stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
4253 stream_put3(s, router_cap->srgb.lower_bound);
4254
4255 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
4256 nb_algo = isis_tlvs_sr_algo_count(router_cap);
4257 if (nb_algo > 0) {
4258 stream_putc(s, ISIS_SUBTLV_ALGORITHM);
4259 stream_putc(s, nb_algo);
4260 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
4261 if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
4262 stream_putc(s, router_cap->algo[i]);
4263 }
4264
4265 /* Local Block if defined as per RFC8667 section #3.3 */
4266 if ((router_cap->srlb.range_size != 0)
4267 && (router_cap->srlb.lower_bound != 0)) {
4268 stream_putc(s, ISIS_SUBTLV_SRLB);
4269 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
4270 /* No Flags are defined for SRLB */
4271 stream_putc(s, 0);
4272 stream_put3(s, router_cap->srlb.range_size);
4273 stream_putc(s, ISIS_SUBTLV_SID_LABEL);
4274 stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
4275 stream_put3(s, router_cap->srlb.lower_bound);
4276 }
4277
4278 /* And finish with MSD if set as per RFC8491 section #2 */
4279 if (router_cap->msd != 0) {
4280 stream_putc(s, ISIS_SUBTLV_NODE_MSD);
4281 stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
4282 stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION);
4283 stream_putc(s, router_cap->msd);
4284 }
4285 }
4286
4287 #ifndef FABRICD
4288 /* Flex Algo Definitions */
4289 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
4290 struct isis_router_cap_fad *fad;
4291 size_t subtlv_len;
4292 struct admin_group *ag;
4293 uint32_t admin_group_length;
4294
4295 fad = router_cap->fads[i];
4296 if (!fad)
4297 continue;
4298
4299 subtlv_len = isis_router_cap_fad_sub_tlv_len(fad);
4300
4301 if ((stream_get_endp(s) - len_pos - 1) > 250) {
4302 /* Adjust TLV length which depends on subTLVs presence
4303 */
4304 tlv_len = stream_get_endp(s) - len_pos - 1;
4305 stream_putc_at(s, len_pos, tlv_len);
4306
4307 /* Add Router Capability TLV 242 with Router ID and
4308 * Flags
4309 */
4310 stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
4311 /* Real length will be adjusted later */
4312 len_pos = stream_get_endp(s);
4313 stream_putc(s, 0);
4314 stream_put_ipv4(s, router_cap->router_id.s_addr);
4315 stream_putc(s, router_cap->flags);
4316 }
4317
4318 stream_putc(s, ISIS_SUBTLV_FAD);
4319 stream_putc(s, subtlv_len); /* length will be filled later */
4320
4321 stream_putc(s, fad->fad.algorithm);
4322 stream_putc(s, fad->fad.metric_type);
4323 stream_putc(s, fad->fad.calc_type);
4324 stream_putc(s, fad->fad.priority);
4325
4326 ag = &fad->fad.admin_group_exclude_any;
4327 admin_group_length = admin_group_nb_words(ag);
4328 if (admin_group_length) {
4329 stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG);
4330 stream_putc(s, sizeof(uint32_t) * admin_group_length);
4331 for (size_t i = 0; i < admin_group_length; i++)
4332 stream_putl(s, admin_group_get_offset(ag, i));
4333 }
4334
4335 ag = &fad->fad.admin_group_include_any;
4336 admin_group_length = admin_group_nb_words(ag);
4337 if (admin_group_length) {
4338 stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG);
4339 stream_putc(s, sizeof(uint32_t) * admin_group_length);
4340 for (size_t i = 0; i < admin_group_length; i++)
4341 stream_putl(s, admin_group_get_offset(ag, i));
4342 }
4343
4344 ag = &fad->fad.admin_group_include_all;
4345 admin_group_length = admin_group_nb_words(ag);
4346 if (admin_group_length) {
4347 stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG);
4348 stream_putc(s, sizeof(uint32_t) * admin_group_length);
4349 for (size_t i = 0; i < admin_group_length; i++)
4350 stream_putl(s, admin_group_get_offset(ag, i));
4351 }
4352
4353 if (fad->fad.flags != 0) {
4354 stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS);
4355 stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE);
4356 stream_putc(s, fad->fad.flags);
4357 }
4358 }
4359 #endif /* ifndef FABRICD */
4360
4361 /* Adjust TLV length which depends on subTLVs presence */
4362 tlv_len = stream_get_endp(s) - len_pos - 1;
4363 stream_putc_at(s, len_pos, tlv_len);
4364
4365 return 0;
4366 }
4367
4368 static int unpack_tlv_router_cap(enum isis_tlv_context context,
4369 uint8_t tlv_type, uint8_t tlv_len,
4370 struct stream *s, struct sbuf *log, void *dest,
4371 int indent)
4372 {
4373 struct isis_tlvs *tlvs = dest;
4374 struct isis_router_cap *rcap;
4375 uint8_t type;
4376 uint8_t length;
4377 uint8_t subtlv_len;
4378 uint8_t size;
4379
4380 sbuf_push(log, indent, "Unpacking Router Capability TLV...\n");
4381 if (tlv_len < ISIS_ROUTER_CAP_SIZE) {
4382 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
4383 stream_forward_getp(s, tlv_len);
4384 return 0;
4385 }
4386
4387 if (tlvs->router_cap)
4388 /* Multiple Router Capability found */
4389 rcap = tlvs->router_cap;
4390 else {
4391 /* Allocate router cap structure and initialize SR Algorithms */
4392 rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap));
4393 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
4394 rcap->algo[i] = SR_ALGORITHM_UNSET;
4395 }
4396
4397 /* Get Router ID and Flags */
4398 rcap->router_id.s_addr = stream_get_ipv4(s);
4399 rcap->flags = stream_getc(s);
4400
4401 /* Parse remaining part of the TLV if present */
4402 subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE;
4403 while (subtlv_len > 2) {
4404 #ifndef FABRICD
4405 struct isis_router_cap_fad *fad;
4406 uint8_t subsubtlvs_len;
4407 #endif /* ifndef FABRICD */
4408 uint8_t msd_type;
4409
4410 type = stream_getc(s);
4411 length = stream_getc(s);
4412
4413 if (length > STREAM_READABLE(s) || length > subtlv_len - 2) {
4414 sbuf_push(
4415 log, indent,
4416 "WARNING: Router Capability subTLV length too large compared to expected size\n");
4417 stream_forward_getp(s, STREAM_READABLE(s));
4418 XFREE(MTYPE_ISIS_TLV, rcap);
4419 return 0;
4420 }
4421
4422 switch (type) {
4423 case ISIS_SUBTLV_SID_LABEL_RANGE:
4424 /* Check that SRGB is correctly formated */
4425 if (length < SUBTLV_RANGE_LABEL_SIZE
4426 || length > SUBTLV_RANGE_INDEX_SIZE) {
4427 stream_forward_getp(s, length);
4428 break;
4429 }
4430 /* Only one SRGB is supported. Skip subsequent one */
4431 if (rcap->srgb.range_size != 0) {
4432 stream_forward_getp(s, length);
4433 break;
4434 }
4435 rcap->srgb.flags = stream_getc(s);
4436 rcap->srgb.range_size = stream_get3(s);
4437 /* Skip Type and get Length of SID Label */
4438 stream_getc(s);
4439 size = stream_getc(s);
4440
4441 if (size == ISIS_SUBTLV_SID_LABEL_SIZE
4442 && length != SUBTLV_RANGE_LABEL_SIZE) {
4443 stream_forward_getp(s, length - 6);
4444 break;
4445 }
4446
4447 if (size == ISIS_SUBTLV_SID_INDEX_SIZE
4448 && length != SUBTLV_RANGE_INDEX_SIZE) {
4449 stream_forward_getp(s, length - 6);
4450 break;
4451 }
4452
4453 if (size == ISIS_SUBTLV_SID_LABEL_SIZE) {
4454 rcap->srgb.lower_bound = stream_get3(s);
4455 } else if (size == ISIS_SUBTLV_SID_INDEX_SIZE) {
4456 rcap->srgb.lower_bound = stream_getl(s);
4457 } else {
4458 stream_forward_getp(s, length - 6);
4459 break;
4460 }
4461
4462 /* SRGB sanity checks. */
4463 if (rcap->srgb.range_size == 0
4464 || (rcap->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
4465 || ((rcap->srgb.lower_bound + rcap->srgb.range_size - 1)
4466 > MPLS_LABEL_UNRESERVED_MAX)) {
4467 sbuf_push(log, indent, "Invalid label range. Reset SRGB\n");
4468 rcap->srgb.lower_bound = 0;
4469 rcap->srgb.range_size = 0;
4470 }
4471 /* Only one range is supported. Skip subsequent one */
4472 size = length - (size + SUBTLV_SR_BLOCK_SIZE);
4473 if (size > 0)
4474 stream_forward_getp(s, size);
4475
4476 break;
4477 case ISIS_SUBTLV_ALGORITHM:
4478 if (length == 0)
4479 break;
4480
4481 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
4482 rcap->algo[i] = SR_ALGORITHM_UNSET;
4483
4484 for (int i = 0; i < length; i++) {
4485 uint8_t algo;
4486
4487 algo = stream_getc(s);
4488 rcap->algo[algo] = algo;
4489 }
4490 break;
4491 case ISIS_SUBTLV_SRLB:
4492 /* Check that SRLB is correctly formated */
4493 if (length < SUBTLV_RANGE_LABEL_SIZE
4494 || length > SUBTLV_RANGE_INDEX_SIZE) {
4495 stream_forward_getp(s, length);
4496 break;
4497 }
4498 /* RFC 8667 section #3.3: Only one SRLB is authorized */
4499 if (rcap->srlb.range_size != 0) {
4500 stream_forward_getp(s, length);
4501 break;
4502 }
4503 /* Ignore Flags which are not defined */
4504 stream_getc(s);
4505 rcap->srlb.range_size = stream_get3(s);
4506 /* Skip Type and get Length of SID Label */
4507 stream_getc(s);
4508 size = stream_getc(s);
4509
4510 if (size == ISIS_SUBTLV_SID_LABEL_SIZE
4511 && length != SUBTLV_RANGE_LABEL_SIZE) {
4512 stream_forward_getp(s, length - 6);
4513 break;
4514 }
4515
4516 if (size == ISIS_SUBTLV_SID_INDEX_SIZE
4517 && length != SUBTLV_RANGE_INDEX_SIZE) {
4518 stream_forward_getp(s, length - 6);
4519 break;
4520 }
4521
4522 if (size == ISIS_SUBTLV_SID_LABEL_SIZE) {
4523 rcap->srlb.lower_bound = stream_get3(s);
4524 } else if (size == ISIS_SUBTLV_SID_INDEX_SIZE) {
4525 rcap->srlb.lower_bound = stream_getl(s);
4526 } else {
4527 stream_forward_getp(s, length - 6);
4528 break;
4529 }
4530
4531 /* SRLB sanity checks. */
4532 if (rcap->srlb.range_size == 0
4533 || (rcap->srlb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
4534 || ((rcap->srlb.lower_bound + rcap->srlb.range_size - 1)
4535 > MPLS_LABEL_UNRESERVED_MAX)) {
4536 sbuf_push(log, indent, "Invalid label range. Reset SRLB\n");
4537 rcap->srlb.lower_bound = 0;
4538 rcap->srlb.range_size = 0;
4539 }
4540 /* Only one range is supported. Skip subsequent one */
4541 size = length - (size + SUBTLV_SR_BLOCK_SIZE);
4542 if (size > 0)
4543 stream_forward_getp(s, size);
4544
4545 break;
4546 case ISIS_SUBTLV_NODE_MSD:
4547 /* Check that MSD is correctly formated */
4548 if (length < MSD_TLV_SIZE) {
4549 stream_forward_getp(s, length);
4550 break;
4551 }
4552 msd_type = stream_getc(s);
4553 rcap->msd = stream_getc(s);
4554 /* Only BMI-MSD type has been defined in RFC 8491 */
4555 if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION)
4556 rcap->msd = 0;
4557 /* Only one MSD is standardized. Skip others */
4558 if (length > MSD_TLV_SIZE)
4559 stream_forward_getp(s, length - MSD_TLV_SIZE);
4560 break;
4561 #ifndef FABRICD
4562 case ISIS_SUBTLV_FAD:
4563 fad = XCALLOC(MTYPE_ISIS_TLV,
4564 sizeof(struct isis_router_cap_fad));
4565 fad->fad.algorithm = stream_getc(s);
4566 fad->fad.metric_type = stream_getc(s);
4567 fad->fad.calc_type = stream_getc(s);
4568 fad->fad.priority = stream_getc(s);
4569 rcap->fads[fad->fad.algorithm] = fad;
4570 admin_group_init(&fad->fad.admin_group_exclude_any);
4571 admin_group_init(&fad->fad.admin_group_include_any);
4572 admin_group_init(&fad->fad.admin_group_include_all);
4573
4574 subsubtlvs_len = length - 4;
4575 while (subsubtlvs_len > 2) {
4576 struct admin_group *ag;
4577 uint8_t subsubtlv_type;
4578 uint8_t subsubtlv_len;
4579 uint32_t v;
4580 int n_ag, i;
4581
4582 subsubtlv_type = stream_getc(s);
4583 subsubtlv_len = stream_getc(s);
4584
4585 switch (subsubtlv_type) {
4586 case ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG:
4587 ag = &fad->fad.admin_group_exclude_any;
4588 n_ag = subsubtlv_len / sizeof(uint32_t);
4589 for (i = 0; i < n_ag; i++) {
4590 v = stream_getl(s);
4591 admin_group_bulk_set(ag, v, i);
4592 }
4593 break;
4594 case ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG:
4595 ag = &fad->fad.admin_group_include_any;
4596 n_ag = subsubtlv_len / sizeof(uint32_t);
4597 for (i = 0; i < n_ag; i++) {
4598 v = stream_getl(s);
4599 admin_group_bulk_set(ag, v, i);
4600 }
4601 break;
4602 case ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG:
4603 ag = &fad->fad.admin_group_include_all;
4604 n_ag = subsubtlv_len / sizeof(uint32_t);
4605 for (i = 0; i < n_ag; i++) {
4606 v = stream_getl(s);
4607 admin_group_bulk_set(ag, v, i);
4608 }
4609 break;
4610 case ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS:
4611 if (subsubtlv_len == 0)
4612 break;
4613
4614 fad->fad.flags = stream_getc(s);
4615 for (i = subsubtlv_len - 1; i > 0; --i)
4616 stream_getc(s);
4617 break;
4618 case ISIS_SUBTLV_FAD_SUBSUBTLV_ESRLG:
4619 fad->fad.exclude_srlg = true;
4620 stream_forward_getp(s, subsubtlv_len);
4621 break;
4622 default:
4623 sbuf_push(
4624 log, indent,
4625 "Received an unsupported Flex-Algo sub-TLV type %u\n",
4626 subsubtlv_type);
4627 fad->fad.unsupported_subtlv = true;
4628 stream_forward_getp(s, subsubtlv_len);
4629 break;
4630 }
4631 subsubtlvs_len -= 2 + subsubtlv_len;
4632 }
4633 break;
4634 #endif /* ifndef FABRICD */
4635 default:
4636 stream_forward_getp(s, length);
4637 break;
4638 }
4639 subtlv_len = subtlv_len - length - 2;
4640 }
4641 tlvs->router_cap = rcap;
4642 return 0;
4643 }
4644
4645 /* Functions related to TLV 10 Authentication */
4646 static struct isis_item *copy_item_auth(struct isis_item *i)
4647 {
4648 struct isis_auth *auth = (struct isis_auth *)i;
4649 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
4650
4651 rv->type = auth->type;
4652 rv->length = auth->length;
4653 memcpy(rv->value, auth->value, sizeof(rv->value));
4654 return (struct isis_item *)rv;
4655 }
4656
4657 static void format_item_auth(uint16_t mtid, struct isis_item *i,
4658 struct sbuf *buf, struct json_object *json,
4659 int indent)
4660 {
4661 struct isis_auth *auth = (struct isis_auth *)i;
4662 char obuf[768];
4663
4664 if (json)
4665 json_object_string_add(json, "test-auth", "ok");
4666 else
4667 sbuf_push(buf, indent, "Authentication:\n");
4668 switch (auth->type) {
4669 case ISIS_PASSWD_TYPE_CLEARTXT:
4670 zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
4671 if (json)
4672 json_object_string_add(json, "auth-pass", obuf);
4673 else
4674 sbuf_push(buf, indent, " Password: %s\n", obuf);
4675 break;
4676 case ISIS_PASSWD_TYPE_HMAC_MD5:
4677 for (unsigned int j = 0; j < 16; j++) {
4678 snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx",
4679 auth->value[j]);
4680 }
4681 if (json)
4682 json_object_string_add(json, "auth-hmac-md5", obuf);
4683 else
4684 sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
4685 break;
4686 default:
4687 if (json)
4688 json_object_int_add(json, "auth-unknown", auth->type);
4689 else
4690 sbuf_push(buf, indent, " Unknown (%hhu)\n",
4691 auth->type);
4692 break;
4693 }
4694 }
4695
4696 static void free_item_auth(struct isis_item *i)
4697 {
4698 XFREE(MTYPE_ISIS_TLV, i);
4699 }
4700
4701 static int pack_item_auth(struct isis_item *i, struct stream *s,
4702 size_t *min_len)
4703 {
4704 struct isis_auth *auth = (struct isis_auth *)i;
4705
4706 if (STREAM_WRITEABLE(s) < 1) {
4707 *min_len = 1;
4708 return 1;
4709 }
4710 stream_putc(s, auth->type);
4711
4712 switch (auth->type) {
4713 case ISIS_PASSWD_TYPE_CLEARTXT:
4714 if (STREAM_WRITEABLE(s) < auth->length) {
4715 *min_len = 1 + auth->length;
4716 return 1;
4717 }
4718 stream_put(s, auth->passwd, auth->length);
4719 break;
4720 case ISIS_PASSWD_TYPE_HMAC_MD5:
4721 if (STREAM_WRITEABLE(s) < 16) {
4722 *min_len = 1 + 16;
4723 return 1;
4724 }
4725 auth->offset = stream_get_endp(s);
4726 stream_put(s, NULL, 16);
4727 break;
4728 default:
4729 return 1;
4730 }
4731
4732 return 0;
4733 }
4734
4735 static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
4736 struct sbuf *log, void *dest, int indent)
4737 {
4738 struct isis_tlvs *tlvs = dest;
4739
4740 sbuf_push(log, indent, "Unpack Auth TLV...\n");
4741 if (len < 1) {
4742 sbuf_push(
4743 log, indent,
4744 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
4745 len);
4746 return 1;
4747 }
4748
4749 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
4750
4751 rv->type = stream_getc(s);
4752 rv->length = len - 1;
4753
4754 if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) {
4755 sbuf_push(
4756 log, indent,
4757 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
4758 rv->length);
4759 XFREE(MTYPE_ISIS_TLV, rv);
4760 return 1;
4761 }
4762
4763 rv->offset = stream_get_getp(s);
4764 stream_get(rv->value, s, rv->length);
4765 format_item_auth(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
4766 append_item(&tlvs->isis_auth, (struct isis_item *)rv);
4767 return 0;
4768 }
4769
4770 /* Functions related to TLV 13 Purge Originator */
4771
4772 static struct isis_purge_originator *copy_tlv_purge_originator(
4773 struct isis_purge_originator *poi)
4774 {
4775 if (!poi)
4776 return NULL;
4777
4778 struct isis_purge_originator *rv;
4779
4780 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
4781 rv->sender_set = poi->sender_set;
4782 memcpy(rv->generator, poi->generator, sizeof(rv->generator));
4783 if (poi->sender_set)
4784 memcpy(rv->sender, poi->sender, sizeof(rv->sender));
4785 return rv;
4786 }
4787
4788 static void format_tlv_purge_originator(struct isis_purge_originator *poi,
4789 struct sbuf *buf,
4790 struct json_object *json, int indent)
4791 {
4792 char sen_id[ISO_SYSID_STRLEN];
4793 char gen_id[ISO_SYSID_STRLEN];
4794
4795 if (!poi)
4796 return;
4797
4798 snprintfrr(gen_id, ISO_SYSID_STRLEN, "%pSY", poi->generator);
4799 if (poi->sender_set)
4800 snprintfrr(sen_id, ISO_SYSID_STRLEN, "%pSY", poi->sender);
4801
4802 if (json) {
4803 struct json_object *purge_json;
4804 purge_json = json_object_new_object();
4805 json_object_object_add(json, "purge_originator", purge_json);
4806
4807 json_object_string_add(purge_json, "id", gen_id);
4808 if (poi->sender_set)
4809 json_object_string_add(purge_json, "rec-from", sen_id);
4810 } else {
4811 sbuf_push(buf, indent, "Purge Originator Identification:\n");
4812 sbuf_push(buf, indent, " Generator: %s\n", gen_id);
4813 if (poi->sender_set)
4814 sbuf_push(buf, indent, " Received-From: %s\n", sen_id);
4815 }
4816 }
4817
4818 static void free_tlv_purge_originator(struct isis_purge_originator *poi)
4819 {
4820 XFREE(MTYPE_ISIS_TLV, poi);
4821 }
4822
4823 static int pack_tlv_purge_originator(struct isis_purge_originator *poi,
4824 struct stream *s)
4825 {
4826 if (!poi)
4827 return 0;
4828
4829 uint8_t data_len = 1 + sizeof(poi->generator);
4830
4831 if (poi->sender_set)
4832 data_len += sizeof(poi->sender);
4833
4834 if (STREAM_WRITEABLE(s) < (unsigned)(2 + data_len))
4835 return 1;
4836
4837 stream_putc(s, ISIS_TLV_PURGE_ORIGINATOR);
4838 stream_putc(s, data_len);
4839 stream_putc(s, poi->sender_set ? 2 : 1);
4840 stream_put(s, poi->generator, sizeof(poi->generator));
4841 if (poi->sender_set)
4842 stream_put(s, poi->sender, sizeof(poi->sender));
4843 return 0;
4844 }
4845
4846 static int unpack_tlv_purge_originator(enum isis_tlv_context context,
4847 uint8_t tlv_type, uint8_t tlv_len,
4848 struct stream *s, struct sbuf *log,
4849 void *dest, int indent)
4850 {
4851 struct isis_tlvs *tlvs = dest;
4852 struct isis_purge_originator poi = {};
4853
4854 sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
4855 if (tlv_len < 7) {
4856 sbuf_push(log, indent, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len);
4857 return 1;
4858 }
4859
4860 uint8_t number_of_ids = stream_getc(s);
4861
4862 if (number_of_ids == 1) {
4863 poi.sender_set = false;
4864 } else if (number_of_ids == 2) {
4865 poi.sender_set = true;
4866 } else {
4867 sbuf_push(log, indent, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids);
4868 return 1;
4869 }
4870
4871 if (tlv_len != 1 + 6 * number_of_ids) {
4872 sbuf_push(log, indent, "Incorrect tlv len for number of IDs.\n");
4873 return 1;
4874 }
4875
4876 stream_get(poi.generator, s, sizeof(poi.generator));
4877 if (poi.sender_set)
4878 stream_get(poi.sender, s, sizeof(poi.sender));
4879
4880 if (tlvs->purge_originator) {
4881 sbuf_push(log, indent,
4882 "WARNING: Purge originator present multiple times, ignoring.\n");
4883 return 0;
4884 }
4885
4886 tlvs->purge_originator = copy_tlv_purge_originator(&poi);
4887 return 0;
4888 }
4889
4890
4891 /* Functions relating to item TLVs */
4892
4893 static void init_item_list(struct isis_item_list *items)
4894 {
4895 items->head = NULL;
4896 items->tail = &items->head;
4897 items->count = 0;
4898 }
4899
4900 static struct isis_item *copy_item(enum isis_tlv_context context,
4901 enum isis_tlv_type type,
4902 struct isis_item *item)
4903 {
4904 const struct tlv_ops *ops = tlv_table[context][type];
4905
4906 if (ops && ops->copy_item)
4907 return ops->copy_item(item);
4908
4909 assert(!"Unknown item tlv type!");
4910 return NULL;
4911 }
4912
4913 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
4914 struct isis_item_list *src, struct isis_item_list *dest)
4915 {
4916 struct isis_item *item;
4917
4918 init_item_list(dest);
4919
4920 for (item = src->head; item; item = item->next) {
4921 append_item(dest, copy_item(context, type, item));
4922 }
4923 }
4924
4925 static void format_item(uint16_t mtid, enum isis_tlv_context context,
4926 enum isis_tlv_type type, struct isis_item *i,
4927 struct sbuf *buf, struct json_object *json, int indent)
4928 {
4929 const struct tlv_ops *ops = tlv_table[context][type];
4930
4931 if (ops && ops->format_item) {
4932 ops->format_item(mtid, i, buf, json, indent);
4933 return;
4934 }
4935
4936 assert(!"Unknown item tlv type!");
4937 }
4938
4939 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
4940 enum isis_tlv_type type, struct isis_item_list *items,
4941 struct sbuf *buf, struct json_object *json,
4942 int indent)
4943 {
4944 struct isis_item *i;
4945
4946 for (i = items->head; i; i = i->next)
4947 format_item(mtid, context, type, i, buf, json, indent);
4948 }
4949
4950 static void free_item(enum isis_tlv_context tlv_context,
4951 enum isis_tlv_type tlv_type, struct isis_item *item)
4952 {
4953 const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type];
4954
4955 if (ops && ops->free_item) {
4956 ops->free_item(item);
4957 return;
4958 }
4959
4960 assert(!"Unknown item tlv type!");
4961 }
4962
4963 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
4964 struct isis_item_list *items)
4965 {
4966 struct isis_item *item, *next_item;
4967
4968 for (item = items->head; item; item = next_item) {
4969 next_item = item->next;
4970 free_item(context, type, item);
4971 }
4972 }
4973
4974 static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
4975 struct isis_item *i, struct stream *s, size_t *min_len,
4976 struct isis_tlvs **fragment_tlvs,
4977 const struct pack_order_entry *pe, uint16_t mtid)
4978 {
4979 const struct tlv_ops *ops = tlv_table[context][type];
4980
4981 if (ops && ops->pack_item) {
4982 return ops->pack_item(i, s, min_len);
4983 }
4984
4985 assert(!"Unknown item tlv type!");
4986 return 1;
4987 }
4988
4989 static void add_item_to_fragment(struct isis_item *i,
4990 const struct pack_order_entry *pe,
4991 struct isis_tlvs *fragment_tlvs, uint16_t mtid)
4992 {
4993 struct isis_item_list *l;
4994
4995 if (pe->how_to_pack == ISIS_ITEMS) {
4996 l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
4997 } else {
4998 struct isis_mt_item_list *m;
4999 m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
5000 l = isis_get_mt_items(m, mtid);
5001 }
5002
5003 append_item(l, copy_item(pe->context, pe->type, i));
5004 }
5005
5006 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
5007 enum isis_tlv_type type, struct isis_item_list *items,
5008 struct stream *s, struct isis_tlvs **fragment_tlvs,
5009 const struct pack_order_entry *pe,
5010 struct isis_tlvs *(*new_fragment)(struct list *l),
5011 struct list *new_fragment_arg)
5012 {
5013 size_t len_pos, last_len, len;
5014 struct isis_item *item = NULL;
5015 int rv;
5016 size_t min_len = 0;
5017
5018 if (!items->head)
5019 return 0;
5020
5021 top:
5022 if (STREAM_WRITEABLE(s) < 2)
5023 goto too_long;
5024
5025 stream_putc(s, type);
5026 len_pos = stream_get_endp(s);
5027 stream_putc(s, 0); /* Put 0 as length for now */
5028
5029 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type)
5030 && mtid != ISIS_MT_IPV4_UNICAST) {
5031 if (STREAM_WRITEABLE(s) < 2)
5032 goto too_long;
5033 stream_putw(s, mtid);
5034 }
5035
5036 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) {
5037 if (STREAM_WRITEABLE(s) < 1)
5038 goto too_long;
5039 stream_putc(s, 0); /* Virtual flag is set to 0 */
5040 }
5041
5042 last_len = len = 0;
5043 for (item = item ? item : items->head; item; item = item->next) {
5044 rv = pack_item(context, type, item, s, &min_len, fragment_tlvs,
5045 pe, mtid);
5046 if (rv)
5047 goto too_long;
5048
5049 len = stream_get_endp(s) - len_pos - 1;
5050
5051 /* Multiple auths don't go into one TLV, so always break */
5052 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) {
5053 item = item->next;
5054 break;
5055 }
5056
5057 /* Multiple prefix-sids don't go into one TLV, so always break */
5058 if (type == ISIS_SUBTLV_PREFIX_SID
5059 && (context == ISIS_CONTEXT_SUBTLV_IP_REACH
5060 || context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
5061 item = item->next;
5062 break;
5063 }
5064
5065 if (len > 255) {
5066 if (!last_len) /* strange, not a single item fit */
5067 return 1;
5068 /* drop last tlv, otherwise, its too long */
5069 stream_set_endp(s, len_pos + 1 + last_len);
5070 len = last_len;
5071 break;
5072 }
5073
5074 if (fragment_tlvs)
5075 add_item_to_fragment(item, pe, *fragment_tlvs, mtid);
5076
5077 last_len = len;
5078 }
5079
5080 stream_putc_at(s, len_pos, len);
5081 if (item)
5082 goto top;
5083
5084 return 0;
5085 too_long:
5086 if (!fragment_tlvs)
5087 return 1;
5088 stream_reset(s);
5089 if (STREAM_WRITEABLE(s) < min_len)
5090 return 1;
5091 *fragment_tlvs = new_fragment(new_fragment_arg);
5092 goto top;
5093 }
5094 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
5095
5096 static void append_item(struct isis_item_list *dest, struct isis_item *item)
5097 {
5098 *dest->tail = item;
5099 dest->tail = &(*dest->tail)->next;
5100 dest->count++;
5101 }
5102
5103 static void delete_item(struct isis_item_list *dest, struct isis_item *del)
5104 {
5105 struct isis_item *item, *prev = NULL, *next;
5106
5107 /* Sanity Check */
5108 if ((dest == NULL) || (del == NULL))
5109 return;
5110
5111 /*
5112 * TODO: delete is tricky because "dest" is a singly linked list.
5113 * We need to switch a doubly linked list.
5114 */
5115 for (item = dest->head; item; item = next) {
5116 if (item->next == del) {
5117 prev = item;
5118 break;
5119 }
5120 next = item->next;
5121 }
5122 if (prev)
5123 prev->next = del->next;
5124 if (dest->head == del)
5125 dest->head = del->next;
5126 if ((struct isis_item *)dest->tail == del) {
5127 *dest->tail = prev;
5128 if (prev)
5129 dest->tail = &(*dest->tail)->next;
5130 else
5131 dest->tail = &dest->head;
5132 }
5133 dest->count--;
5134 }
5135
5136 static struct isis_item *last_item(struct isis_item_list *list)
5137 {
5138 return container_of(list->tail, struct isis_item, next);
5139 }
5140
5141 static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
5142 uint8_t tlv_type, uint8_t len, struct stream *s,
5143 struct sbuf *log, void *dest, int indent)
5144 {
5145 const struct tlv_ops *ops = tlv_table[context][tlv_type];
5146
5147 if (ops && ops->unpack_item)
5148 return ops->unpack_item(mtid, len, s, log, dest, indent);
5149
5150 assert(!"Unknown item tlv type!");
5151 sbuf_push(log, indent, "Unknown item tlv type!\n");
5152 return 1;
5153 }
5154
5155 static int unpack_tlv_with_items(enum isis_tlv_context context,
5156 uint8_t tlv_type, uint8_t tlv_len,
5157 struct stream *s, struct sbuf *log, void *dest,
5158 int indent)
5159 {
5160 size_t tlv_start;
5161 size_t tlv_pos;
5162 int rv;
5163 uint16_t mtid;
5164
5165 tlv_start = stream_get_getp(s);
5166 tlv_pos = 0;
5167
5168 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) {
5169 if (tlv_len < 2) {
5170 sbuf_push(log, indent,
5171 "TLV is too short to contain MTID\n");
5172 return 1;
5173 }
5174 mtid = stream_getw(s) & ISIS_MT_MASK;
5175 tlv_pos += 2;
5176 sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n",
5177 isis_mtid2str_fake(mtid));
5178 } else {
5179 sbuf_push(log, indent, "Unpacking as item TLV...\n");
5180 mtid = ISIS_MT_IPV4_UNICAST;
5181 }
5182
5183 if (context == ISIS_CONTEXT_LSP
5184 && tlv_type == ISIS_TLV_OLDSTYLE_REACH) {
5185 if (tlv_len - tlv_pos < 1) {
5186 sbuf_push(log, indent,
5187 "TLV is too short for old style reach\n");
5188 return 1;
5189 }
5190 stream_forward_getp(s, 1);
5191 tlv_pos += 1;
5192 }
5193
5194 if (context == ISIS_CONTEXT_LSP
5195 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) {
5196 struct isis_tlvs *tlvs = dest;
5197 dest = &tlvs->oldstyle_ip_reach;
5198 } else if (context == ISIS_CONTEXT_LSP
5199 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) {
5200 struct isis_tlvs *tlvs = dest;
5201 dest = &tlvs->oldstyle_ip_reach_ext;
5202 }
5203
5204 if (context == ISIS_CONTEXT_LSP
5205 && tlv_type == ISIS_TLV_MT_ROUTER_INFO) {
5206 struct isis_tlvs *tlvs = dest;
5207 tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len);
5208 }
5209
5210 while (tlv_pos < (size_t)tlv_len) {
5211 rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s,
5212 log, dest, indent + 2);
5213 if (rv)
5214 return rv;
5215
5216 tlv_pos = stream_get_getp(s) - tlv_start;
5217 }
5218
5219 return 0;
5220 }
5221
5222 /* Functions to manipulate mt_item_lists */
5223
5224 static int isis_mt_item_list_cmp(const struct isis_item_list *a,
5225 const struct isis_item_list *b)
5226 {
5227 if (a->mtid < b->mtid)
5228 return -1;
5229 if (a->mtid > b->mtid)
5230 return 1;
5231 return 0;
5232 }
5233
5234 RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
5235 RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
5236
5237 struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
5238 uint16_t mtid)
5239 {
5240 struct isis_item_list *rv;
5241
5242 rv = isis_lookup_mt_items(m, mtid);
5243 if (!rv) {
5244 rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv));
5245 init_item_list(rv);
5246 rv->mtid = mtid;
5247 RB_INSERT(isis_mt_item_list, m, rv);
5248 }
5249
5250 return rv;
5251 }
5252
5253 struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
5254 uint16_t mtid)
5255 {
5256 struct isis_item_list key = {.mtid = mtid};
5257
5258 return RB_FIND(isis_mt_item_list, m, &key);
5259 }
5260
5261 static void free_mt_items(enum isis_tlv_context context,
5262 enum isis_tlv_type type, struct isis_mt_item_list *m)
5263 {
5264 struct isis_item_list *n, *nnext;
5265
5266 RB_FOREACH_SAFE (n, isis_mt_item_list, m, nnext) {
5267 free_items(context, type, n);
5268 RB_REMOVE(isis_mt_item_list, m, n);
5269 XFREE(MTYPE_ISIS_MT_ITEM_LIST, n);
5270 }
5271 }
5272
5273 static void format_mt_items(enum isis_tlv_context context,
5274 enum isis_tlv_type type,
5275 struct isis_mt_item_list *m, struct sbuf *buf,
5276 struct json_object *json, int indent)
5277 {
5278 struct isis_item_list *n;
5279
5280 RB_FOREACH (n, isis_mt_item_list, m) {
5281 format_items_(n->mtid, context, type, n, buf, json, indent);
5282 }
5283 }
5284
5285 static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type,
5286 struct isis_mt_item_list *m, struct stream *s,
5287 struct isis_tlvs **fragment_tlvs,
5288 const struct pack_order_entry *pe,
5289 struct isis_tlvs *(*new_fragment)(struct list *l),
5290 struct list *new_fragment_arg)
5291 {
5292 struct isis_item_list *n;
5293
5294 RB_FOREACH (n, isis_mt_item_list, m) {
5295 int rv;
5296
5297 rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs,
5298 pe, new_fragment, new_fragment_arg);
5299 if (rv)
5300 return rv;
5301 }
5302
5303 return 0;
5304 }
5305
5306 static void copy_mt_items(enum isis_tlv_context context,
5307 enum isis_tlv_type type,
5308 struct isis_mt_item_list *src,
5309 struct isis_mt_item_list *dest)
5310 {
5311 struct isis_item_list *n;
5312
5313 RB_INIT(isis_mt_item_list, dest);
5314
5315 RB_FOREACH (n, isis_mt_item_list, src) {
5316 copy_items(context, type, n, isis_get_mt_items(dest, n->mtid));
5317 }
5318 }
5319
5320 /* Functions related to tlvs in general */
5321
5322 struct isis_tlvs *isis_alloc_tlvs(void)
5323 {
5324 struct isis_tlvs *result;
5325
5326 result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result));
5327
5328 init_item_list(&result->isis_auth);
5329 init_item_list(&result->area_addresses);
5330 init_item_list(&result->mt_router_info);
5331 init_item_list(&result->oldstyle_reach);
5332 init_item_list(&result->lan_neighbor);
5333 init_item_list(&result->lsp_entries);
5334 init_item_list(&result->extended_reach);
5335 RB_INIT(isis_mt_item_list, &result->mt_reach);
5336 init_item_list(&result->oldstyle_ip_reach);
5337 init_item_list(&result->oldstyle_ip_reach_ext);
5338 init_item_list(&result->ipv4_address);
5339 init_item_list(&result->ipv6_address);
5340 init_item_list(&result->global_ipv6_address);
5341 init_item_list(&result->extended_ip_reach);
5342 RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
5343 init_item_list(&result->ipv6_reach);
5344 RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach);
5345
5346 return result;
5347 }
5348
5349 struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
5350 {
5351 struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
5352
5353 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
5354 &rv->isis_auth);
5355
5356 rv->purge_originator =
5357 copy_tlv_purge_originator(tlvs->purge_originator);
5358
5359 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
5360 &tlvs->area_addresses, &rv->area_addresses);
5361
5362 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
5363 &tlvs->mt_router_info, &rv->mt_router_info);
5364
5365 rv->mt_router_info_empty = tlvs->mt_router_info_empty;
5366
5367 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
5368 &tlvs->oldstyle_reach, &rv->oldstyle_reach);
5369
5370 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
5371 &tlvs->lan_neighbor, &rv->lan_neighbor);
5372
5373 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
5374 &rv->lsp_entries);
5375
5376 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
5377 &tlvs->extended_reach, &rv->extended_reach);
5378
5379 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
5380 &rv->mt_reach);
5381
5382 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
5383 &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach);
5384
5385 copy_tlv_protocols_supported(&tlvs->protocols_supported,
5386 &rv->protocols_supported);
5387
5388 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
5389 &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext);
5390
5391 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address,
5392 &rv->ipv4_address);
5393
5394 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
5395 &rv->ipv6_address);
5396
5397 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
5398 &tlvs->global_ipv6_address, &rv->global_ipv6_address);
5399
5400 rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
5401
5402 rv->te_router_id_ipv6 =
5403 copy_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6);
5404
5405 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
5406 &tlvs->extended_ip_reach, &rv->extended_ip_reach);
5407
5408 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
5409 &tlvs->mt_ip_reach, &rv->mt_ip_reach);
5410
5411 rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname);
5412
5413 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
5414 &rv->ipv6_reach);
5415
5416 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
5417 &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
5418
5419 rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
5420
5421 rv->router_cap = copy_tlv_router_cap(tlvs->router_cap);
5422
5423 rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
5424
5425 return rv;
5426 }
5427
5428 static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_object *json, int indent)
5429 {
5430 format_tlv_protocols_supported(&tlvs->protocols_supported, buf, json,
5431 indent);
5432
5433 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
5434 json, indent);
5435
5436 format_tlv_purge_originator(tlvs->purge_originator, buf, json, indent);
5437
5438 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
5439 &tlvs->area_addresses, buf, json, indent);
5440
5441 if (tlvs->mt_router_info_empty) {
5442 if (json)
5443 json_object_string_add(json, "mt-router-info", "none");
5444 else
5445 sbuf_push(buf, indent, "MT Router Info: None\n");
5446 } else {
5447 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
5448 &tlvs->mt_router_info, buf, json, indent);
5449 }
5450
5451 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
5452 &tlvs->oldstyle_reach, buf, json, indent);
5453
5454 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
5455 &tlvs->lan_neighbor, buf, json, indent);
5456
5457 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
5458 buf, json, indent);
5459
5460 format_tlv_dynamic_hostname(tlvs->hostname, buf, json, indent);
5461 format_tlv_te_router_id(tlvs->te_router_id, buf, json, indent);
5462 format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, json,
5463 indent);
5464 if (json)
5465 format_tlv_router_cap_json(tlvs->router_cap, json);
5466 else
5467 format_tlv_router_cap(tlvs->router_cap, buf, indent);
5468
5469 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
5470 &tlvs->extended_reach, buf, json, indent);
5471
5472 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
5473 buf, json, indent);
5474
5475 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
5476 &tlvs->oldstyle_ip_reach, buf, json, indent);
5477
5478 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
5479 &tlvs->oldstyle_ip_reach_ext, buf, json, indent);
5480
5481 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
5482 &tlvs->ipv4_address, buf, json, indent);
5483
5484 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
5485 &tlvs->ipv6_address, buf, json, indent);
5486
5487 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
5488 &tlvs->global_ipv6_address, buf, json, indent);
5489
5490 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
5491 &tlvs->extended_ip_reach, buf, json, indent);
5492
5493 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
5494 &tlvs->mt_ip_reach, buf, json, indent);
5495
5496 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
5497 buf, json, indent);
5498
5499 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
5500 &tlvs->mt_ipv6_reach, buf, json, indent);
5501
5502 format_tlv_threeway_adj(tlvs->threeway_adj, buf, json, indent);
5503
5504 format_tlv_spine_leaf(tlvs->spine_leaf, buf, json, indent);
5505 }
5506
5507 const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json)
5508 {
5509 if (json) {
5510 format_tlvs(tlvs, NULL, json, 0);
5511 return NULL;
5512 } else {
5513 static struct sbuf buf;
5514
5515 if (!sbuf_buf(&buf))
5516 sbuf_init(&buf, NULL, 0);
5517
5518 sbuf_reset(&buf);
5519 format_tlvs(tlvs, &buf, NULL, 0);
5520 return sbuf_buf(&buf);
5521 }
5522 }
5523
5524 void isis_free_tlvs(struct isis_tlvs *tlvs)
5525 {
5526 if (!tlvs)
5527 return;
5528
5529 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
5530 free_tlv_purge_originator(tlvs->purge_originator);
5531 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
5532 &tlvs->area_addresses);
5533 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
5534 &tlvs->mt_router_info);
5535 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
5536 &tlvs->oldstyle_reach);
5537 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
5538 &tlvs->lan_neighbor);
5539 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries);
5540 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
5541 &tlvs->extended_reach);
5542 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach);
5543 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
5544 &tlvs->oldstyle_ip_reach);
5545 free_tlv_protocols_supported(&tlvs->protocols_supported);
5546 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
5547 &tlvs->oldstyle_ip_reach_ext);
5548 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
5549 &tlvs->ipv4_address);
5550 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
5551 &tlvs->ipv6_address);
5552 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
5553 &tlvs->global_ipv6_address);
5554 free_tlv_te_router_id(tlvs->te_router_id);
5555 free_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6);
5556 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
5557 &tlvs->extended_ip_reach);
5558 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
5559 &tlvs->mt_ip_reach);
5560 free_tlv_dynamic_hostname(tlvs->hostname);
5561 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
5562 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
5563 &tlvs->mt_ipv6_reach);
5564 free_tlv_threeway_adj(tlvs->threeway_adj);
5565 free_tlv_router_cap(tlvs->router_cap);
5566 free_tlv_spine_leaf(tlvs->spine_leaf);
5567
5568 XFREE(MTYPE_ISIS_TLV, tlvs);
5569 }
5570
5571 static void add_padding(struct stream *s)
5572 {
5573 while (STREAM_WRITEABLE(s)) {
5574 if (STREAM_WRITEABLE(s) == 1)
5575 break;
5576 uint32_t padding_len = STREAM_WRITEABLE(s) - 2;
5577
5578 if (padding_len > 255) {
5579 if (padding_len == 256)
5580 padding_len = 254;
5581 else
5582 padding_len = 255;
5583 }
5584
5585 stream_putc(s, ISIS_TLV_PADDING);
5586 stream_putc(s, padding_len);
5587 stream_put(s, NULL, padding_len);
5588 }
5589 }
5590
5591 #define LSP_REM_LIFETIME_OFF 10
5592 #define LSP_CHECKSUM_OFF 24
5593 static void safe_auth_md5(struct stream *s, uint16_t *checksum,
5594 uint16_t *rem_lifetime)
5595 {
5596 memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF,
5597 sizeof(*rem_lifetime));
5598 memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime));
5599 memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum));
5600 memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum));
5601 }
5602
5603 static void restore_auth_md5(struct stream *s, uint16_t checksum,
5604 uint16_t rem_lifetime)
5605 {
5606 memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime,
5607 sizeof(rem_lifetime));
5608 memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum));
5609 }
5610
5611 static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s,
5612 bool is_lsp)
5613 {
5614 uint8_t digest[16];
5615 uint16_t checksum, rem_lifetime;
5616
5617 if (is_lsp)
5618 safe_auth_md5(s, &checksum, &rem_lifetime);
5619
5620 memset(STREAM_DATA(s) + auth->offset, 0, 16);
5621 #ifdef CRYPTO_OPENSSL
5622 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), auth->passwd,
5623 auth->plength, STREAM_DATA(s),
5624 stream_get_endp(s), NULL, NULL);
5625
5626 memcpy(digest, result, 16);
5627 #elif CRYPTO_INTERNAL
5628 hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd,
5629 auth->plength, digest);
5630 #endif
5631 memcpy(auth->value, digest, 16);
5632 memcpy(STREAM_DATA(s) + auth->offset, digest, 16);
5633
5634 if (is_lsp)
5635 restore_auth_md5(s, checksum, rem_lifetime);
5636 }
5637
5638 static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp)
5639 {
5640 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
5641
5642 for (struct isis_auth *auth = auth_head; auth; auth = auth->next) {
5643 if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5)
5644 update_auth_hmac_md5(auth, s, is_lsp);
5645 }
5646 }
5647
5648 static int handle_pack_entry(const struct pack_order_entry *pe,
5649 struct isis_tlvs *tlvs, struct stream *stream,
5650 struct isis_tlvs **fragment_tlvs,
5651 struct isis_tlvs *(*new_fragment)(struct list *l),
5652 struct list *new_fragment_arg)
5653 {
5654 int rv;
5655
5656 if (pe->how_to_pack == ISIS_ITEMS) {
5657 struct isis_item_list *l;
5658 l = (struct isis_item_list *)(((char *)tlvs)
5659 + pe->what_to_pack);
5660 rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs,
5661 pe, new_fragment, new_fragment_arg);
5662 } else {
5663 struct isis_mt_item_list *l;
5664 l = (struct isis_mt_item_list *)(((char *)tlvs)
5665 + pe->what_to_pack);
5666 rv = pack_mt_items(pe->context, pe->type, l, stream,
5667 fragment_tlvs, pe, new_fragment,
5668 new_fragment_arg);
5669 }
5670
5671 return rv;
5672 }
5673
5674 static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
5675 struct isis_tlvs *fragment_tlvs,
5676 struct isis_tlvs *(*new_fragment)(struct list *l),
5677 struct list *new_fragment_arg)
5678 {
5679 int rv;
5680
5681 /* When fragmenting, don't add auth as it's already accounted for in the
5682 * size we are given. */
5683 if (!fragment_tlvs) {
5684 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH,
5685 &tlvs->isis_auth, stream, NULL, NULL, NULL,
5686 NULL);
5687 if (rv)
5688 return rv;
5689 }
5690
5691 rv = pack_tlv_purge_originator(tlvs->purge_originator, stream);
5692 if (rv)
5693 return rv;
5694 if (fragment_tlvs) {
5695 fragment_tlvs->purge_originator =
5696 copy_tlv_purge_originator(tlvs->purge_originator);
5697 }
5698
5699 rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
5700 if (rv)
5701 return rv;
5702 if (fragment_tlvs) {
5703 copy_tlv_protocols_supported(
5704 &tlvs->protocols_supported,
5705 &fragment_tlvs->protocols_supported);
5706 }
5707
5708 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
5709 &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL);
5710 if (rv)
5711 return rv;
5712 if (fragment_tlvs) {
5713 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
5714 &tlvs->area_addresses,
5715 &fragment_tlvs->area_addresses);
5716 }
5717
5718
5719 if (tlvs->mt_router_info_empty) {
5720 if (STREAM_WRITEABLE(stream) < 2)
5721 return 1;
5722 stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO);
5723 stream_putc(stream, 0);
5724 if (fragment_tlvs)
5725 fragment_tlvs->mt_router_info_empty = true;
5726 } else {
5727 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
5728 &tlvs->mt_router_info, stream, NULL, NULL, NULL,
5729 NULL);
5730 if (rv)
5731 return rv;
5732 if (fragment_tlvs) {
5733 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
5734 &tlvs->mt_router_info,
5735 &fragment_tlvs->mt_router_info);
5736 }
5737 }
5738
5739 rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream);
5740 if (rv)
5741 return rv;
5742 if (fragment_tlvs)
5743 fragment_tlvs->hostname =
5744 copy_tlv_dynamic_hostname(tlvs->hostname);
5745
5746 rv = pack_tlv_router_cap(tlvs->router_cap, stream);
5747 if (rv)
5748 return rv;
5749 if (fragment_tlvs) {
5750 fragment_tlvs->router_cap =
5751 copy_tlv_router_cap(tlvs->router_cap);
5752 }
5753
5754 rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
5755 if (rv)
5756 return rv;
5757 if (fragment_tlvs) {
5758 fragment_tlvs->te_router_id =
5759 copy_tlv_te_router_id(tlvs->te_router_id);
5760 }
5761
5762 rv = pack_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, stream);
5763 if (rv)
5764 return rv;
5765 if (fragment_tlvs) {
5766 fragment_tlvs->te_router_id_ipv6 =
5767 copy_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6);
5768 }
5769
5770 rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
5771 if (rv)
5772 return rv;
5773 if (fragment_tlvs) {
5774 fragment_tlvs->threeway_adj =
5775 copy_tlv_threeway_adj(tlvs->threeway_adj);
5776 }
5777
5778 rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
5779 if (rv)
5780 return rv;
5781 if (fragment_tlvs) {
5782 fragment_tlvs->spine_leaf =
5783 copy_tlv_spine_leaf(tlvs->spine_leaf);
5784 }
5785
5786 for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
5787 pack_idx++) {
5788 rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
5789 fragment_tlvs ? &fragment_tlvs : NULL,
5790 new_fragment, new_fragment_arg);
5791
5792 if (rv)
5793 return rv;
5794 }
5795
5796 return 0;
5797 }
5798
5799 int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
5800 size_t len_pointer, bool pad, bool is_lsp)
5801 {
5802 int rv;
5803
5804 rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL);
5805 if (rv)
5806 return rv;
5807
5808 if (pad)
5809 add_padding(stream);
5810
5811 if (len_pointer != (size_t)-1) {
5812 stream_putw_at(stream, len_pointer, stream_get_endp(stream));
5813 }
5814
5815 update_auth(tlvs, stream, is_lsp);
5816
5817 return 0;
5818 }
5819
5820 static struct isis_tlvs *new_fragment(struct list *l)
5821 {
5822 struct isis_tlvs *rv = isis_alloc_tlvs();
5823
5824 listnode_add(l, rv);
5825 return rv;
5826 }
5827
5828 struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size)
5829 {
5830 struct stream *dummy_stream = stream_new(size);
5831 struct list *rv = list_new();
5832 struct isis_tlvs *fragment_tlvs = new_fragment(rv);
5833
5834 if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) {
5835 struct listnode *node;
5836 for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs))
5837 isis_free_tlvs(fragment_tlvs);
5838 list_delete(&rv);
5839 }
5840
5841 stream_free(dummy_stream);
5842 return rv;
5843 }
5844
5845 static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type,
5846 uint8_t tlv_len, struct stream *s,
5847 struct sbuf *log, int indent)
5848 {
5849 stream_forward_getp(s, tlv_len);
5850 sbuf_push(log, indent,
5851 "Skipping unknown TLV %hhu (%hhu bytes)\n",
5852 tlv_type, tlv_len);
5853 return 0;
5854 }
5855
5856 static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
5857 struct stream *stream, struct sbuf *log, void *dest,
5858 int indent, bool *unpacked_known_tlvs)
5859 {
5860 uint8_t tlv_type, tlv_len;
5861 const struct tlv_ops *ops;
5862
5863 sbuf_push(log, indent, "Unpacking TLV...\n");
5864
5865 if (avail_len < 2) {
5866 sbuf_push(
5867 log, indent + 2,
5868 "Available data %zu too short to contain a TLV header.\n",
5869 avail_len);
5870 return 1;
5871 }
5872
5873 tlv_type = stream_getc(stream);
5874 tlv_len = stream_getc(stream);
5875
5876 sbuf_push(log, indent + 2,
5877 "Found TLV of type %hhu and len %hhu.\n",
5878 tlv_type, tlv_len);
5879
5880 if (avail_len < ((size_t)tlv_len) + 2) {
5881 sbuf_push(log, indent + 2,
5882 "Available data %zu too short for claimed TLV len %hhu.\n",
5883 avail_len - 2, tlv_len);
5884 return 1;
5885 }
5886
5887 ops = tlv_table[context][tlv_type];
5888 if (ops && ops->unpack) {
5889 if (unpacked_known_tlvs)
5890 *unpacked_known_tlvs = true;
5891 return ops->unpack(context, tlv_type, tlv_len, stream, log,
5892 dest, indent + 2);
5893 }
5894
5895 return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log,
5896 indent + 2);
5897 }
5898
5899 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
5900 struct stream *stream, struct sbuf *log, void *dest,
5901 int indent, bool *unpacked_known_tlvs)
5902 {
5903 int rv;
5904 size_t tlv_start, tlv_pos;
5905
5906 tlv_start = stream_get_getp(stream);
5907 tlv_pos = 0;
5908
5909 sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len,
5910 (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs");
5911
5912 while (tlv_pos < avail_len) {
5913 rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
5914 indent + 2, unpacked_known_tlvs);
5915 if (rv)
5916 return rv;
5917
5918 tlv_pos = stream_get_getp(stream) - tlv_start;
5919 }
5920
5921 return 0;
5922 }
5923
5924 int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
5925 struct isis_tlvs **dest, const char **log)
5926 {
5927 static struct sbuf logbuf;
5928 int indent = 0;
5929 int rv;
5930 struct isis_tlvs *result;
5931
5932 if (!sbuf_buf(&logbuf))
5933 sbuf_init(&logbuf, NULL, 0);
5934
5935 sbuf_reset(&logbuf);
5936 if (avail_len > STREAM_READABLE(stream)) {
5937 sbuf_push(&logbuf, indent,
5938 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
5939 avail_len, STREAM_READABLE(stream));
5940 return 1;
5941 }
5942
5943 result = isis_alloc_tlvs();
5944 rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
5945 indent, NULL);
5946
5947 *log = sbuf_buf(&logbuf);
5948 *dest = result;
5949
5950 return rv;
5951 }
5952
5953 #define TLV_OPS(_name_, _desc_) \
5954 static const struct tlv_ops tlv_##_name_##_ops = { \
5955 .name = _desc_, .unpack = unpack_tlv_##_name_, \
5956 }
5957
5958 #define ITEM_TLV_OPS(_name_, _desc_) \
5959 static const struct tlv_ops tlv_##_name_##_ops = { \
5960 .name = _desc_, \
5961 .unpack = unpack_tlv_with_items, \
5962 \
5963 .pack_item = pack_item_##_name_, \
5964 .free_item = free_item_##_name_, \
5965 .unpack_item = unpack_item_##_name_, \
5966 .format_item = format_item_##_name_, \
5967 .copy_item = copy_item_##_name_}
5968
5969 #define SUBTLV_OPS(_name_, _desc_) \
5970 static const struct tlv_ops subtlv_##_name_##_ops = { \
5971 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
5972 }
5973
5974 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
5975 ITEM_TLV_OPS(_name_, _desc_)
5976
5977 ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
5978 ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
5979 ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
5980 ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
5981 ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
5982 TLV_OPS(purge_originator, "TLV 13 Purge Originator Identification");
5983 ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
5984 ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
5985 TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
5986 ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
5987 TLV_OPS(te_router_id, "TLV 134 TE Router ID");
5988 ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
5989 TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
5990 TLV_OPS(te_router_id_ipv6, "TLV 140 IPv6 TE Router ID");
5991 TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
5992 ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
5993 TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
5994 ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
5995 ITEM_TLV_OPS(global_ipv6_address, "TLV 233 Global IPv6 Interface Address");
5996 ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
5997 TLV_OPS(router_cap, "TLV 242 Router Capability");
5998
5999 ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
6000 SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
6001
6002 static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
6003 [ISIS_CONTEXT_LSP] = {
6004 [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
6005 [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
6006 [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
6007 [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
6008 [ISIS_TLV_AUTH] = &tlv_auth_ops,
6009 [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
6010 [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
6011 [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
6012 [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
6013 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
6014 [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
6015 [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
6016 [ISIS_TLV_TE_ROUTER_ID_IPV6] = &tlv_te_router_id_ipv6_ops,
6017 [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
6018 [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
6019 [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
6020 [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
6021 [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
6022 [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
6023 [ISIS_TLV_GLOBAL_IPV6_ADDRESS] = &tlv_global_ipv6_address_ops,
6024 [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
6025 [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
6026 [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
6027 [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
6028 [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops,
6029 },
6030 [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
6031 [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
6032 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
6033 },
6034 [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
6035 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
6036 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
6037 }
6038 };
6039
6040 /* Accessor functions */
6041
6042 void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd)
6043 {
6044 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
6045 init_item_list(&tlvs->isis_auth);
6046
6047 if (passwd->type == ISIS_PASSWD_TYPE_UNUSED)
6048 return;
6049
6050 struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth));
6051
6052 auth->type = passwd->type;
6053
6054 auth->plength = passwd->len;
6055 memcpy(auth->passwd, passwd->passwd,
6056 MIN(sizeof(auth->passwd), sizeof(passwd->passwd)));
6057
6058 if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) {
6059 auth->length = passwd->len;
6060 memcpy(auth->value, passwd->passwd,
6061 MIN(sizeof(auth->value), sizeof(passwd->passwd)));
6062 }
6063
6064 append_item(&tlvs->isis_auth, (struct isis_item *)auth);
6065 }
6066
6067 void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
6068 struct list *addresses)
6069 {
6070 struct listnode *node;
6071 struct iso_address *area_addr;
6072
6073 for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) {
6074 struct isis_area_address *a =
6075 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
6076
6077 a->len = area_addr->addr_len;
6078 memcpy(a->addr, area_addr->area_addr, ISO_ADDR_SIZE);
6079 append_item(&tlvs->area_addresses, (struct isis_item *)a);
6080 }
6081 }
6082
6083 void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors)
6084 {
6085 struct listnode *node;
6086 uint8_t *snpa;
6087
6088 for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) {
6089 struct isis_lan_neighbor *n =
6090 XCALLOC(MTYPE_ISIS_TLV, sizeof(*n));
6091
6092 memcpy(n->mac, snpa, 6);
6093 append_item(&tlvs->lan_neighbor, (struct isis_item *)n);
6094 }
6095 }
6096
6097 void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
6098 struct nlpids *nlpids)
6099 {
6100 tlvs->protocols_supported.count = nlpids->count;
6101 XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
6102 if (nlpids->count) {
6103 tlvs->protocols_supported.protocols =
6104 XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
6105 memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids,
6106 nlpids->count);
6107 } else {
6108 tlvs->protocols_supported.protocols = NULL;
6109 }
6110 }
6111
6112 void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
6113 bool overload, bool attached)
6114 {
6115 struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i));
6116
6117 i->overload = overload;
6118 i->attached = attached;
6119 i->mtid = mtid;
6120 append_item(&tlvs->mt_router_info, (struct isis_item *)i);
6121 }
6122
6123 void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr)
6124 {
6125 struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
6126 a->addr = *addr;
6127 append_item(&tlvs->ipv4_address, (struct isis_item *)a);
6128 }
6129
6130
6131 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
6132 struct list *addresses)
6133 {
6134 struct listnode *node;
6135 struct prefix_ipv4 *ip_addr;
6136 unsigned int addr_count = 0;
6137
6138 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
6139 isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix);
6140 addr_count++;
6141 if (addr_count >= 63)
6142 break;
6143 }
6144 }
6145
6146 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
6147 struct list *addresses)
6148 {
6149 struct listnode *node;
6150 struct prefix_ipv6 *ip_addr;
6151 unsigned int addr_count = 0;
6152
6153 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
6154 if (addr_count >= 15)
6155 break;
6156
6157 struct isis_ipv6_address *a =
6158 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
6159
6160 a->addr = ip_addr->prefix;
6161 append_item(&tlvs->ipv6_address, (struct isis_item *)a);
6162 addr_count++;
6163 }
6164 }
6165
6166 void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs *tlvs,
6167 struct list *addresses)
6168 {
6169 struct listnode *node;
6170 struct prefix_ipv6 *ip_addr;
6171 unsigned int addr_count = 0;
6172
6173 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
6174 if (addr_count >= 15)
6175 break;
6176
6177 struct isis_ipv6_address *a =
6178 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
6179
6180 a->addr = ip_addr->prefix;
6181 append_item(&tlvs->global_ipv6_address, (struct isis_item *)a);
6182 addr_count++;
6183 }
6184 }
6185
6186 typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
6187 struct stream *stream,
6188 struct isis_auth *auth, bool is_lsp);
6189
6190 static bool auth_validator_cleartxt(struct isis_passwd *passwd,
6191 struct stream *stream,
6192 struct isis_auth *auth, bool is_lsp)
6193 {
6194 return (auth->length == passwd->len
6195 && !memcmp(auth->value, passwd->passwd, passwd->len));
6196 }
6197
6198 static bool auth_validator_hmac_md5(struct isis_passwd *passwd,
6199 struct stream *stream,
6200 struct isis_auth *auth, bool is_lsp)
6201 {
6202 uint8_t digest[16];
6203 uint16_t checksum;
6204 uint16_t rem_lifetime;
6205
6206 if (is_lsp)
6207 safe_auth_md5(stream, &checksum, &rem_lifetime);
6208
6209 memset(STREAM_DATA(stream) + auth->offset, 0, 16);
6210 #ifdef CRYPTO_OPENSSL
6211 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), passwd->passwd,
6212 passwd->len, STREAM_DATA(stream),
6213 stream_get_endp(stream), NULL, NULL);
6214
6215 memcpy(digest, result, 16);
6216 #elif CRYPTO_INTERNAL
6217 hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd,
6218 passwd->len, digest);
6219 #endif
6220 memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16);
6221
6222 bool rv = !memcmp(digest, auth->value, 16);
6223
6224 if (is_lsp)
6225 restore_auth_md5(stream, checksum, rem_lifetime);
6226
6227 return rv;
6228 }
6229
6230 static const auth_validator_func auth_validators[] = {
6231 [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt,
6232 [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5,
6233 };
6234
6235 int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
6236 struct stream *stream, bool is_lsp)
6237 {
6238 /* If no auth is set, always pass authentication */
6239 if (!passwd->type)
6240 return ISIS_AUTH_OK;
6241
6242 /* If we don't known how to validate the auth, return invalid */
6243 if (passwd->type >= array_size(auth_validators)
6244 || !auth_validators[passwd->type])
6245 return ISIS_AUTH_NO_VALIDATOR;
6246
6247 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
6248 struct isis_auth *auth;
6249 for (auth = auth_head; auth; auth = auth->next) {
6250 if (auth->type == passwd->type)
6251 break;
6252 }
6253
6254 /* If matching auth TLV could not be found, return invalid */
6255 if (!auth)
6256 return ISIS_AUTH_TYPE_FAILURE;
6257
6258
6259 /* Perform validation and return result */
6260 if (auth_validators[passwd->type](passwd, stream, auth, is_lsp))
6261 return ISIS_AUTH_OK;
6262 else
6263 return ISIS_AUTH_FAILURE;
6264 }
6265
6266 bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
6267 struct list *addresses)
6268 {
6269 struct isis_area_address *addr_head;
6270
6271 addr_head = (struct isis_area_address *)tlvs->area_addresses.head;
6272 for (struct isis_area_address *addr = addr_head; addr;
6273 addr = addr->next) {
6274 struct listnode *node;
6275 struct iso_address *a;
6276
6277 for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) {
6278 if (a->addr_len == addr->len
6279 && !memcmp(a->area_addr, addr->addr, addr->len))
6280 return true;
6281 }
6282 }
6283
6284 return false;
6285 }
6286
6287 static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs,
6288 struct isis_adjacency *adj,
6289 bool *changed)
6290 {
6291 if (adj->area_address_count != tlvs->area_addresses.count) {
6292 uint32_t oc = adj->area_address_count;
6293
6294 *changed = true;
6295 adj->area_address_count = tlvs->area_addresses.count;
6296 adj->area_addresses = XREALLOC(
6297 MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses,
6298 adj->area_address_count * sizeof(*adj->area_addresses));
6299
6300 for (; oc < adj->area_address_count; oc++) {
6301 adj->area_addresses[oc].addr_len = 0;
6302 memset(&adj->area_addresses[oc].area_addr, 0,
6303 sizeof(adj->area_addresses[oc].area_addr));
6304 }
6305 }
6306
6307 struct isis_area_address *addr = NULL;
6308 for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) {
6309 if (!addr)
6310 addr = (struct isis_area_address *)
6311 tlvs->area_addresses.head;
6312 else
6313 addr = addr->next;
6314
6315 if (adj->area_addresses[i].addr_len == addr->len
6316 && !memcmp(adj->area_addresses[i].area_addr, addr->addr,
6317 addr->len)) {
6318 continue;
6319 }
6320
6321 *changed = true;
6322 adj->area_addresses[i].addr_len = addr->len;
6323 memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len);
6324 }
6325 }
6326
6327 static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
6328 struct isis_adjacency *adj,
6329 bool *changed)
6330 {
6331 bool ipv4_supported = false, ipv6_supported = false;
6332
6333 for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) {
6334 if (tlvs->protocols_supported.protocols[i] == NLPID_IP)
6335 ipv4_supported = true;
6336 if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6)
6337 ipv6_supported = true;
6338 }
6339
6340 struct nlpids reduced = {};
6341
6342 if (ipv4_supported && ipv6_supported) {
6343 reduced.count = 2;
6344 reduced.nlpids[0] = NLPID_IP;
6345 reduced.nlpids[1] = NLPID_IPV6;
6346 } else if (ipv4_supported) {
6347 reduced.count = 1;
6348 reduced.nlpids[0] = NLPID_IP;
6349 } else if (ipv6_supported) {
6350 reduced.count = 1;
6351 reduced.nlpids[0] = NLPID_IPV6;
6352 } else {
6353 reduced.count = 0;
6354 }
6355
6356 if (adj->nlpids.count == reduced.count
6357 && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count))
6358 return;
6359
6360 *changed = true;
6361 adj->nlpids.count = reduced.count;
6362 memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
6363 }
6364
6365 DEFINE_HOOK(isis_adj_ip_enabled_hook,
6366 (struct isis_adjacency * adj, int family, bool global),
6367 (adj, family, global));
6368 DEFINE_HOOK(isis_adj_ip_disabled_hook,
6369 (struct isis_adjacency * adj, int family, bool global),
6370 (adj, family, global));
6371
6372 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
6373 struct isis_adjacency *adj,
6374 bool *changed)
6375 {
6376 bool ipv4_enabled = false;
6377
6378 if (adj->ipv4_address_count == 0 && tlvs->ipv4_address.count > 0)
6379 ipv4_enabled = true;
6380 else if (adj->ipv4_address_count > 0 && tlvs->ipv4_address.count == 0)
6381 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET, false);
6382
6383 if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
6384 uint32_t oc = adj->ipv4_address_count;
6385
6386 *changed = true;
6387 adj->ipv4_address_count = tlvs->ipv4_address.count;
6388 adj->ipv4_addresses = XREALLOC(
6389 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses,
6390 adj->ipv4_address_count * sizeof(*adj->ipv4_addresses));
6391
6392 for (; oc < adj->ipv4_address_count; oc++) {
6393 memset(&adj->ipv4_addresses[oc], 0,
6394 sizeof(adj->ipv4_addresses[oc]));
6395 }
6396 }
6397
6398 struct isis_ipv4_address *addr = NULL;
6399 for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) {
6400 if (!addr)
6401 addr = (struct isis_ipv4_address *)
6402 tlvs->ipv4_address.head;
6403 else
6404 addr = addr->next;
6405
6406 if (!memcmp(&adj->ipv4_addresses[i], &addr->addr,
6407 sizeof(addr->addr)))
6408 continue;
6409
6410 *changed = true;
6411 adj->ipv4_addresses[i] = addr->addr;
6412 }
6413
6414 if (ipv4_enabled)
6415 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET, false);
6416 }
6417
6418 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
6419 struct isis_adjacency *adj,
6420 bool *changed)
6421 {
6422 bool ipv6_enabled = false;
6423
6424 if (adj->ll_ipv6_count == 0 && tlvs->ipv6_address.count > 0)
6425 ipv6_enabled = true;
6426 else if (adj->ll_ipv6_count > 0 && tlvs->ipv6_address.count == 0)
6427 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6, false);
6428
6429 if (adj->ll_ipv6_count != tlvs->ipv6_address.count) {
6430 uint32_t oc = adj->ll_ipv6_count;
6431
6432 *changed = true;
6433 adj->ll_ipv6_count = tlvs->ipv6_address.count;
6434 adj->ll_ipv6_addrs = XREALLOC(
6435 MTYPE_ISIS_ADJACENCY_INFO, adj->ll_ipv6_addrs,
6436 adj->ll_ipv6_count * sizeof(*adj->ll_ipv6_addrs));
6437
6438 for (; oc < adj->ll_ipv6_count; oc++) {
6439 memset(&adj->ll_ipv6_addrs[oc], 0,
6440 sizeof(adj->ll_ipv6_addrs[oc]));
6441 }
6442 }
6443
6444 struct isis_ipv6_address *addr = NULL;
6445 for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) {
6446 if (!addr)
6447 addr = (struct isis_ipv6_address *)
6448 tlvs->ipv6_address.head;
6449 else
6450 addr = addr->next;
6451
6452 if (!memcmp(&adj->ll_ipv6_addrs[i], &addr->addr,
6453 sizeof(addr->addr)))
6454 continue;
6455
6456 *changed = true;
6457 adj->ll_ipv6_addrs[i] = addr->addr;
6458 }
6459
6460 if (ipv6_enabled)
6461 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6, false);
6462 }
6463
6464
6465 static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
6466 struct isis_adjacency *adj,
6467 bool *changed)
6468 {
6469 bool global_ipv6_enabled = false;
6470
6471 if (adj->global_ipv6_count == 0 && tlvs->global_ipv6_address.count > 0)
6472 global_ipv6_enabled = true;
6473 else if (adj->global_ipv6_count > 0
6474 && tlvs->global_ipv6_address.count == 0)
6475 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6, true);
6476
6477 if (adj->global_ipv6_count != tlvs->global_ipv6_address.count) {
6478 uint32_t oc = adj->global_ipv6_count;
6479
6480 *changed = true;
6481 adj->global_ipv6_count = tlvs->global_ipv6_address.count;
6482 adj->global_ipv6_addrs = XREALLOC(
6483 MTYPE_ISIS_ADJACENCY_INFO, adj->global_ipv6_addrs,
6484 adj->global_ipv6_count
6485 * sizeof(*adj->global_ipv6_addrs));
6486
6487 for (; oc < adj->global_ipv6_count; oc++) {
6488 memset(&adj->global_ipv6_addrs[oc], 0,
6489 sizeof(adj->global_ipv6_addrs[oc]));
6490 }
6491 }
6492
6493 struct isis_ipv6_address *addr = NULL;
6494 for (unsigned int i = 0; i < tlvs->global_ipv6_address.count; i++) {
6495 if (!addr)
6496 addr = (struct isis_ipv6_address *)
6497 tlvs->global_ipv6_address.head;
6498 else
6499 addr = addr->next;
6500
6501 if (!memcmp(&adj->global_ipv6_addrs[i], &addr->addr,
6502 sizeof(addr->addr)))
6503 continue;
6504
6505 *changed = true;
6506 adj->global_ipv6_addrs[i] = addr->addr;
6507 }
6508
6509 if (global_ipv6_enabled)
6510 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6, true);
6511 }
6512
6513 void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
6514 bool *changed)
6515 {
6516 *changed = false;
6517
6518 tlvs_area_addresses_to_adj(tlvs, adj, changed);
6519 tlvs_protocols_supported_to_adj(tlvs, adj, changed);
6520 tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
6521 tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
6522 tlvs_global_ipv6_addresses_to_adj(tlvs, adj, changed);
6523 }
6524
6525 bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
6526 {
6527 struct isis_lan_neighbor *ne_head;
6528
6529 ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head;
6530 for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) {
6531 if (!memcmp(ne->mac, snpa, ETH_ALEN))
6532 return true;
6533 }
6534
6535 return false;
6536 }
6537
6538 void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp)
6539 {
6540 struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry));
6541
6542 entry->rem_lifetime = lsp->hdr.rem_lifetime;
6543 memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
6544 entry->checksum = lsp->hdr.checksum;
6545 entry->seqno = lsp->hdr.seqno;
6546 entry->lsp = lsp;
6547
6548 append_item(&tlvs->lsp_entries, (struct isis_item *)entry);
6549 }
6550
6551 void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
6552 uint8_t *stop_id, uint16_t num_lsps,
6553 struct lspdb_head *head,
6554 struct isis_lsp **last_lsp)
6555 {
6556 struct isis_lsp searchfor;
6557 struct isis_lsp *first, *lsp;
6558
6559 memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
6560 first = lspdb_find_gteq(head, &searchfor);
6561 if (!first)
6562 return;
6563
6564 frr_each_from (lspdb, head, lsp, first) {
6565 if (memcmp(lsp->hdr.lsp_id, stop_id, sizeof(lsp->hdr.lsp_id))
6566 > 0 || tlvs->lsp_entries.count == num_lsps)
6567 break;
6568
6569 isis_tlvs_add_lsp_entry(tlvs, lsp);
6570 *last_lsp = lsp;
6571 }
6572 }
6573
6574 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
6575 const char *hostname)
6576 {
6577 XFREE(MTYPE_ISIS_TLV, tlvs->hostname);
6578 if (hostname)
6579 tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
6580 }
6581
6582 /* Init Router Capability TLV parameters */
6583 struct isis_router_cap *isis_tlvs_init_router_capability(struct isis_tlvs *tlvs)
6584 {
6585 tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
6586
6587 /* init SR algo list content to the default value */
6588 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
6589 tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET;
6590
6591 return tlvs->router_cap;
6592 }
6593
6594 #ifndef FABRICD
6595 void isis_tlvs_set_router_capability_fad(struct isis_tlvs *tlvs,
6596 struct flex_algo *fa, int algorithm,
6597 uint8_t *sysid)
6598 {
6599 struct isis_router_cap_fad *rcap_fad;
6600
6601 assert(tlvs->router_cap);
6602
6603 rcap_fad = tlvs->router_cap->fads[algorithm];
6604
6605 if (!rcap_fad)
6606 rcap_fad = XCALLOC(MTYPE_ISIS_TLV,
6607 sizeof(struct isis_router_cap_fad));
6608
6609 memset(rcap_fad->sysid, 0, ISIS_SYS_ID_LEN + 2);
6610 memcpy(rcap_fad->sysid, sysid, ISIS_SYS_ID_LEN);
6611
6612 memcpy(&rcap_fad->fad, fa, sizeof(struct flex_algo));
6613
6614 rcap_fad->fad.admin_group_exclude_any.bitmap.data = NULL;
6615 rcap_fad->fad.admin_group_include_any.bitmap.data = NULL;
6616 rcap_fad->fad.admin_group_include_all.bitmap.data = NULL;
6617
6618 admin_group_copy(&rcap_fad->fad.admin_group_exclude_any,
6619 &fa->admin_group_exclude_any);
6620 admin_group_copy(&rcap_fad->fad.admin_group_include_any,
6621 &fa->admin_group_include_any);
6622 admin_group_copy(&rcap_fad->fad.admin_group_include_all,
6623 &fa->admin_group_include_all);
6624
6625 tlvs->router_cap->fads[algorithm] = rcap_fad;
6626 }
6627 #endif /* ifndef FABRICD */
6628
6629 int isis_tlvs_sr_algo_count(const struct isis_router_cap *cap)
6630 {
6631 int count = 0;
6632
6633 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
6634 if (cap->algo[i] != SR_ALGORITHM_UNSET)
6635 count++;
6636 return count;
6637 }
6638
6639 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
6640 const struct in_addr *id)
6641 {
6642 XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id);
6643 if (!id)
6644 return;
6645 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
6646 memcpy(tlvs->te_router_id, id, sizeof(*id));
6647 }
6648
6649 void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs *tlvs,
6650 const struct in6_addr *id)
6651 {
6652 XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id_ipv6);
6653 if (!id)
6654 return;
6655 tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
6656 memcpy(tlvs->te_router_id_ipv6, id, sizeof(*id));
6657 }
6658
6659 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
6660 struct prefix_ipv4 *dest, uint8_t metric)
6661 {
6662 struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
6663
6664 r->metric = metric;
6665 memcpy(&r->prefix, dest, sizeof(*dest));
6666 apply_mask_ipv4(&r->prefix);
6667 append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
6668 }
6669
6670 /* Add IS-IS SR Adjacency-SID subTLVs */
6671 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
6672 struct isis_adj_sid *adj)
6673 {
6674 append_item(&exts->adj_sid, (struct isis_item *)adj);
6675 SET_SUBTLV(exts, EXT_ADJ_SID);
6676 }
6677
6678 /* Delete IS-IS SR Adjacency-SID subTLVs */
6679 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
6680 struct isis_adj_sid *adj)
6681 {
6682 delete_item(&exts->adj_sid, (struct isis_item *)adj);
6683 XFREE(MTYPE_ISIS_SUBTLV, adj);
6684 if (exts->adj_sid.count == 0)
6685 UNSET_SUBTLV(exts, EXT_ADJ_SID);
6686 }
6687
6688 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
6689 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
6690 struct isis_lan_adj_sid *lan)
6691 {
6692 append_item(&exts->lan_sid, (struct isis_item *)lan);
6693 SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
6694 }
6695
6696 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
6697 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
6698 struct isis_lan_adj_sid *lan)
6699 {
6700 delete_item(&exts->lan_sid, (struct isis_item *)lan);
6701 XFREE(MTYPE_ISIS_SUBTLV, lan);
6702 if (exts->lan_sid.count == 0)
6703 UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID);
6704 }
6705
6706 void isis_tlvs_del_asla_flex_algo(struct isis_ext_subtlvs *ext,
6707 struct isis_asla_subtlvs *asla)
6708 {
6709 admin_group_term(&asla->ext_admin_group);
6710 listnode_delete(ext->aslas, asla);
6711 XFREE(MTYPE_ISIS_SUBTLV, asla);
6712 }
6713
6714 struct isis_asla_subtlvs *
6715 isis_tlvs_find_alloc_asla(struct isis_ext_subtlvs *ext, uint8_t standard_apps)
6716 {
6717 struct isis_asla_subtlvs *asla;
6718 struct listnode *node;
6719
6720 if (!list_isempty(ext->aslas)) {
6721 for (ALL_LIST_ELEMENTS_RO(ext->aslas, node, asla)) {
6722 if (CHECK_FLAG(asla->standard_apps, standard_apps))
6723 return asla;
6724 }
6725 }
6726
6727 asla = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_asla_subtlvs));
6728 admin_group_init(&asla->ext_admin_group);
6729 SET_FLAG(asla->standard_apps, standard_apps);
6730 SET_FLAG(asla->user_def_apps, standard_apps);
6731 asla->standard_apps_length = ASLA_APP_IDENTIFIER_BIT_LENGTH;
6732 asla->user_def_apps_length = ASLA_APP_IDENTIFIER_BIT_LENGTH;
6733
6734 listnode_add(ext->aslas, asla);
6735 return asla;
6736 }
6737
6738 void isis_tlvs_free_asla(struct isis_ext_subtlvs *ext, uint8_t standard_apps)
6739 {
6740 struct isis_asla_subtlvs *asla;
6741 struct listnode *node;
6742
6743 if (!ext)
6744 return;
6745
6746 for (ALL_LIST_ELEMENTS_RO(ext->aslas, node, asla)) {
6747 if (!CHECK_FLAG(asla->standard_apps, standard_apps))
6748 continue;
6749 isis_tlvs_del_asla_flex_algo(ext, asla);
6750 break;
6751 }
6752 }
6753
6754 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
6755 struct prefix_ipv4 *dest, uint32_t metric,
6756 bool external,
6757 struct sr_prefix_cfg **pcfgs)
6758 {
6759 struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
6760
6761 r->metric = metric;
6762 memcpy(&r->prefix, dest, sizeof(*dest));
6763 apply_mask_ipv4(&r->prefix);
6764
6765 if (pcfgs) {
6766 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
6767 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
6768 struct isis_prefix_sid *psid;
6769 struct sr_prefix_cfg *pcfg = pcfgs[i];
6770
6771 if (!pcfg)
6772 continue;
6773
6774 psid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
6775 isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
6776 append_item(&r->subtlvs->prefix_sids,
6777 (struct isis_item *)psid);
6778 }
6779 }
6780
6781 append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
6782 }
6783
6784 void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
6785 struct prefix_ipv6 *dest, uint32_t metric,
6786 bool external, struct sr_prefix_cfg **pcfgs)
6787 {
6788 struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
6789
6790 r->metric = metric;
6791 memcpy(&r->prefix, dest, sizeof(*dest));
6792 apply_mask_ipv6(&r->prefix);
6793 if (pcfgs) {
6794 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
6795 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
6796 struct isis_prefix_sid *psid;
6797 struct sr_prefix_cfg *pcfg = pcfgs[i];
6798
6799 if (!pcfg)
6800 continue;
6801
6802 psid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
6803 isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
6804 append_item(&r->subtlvs->prefix_sids,
6805 (struct isis_item *)psid);
6806 }
6807 }
6808
6809 struct isis_item_list *l;
6810 l = (mtid == ISIS_MT_IPV4_UNICAST)
6811 ? &tlvs->ipv6_reach
6812 : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
6813 append_item(l, (struct isis_item *)r);
6814 }
6815
6816 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
6817 struct prefix_ipv6 *dest,
6818 struct prefix_ipv6 *src,
6819 uint32_t metric)
6820 {
6821 isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric, false, NULL);
6822 struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
6823 mtid);
6824
6825 struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
6826 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
6827 r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
6828 memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
6829 }
6830
6831 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
6832 uint8_t metric)
6833 {
6834 struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
6835
6836 r->metric = metric;
6837 memcpy(r->id, id, sizeof(r->id));
6838 append_item(&tlvs->oldstyle_reach, (struct isis_item *)r);
6839 }
6840
6841 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
6842 uint8_t *id, uint32_t metric,
6843 struct isis_ext_subtlvs *exts)
6844 {
6845 struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
6846
6847 memcpy(r->id, id, sizeof(r->id));
6848 r->metric = metric;
6849 if (exts)
6850 r->subtlvs = copy_item_ext_subtlvs(exts, mtid);
6851
6852 struct isis_item_list *l;
6853 if ((mtid == ISIS_MT_IPV4_UNICAST) || (mtid == ISIS_MT_DISABLE))
6854 l = &tlvs->extended_reach;
6855 else
6856 l = isis_get_mt_items(&tlvs->mt_reach, mtid);
6857 append_item(l, (struct isis_item *)r);
6858 }
6859
6860 void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
6861 enum isis_threeway_state state,
6862 uint32_t local_circuit_id,
6863 const uint8_t *neighbor_id,
6864 uint32_t neighbor_circuit_id)
6865 {
6866 assert(!tlvs->threeway_adj);
6867
6868 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
6869 tlvs->threeway_adj->state = state;
6870 tlvs->threeway_adj->local_circuit_id = local_circuit_id;
6871
6872 if (neighbor_id) {
6873 tlvs->threeway_adj->neighbor_set = true;
6874 memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6);
6875 tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id;
6876 }
6877 }
6878
6879 void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
6880 bool has_tier, bool is_leaf, bool is_spine,
6881 bool is_backup)
6882 {
6883 assert(!tlvs->spine_leaf);
6884
6885 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
6886
6887 if (has_tier) {
6888 tlvs->spine_leaf->tier = tier;
6889 }
6890
6891 tlvs->spine_leaf->has_tier = has_tier;
6892 tlvs->spine_leaf->is_leaf = is_leaf;
6893 tlvs->spine_leaf->is_spine = is_spine;
6894 tlvs->spine_leaf->is_backup = is_backup;
6895 }
6896
6897 struct isis_mt_router_info *
6898 isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
6899 {
6900 if (!tlvs || tlvs->mt_router_info_empty)
6901 return NULL;
6902
6903 struct isis_mt_router_info *rv;
6904 for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv;
6905 rv = rv->next) {
6906 if (rv->mtid == mtid)
6907 return rv;
6908 }
6909
6910 return NULL;
6911 }
6912
6913 void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
6914 const uint8_t *generator,
6915 const uint8_t *sender)
6916 {
6917 assert(!tlvs->purge_originator);
6918
6919 tlvs->purge_originator = XCALLOC(MTYPE_ISIS_TLV,
6920 sizeof(*tlvs->purge_originator));
6921 memcpy(tlvs->purge_originator->generator, generator,
6922 sizeof(tlvs->purge_originator->generator));
6923 if (sender) {
6924 tlvs->purge_originator->sender_set = true;
6925 memcpy(tlvs->purge_originator->sender, sender,
6926 sizeof(tlvs->purge_originator->sender));
6927 }
6928 }