1 /*
2 * IFLA_LINKINFO netlink attribute decoding check.
3 *
4 * Copyright (c) 2018-2023 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11
12 #include <inttypes.h>
13 #include <math.h>
14 #include <stdio.h>
15 #include <stddef.h>
16 #include <unistd.h>
17 #include <arpa/inet.h>
18
19 #include "test_nlattr.h"
20 #include "xmalloc.h"
21
22 #include <linux/if.h>
23 #include <linux/if_arp.h>
24 #include <linux/if_bridge.h>
25 #include <linux/if_link.h>
26 #include <linux/rtnetlink.h>
27
28 #define XLAT_MACROS_ONLY
29 #include <xlat/rtnl_link_attrs.h>
30 #include <xlat/rtnl_ifla_info_attrs.h>
31 #undef XLAT_MACROS_ONLY
32
33 #define IFLA_ATTR IFLA_LINKINFO
34 #include "nlattr_ifla.h"
35
36 #define COMMA ,
37 #define TEST_UNKNOWN_TUNNELS(fd_, nlh0_, kindtype_, objtype_, objtype_str_, \
38 obj_, objsz_, arrstrs_, ...) \
39 do { \
40 /* 64 is guestimate for maximum unknown type len */ \
41 char buf[8 * 2 + 64 + objsz_]; \
42 const char *const *arrstrs[] = arrstrs_; \
43 const char *const **arrstrs_pos = arrstrs; \
44 const char *const *arrstr = *arrstrs_pos; \
45 \
46 for (const char *type = arrstr ? arrstr[0] : NULL; \
47 type && arrstr; \
48 type = (++arrstr)[0] ? arrstr[0] \
49 : (++arrstrs_pos)[0] \
50 ? (arrstr = arrstrs_pos[0])[0] \
51 : NULL) \
52 { \
53 size_t type_len = strlen(type) + 1; \
54 \
55 if (type_len > 64) \
56 error_msg_and_fail("Unexpectedly long " \
57 "unknown type: \"%s\" " \
58 "(length is %zu)", \
59 type, type_len); \
60 \
61 struct nlattr obj_nla = { \
62 .nla_len = NLA_HDRLEN + (objsz_), \
63 .nla_type = (objtype_), \
64 }; \
65 \
66 char *pos = buf; \
67 memcpy(pos, type, type_len); \
68 pos += NLA_ALIGN(type_len); \
69 memcpy(pos, &obj_nla, sizeof(obj_nla)); \
70 pos += sizeof(obj_nla); \
71 memcpy(pos, (obj_), (objsz_)); \
72 \
73 TEST_NLATTR_EX_((fd_), \
74 (nlh0_) - hdrlen - (pos - buf), \
75 hdrlen + NLA_HDRLEN, \
76 init_ifinfomsg, print_ifinfomsg, \
77 (kindtype_), #kindtype_, \
78 type_len, objsz_ + (pos - buf), \
79 buf, objsz_ + (pos - buf), \
80 printf("\"%s\"]", type); \
81 printf(", [{nla_len=%zu" \
82 ", nla_type=%s}, ", \
83 (objsz_) + NLA_HDRLEN, \
84 (objtype_str_)); \
85 \
86 { __VA_ARGS__; } \
87 \
88 printf("]")); \
89 } \
90 } while (0)
91
92 #define TEST_LINKINFO_(fd_, nlh0_, kindtype_, nla_type_, nla_type_str_, \
93 tuntype_, obj_, objsz_, pattern_, fallback_func_, ...) \
94 do { \
95 size_t tuntype_len = strlen(tuntype_) + 1; \
96 char *buf = tail_alloc(NLA_ALIGN(tuntype_len) \
97 + NLA_HDRLEN + (objsz_)); \
98 char *pos = buf; \
99 \
100 struct nlattr obj_nla = { \
101 .nla_len = NLA_HDRLEN + (objsz_), \
102 .nla_type = (nla_type_), \
103 }; \
104 \
105 memcpy(pos, (tuntype_), tuntype_len); \
106 pos += NLA_ALIGN(tuntype_len); \
107 memcpy(pos, &obj_nla, sizeof(obj_nla)); \
108 pos += sizeof(obj_nla); \
109 memcpy(pos, &(obj_), (objsz_)); \
110 \
111 if (fallback_func_ == print_quoted_hex) { \
112 TEST_NLATTR_EX_((fd_), \
113 (nlh0_) - NLA_HDRLEN, \
114 hdrlen + NLA_HDRLEN, \
115 init_ifinfomsg, print_ifinfomsg, \
116 (kindtype_), #kindtype_, \
117 tuntype_len, \
118 objsz_ + (pos - buf) - 1, \
119 buf, objsz_ + (pos - buf) - 1, \
120 printf("\"%s\"]", (tuntype_)); \
121 printf(", [{nla_len=%zu" \
122 ", nla_type=%s}, ", \
123 (objsz_) + NLA_HDRLEN, \
124 (nla_type_str_)); \
125 (fallback_func_)((obj_), \
126 (objsz_) - 1); \
127 printf("]")); \
128 } \
129 \
130 TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN, \
131 hdrlen + NLA_HDRLEN, \
132 init_ifinfomsg, print_ifinfomsg, \
133 (kindtype_), #kindtype_, \
134 tuntype_len, objsz_ + (pos - buf), \
135 buf, objsz_ + (pos - buf) - 1, \
136 printf("\"%s\"]", (tuntype_)); \
137 printf(", [{nla_len=%zu, nla_type=%s}, ", \
138 (objsz_) + NLA_HDRLEN, \
139 (nla_type_str_)); \
140 printf("%p]", \
141 RTA_DATA(NLMSG_ATTR(nlh, \
142 (hdrlen + NLA_HDRLEN + (pos - buf)))) \
143 ) \
144 ); \
145 \
146 TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN, \
147 hdrlen + NLA_HDRLEN, \
148 init_ifinfomsg, print_ifinfomsg, \
149 (kindtype_), #kindtype_, \
150 tuntype_len, objsz_ + (pos - buf), \
151 buf, objsz_ + (pos - buf), \
152 printf("\"%s\"]", (tuntype_)); \
153 printf(", [{nla_len=%zu, nla_type=%s}, ", \
154 (objsz_) + NLA_HDRLEN, \
155 (nla_type_str_)); \
156 \
157 { __VA_ARGS__; } \
158 \
159 printf("]")); \
160 } while (0)
161
162 #define TEST_LINKINFO(fd_, nlh0_, kindtype_, nla_type_, tuntype_, \
163 obj_, pattern_, fallback_func_, ...) \
164 TEST_LINKINFO_((fd_), (nlh0_), kindtype_, nla_type_, #nla_type_, \
165 (tuntype_), (obj_), sizeof(obj_), pattern_, \
166 fallback_func_, __VA_ARGS__)
167
168 #define TEST_NESTED_LINKINFO(fd_, nlh0_, kindtype_, \
169 nla_type_, nla_type_str_, tuntype_, \
170 subnla_type_, subnla_type_str_, \
171 obj_, pattern_, ...) \
172 do { \
173 size_t tuntype_len = strlen(tuntype_) + 1; \
174 struct { \
175 size_t sz; \
176 const char *str; \
177 } attrs[] = { __VA_ARGS__ }; \
178 size_t tunhdrlen; \
179 size_t buflen = NLA_ALIGN(tuntype_len) + NLA_HDRLEN; \
180 size_t attrsz = 0; \
181 \
182 for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
183 attrsz += NLA_HDRLEN + NLA_ALIGN(attrs[i].sz); \
184 \
185 buflen += attrsz; \
186 \
187 char *buf = tail_alloc(buflen); \
188 char *pos = buf; \
189 \
190 struct nlattr nla = { \
191 .nla_len = NLA_HDRLEN + attrsz, \
192 .nla_type = (nla_type_), \
193 }; \
194 \
195 memcpy(pos, (tuntype_), tuntype_len); \
196 pos += NLA_ALIGN(tuntype_len); \
197 memcpy(pos, &nla, sizeof(nla)); \
198 pos += sizeof(nla); \
199 \
200 tunhdrlen = pos - buf; \
201 \
202 nla.nla_type = subnla_type_; \
203 \
204 for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) { \
205 nla.nla_len = NLA_HDRLEN + attrs[i].sz; \
206 memcpy(pos, &nla, sizeof(nla)); \
207 pos += sizeof(nla); \
208 \
209 memcpy(pos, &(obj_), MIN(sizeof(obj_), attrs[i].sz)); \
210 \
211 if (attrs[i].sz > sizeof(obj_)) \
212 memcpy(pos + sizeof(obj_), \
213 &(pattern_), \
214 attrs[i].sz - sizeof(obj_)); \
215 \
216 pos += NLA_ALIGN(attrs[i].sz); \
217 } \
218 \
219 TEST_NLATTR_EX_((fd_), (nlh0_) - hdrlen - tunhdrlen, \
220 hdrlen + NLA_HDRLEN, \
221 init_ifinfomsg, print_ifinfomsg, \
222 (kindtype_), #kindtype_, \
223 tuntype_len, buflen, \
224 buf, buflen, \
225 printf("\"%s\"]", (tuntype_)); \
226 printf(", [{nla_len=%zu, nla_type=%s}, [", \
227 attrsz + NLA_HDRLEN, \
228 (nla_type_str_)); \
229 \
230 for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
231 printf("%s%s{nla_len=%zu" \
232 ", nla_type=%s}%s%s%s", \
233 i ? ", " : "", \
234 attrs[i].str ? "[": "", \
235 attrs[i].sz + NLA_HDRLEN, \
236 subnla_type_str_, \
237 attrs[i].str ? ", ": "", \
238 attrs[i].str ?: "", \
239 attrs[i].str ? "]" : ""); \
240 \
241 printf("]]")); \
242 } while (0)
243
244 int
245 main(void)
246 {
247 static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd };
248 static const char *const unsupported_tunnel_types[] = {
249 "batadv", "bareudp", "bond",
250 "caif", "cfhsi",
251 "dummy",
252 "erspan",
253 "geneve", "gre", "gretap", "gtp",
254 "hsr",
255 "ifb", "ip6erspan", "ip6gre", "ip6gretap", "ip6tnl",
256 "ipip", "ipoib", "ipvlan", "ipvtap",
257 "lowpan",
258 "macsec", "macvlan", "macvtap",
259 "netdevsim", "nlmon",
260 "openvswitch",
261 "ppp",
262 "rmnet",
263 "sit",
264 "team",
265 "vcan", "veth", "vlan", "vrf", "vsockmon",
266 "vti", "vti6", "vxcan", "vxlan",
267 "wireguard", "wwan",
268 "xfrm",
269 NULL
270 };
271 static const char *const unsupported_xstats_types[] = {
272 "bridge",
273 "tun",
274 NULL
275 };
276 static const char *const unsupported_data_types[] = {
277 "can",
278 NULL
279 };
280 static const char *const unsupported_slave_data_types[] = {
281 "can",
282 "tun",
283 NULL
284 };
285 /* supported by at least one attribute */
286 static const char *const supported_tunnel_types[] = {
287 "bridge",
288 "can",
289 "tun",
290 NULL
291 };
292
293 skip_if_unavailable("/proc/self/fd/");
294
295 const int fd = create_nl_socket(NETLINK_ROUTE);
296
297 const unsigned int hdrlen = sizeof(struct ifinfomsg);
298 void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 2 * NLA_HDRLEN + 256);
299
300 static char pattern[4096];
301 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
302
303
304 /* unknown AF_INFO_* type */
305 TEST_NESTED_NLATTR_OBJECT(fd, nlh0, hdrlen,
306 init_ifinfomsg, print_ifinfomsg,
307 IFLA_INFO_UNSPEC, pattern, unknown_msg,
308 printf("\"\\xab\\xac\\xdb\\xcd\""));
309
310 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
311 init_ifinfomsg, print_ifinfomsg,
312 6, "0x6 /* IFLA_INFO_??? */", pattern,
313 unknown_msg, print_quoted_hex, 1,
314 printf("\"\\xab\\xac\\xdb\\xcd\""));
315
316
317 /* IFLA_INFO_KIND */
318 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
319 init_ifinfomsg, print_ifinfomsg,
320 IFLA_INFO_KIND, "IFLA_INFO_KIND", pattern,
321 unknown_msg, print_quoted_stringn, 1,
322 printf("\"\\253\\254\\333\\315\"..."));
323
324
325 /* IFLA_INFO_KIND + IFLA_INFO_UNSPEC */
326 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
327 IFLA_INFO_UNSPEC, "IFLA_INFO_UNSPEC",
328 unknown_msg, sizeof(unknown_msg),
329 {unsupported_tunnel_types COMMA
330 supported_tunnel_types COMMA
331 NULL},
332 printf("\"\\xab\\xac\\xdb\\xcd\""));
333
334
335 /* IFLA_INFO_KIND + IFLA_INFO_KIND */
336 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
337 IFLA_INFO_KIND, "IFLA_INFO_KIND",
338 unknown_msg, sizeof(unknown_msg),
339 {unsupported_tunnel_types COMMA
340 supported_tunnel_types COMMA
341 NULL},
342 printf("\"\\253\\254\\333\\315\"..."));
343
344
345 /* IFLA_INFO_KIND + IFLA_INFO_DATA */
346 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
347 IFLA_INFO_DATA, "IFLA_INFO_DATA",
348 unknown_msg, sizeof(unknown_msg),
349 {unsupported_tunnel_types COMMA
350 unsupported_data_types COMMA
351 NULL},
352 printf("\"\\xab\\xac\\xdb\\xcd\""));
353
354 struct val_name {
355 unsigned int val;
356 const char *name;
357 };
358
359 static const uint64_t u64_val = 0xdeadc0defacefeedULL;
360 static const uint32_t u32_val = 0xbadc0dedU;
361 static const uint16_t u16_val = 0xdeed;
362 static const uint8_t u8_val = 0xa1;
363
364 /* bridge attrs */
365 static const struct val_name und_br_attrs[] = {
366 { 0, "IFLA_BR_UNSPEC" },
367 { 21, "IFLA_BR_FDB_FLUSH" },
368 { 40, "IFLA_BR_PAD" },
369 { 48, "0x30 /* IFLA_BR_??? */" },
370 };
371
372 for (size_t k = 0; k < ARRAY_SIZE(und_br_attrs); k++) {
373 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
374 2, "IFLA_INFO_DATA", "bridge",
375 und_br_attrs[k].val, und_br_attrs[k].name,
376 unknown_msg, pattern,
377 { 2, "\"\\xab\\xac\"" },
378 { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
379 { 6,
380 "\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
381 { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
382 "\\x63\\x64\"" },
383 { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
384 "\\x63\\x64\\x65\\x66\"" });
385 }
386
387 static const struct val_name hwa_br_attrs[] = {
388 { 20, "IFLA_BR_GROUP_ADDR" },
389 };
390
391 for (size_t k = 0; k < ARRAY_SIZE(hwa_br_attrs); k++) {
392 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
393 2, "IFLA_INFO_DATA", "bridge",
394 hwa_br_attrs[k].val, hwa_br_attrs[k].name,
395 unknown_msg, pattern,
396 { 2, "ab:ac" },
397 { 4, "ab:ac:db:cd" },
398 { 6, "ab:ac:db:cd:61:62" },
399 { 8, "ab:ac:db:cd:61:62:63:64" },
400 { 10, "ab:ac:db:cd:61:62:63:64:65:66" });
401 }
402
403 static const struct val_name c_t_br_attrs[] = {
404 { 1, "IFLA_BR_FORWARD_DELAY" },
405 { 2, "IFLA_BR_HELLO_TIME" },
406 { 3, "IFLA_BR_MAX_AGE" },
407 { 4, "IFLA_BR_AGEING_TIME" },
408 { 16, "IFLA_BR_HELLO_TIMER" },
409 { 17, "IFLA_BR_TCN_TIMER" },
410 { 18, "IFLA_BR_TOPOLOGY_CHANGE_TIMER" },
411 { 19, "IFLA_BR_GC_TIMER" },
412 { 30, "IFLA_BR_MCAST_LAST_MEMBER_INTVL" },
413 { 31, "IFLA_BR_MCAST_MEMBERSHIP_INTVL" },
414 { 32, "IFLA_BR_MCAST_QUERIER_INTVL" },
415 { 33, "IFLA_BR_MCAST_QUERY_INTVL" },
416 { 34, "IFLA_BR_MCAST_QUERY_RESPONSE_INTVL" },
417 { 35, "IFLA_BR_MCAST_STARTUP_QUERY_INTVL" },
418 };
419 char sz7_str[64];
420 char sz8_str[64];
421
422 clock_t_str(BE_LE(0xdeadc0defacefe, 0xadc0defacefeed),
423 ARRSZ_PAIR(sz7_str));
424 clock_t_str(0xdeadc0defacefeed, ARRSZ_PAIR(sz8_str));
425
426 for (size_t k = 0; k < ARRAY_SIZE(c_t_br_attrs); k++) {
427 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
428 2, "IFLA_INFO_DATA", "bridge",
429 c_t_br_attrs[k].val, c_t_br_attrs[k].name,
430 u64_val, pattern,
431 { 7, sz7_str },
432 { 8, sz8_str },
433 { 9, "\"" BE_LE("\\xde\\xad\\xc0\\xde"
434 "\\xfa\\xce\\xfe\\xed",
435 "\\xed\\xfe\\xce\\xfa"
436 "\\xde\\xc0\\xad\\xde")
437 "\\x61\"" });
438 }
439
440 static const struct val_name u32_br_attrs[] = {
441 { 5, "IFLA_BR_STP_STATE" },
442 { 13, "IFLA_BR_ROOT_PATH_COST" },
443 { 26, "IFLA_BR_MCAST_HASH_ELASTICITY" },
444 { 27, "IFLA_BR_MCAST_HASH_MAX" },
445 { 28, "IFLA_BR_MCAST_LAST_MEMBER_CNT" },
446 { 29, "IFLA_BR_MCAST_STARTUP_QUERY_CNT" },
447 };
448
449 for (size_t k = 0; k < ARRAY_SIZE(u32_br_attrs); k++) {
450 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
451 2, "IFLA_INFO_DATA", "bridge",
452 u32_br_attrs[k].val, u32_br_attrs[k].name,
453 u32_val, pattern,
454 { 3, BE_LE("\"\\xba\\xdc\\x0d\"",
455 "\"\\xed\\x0d\\xdc\"") },
456 { 4, "3134983661" },
457 { 5, "3134983661" });
458 }
459
460 static const struct val_name u16_br_attrs[] = {
461 { 6, "IFLA_BR_PRIORITY" },
462 { 12, "IFLA_BR_ROOT_PORT" },
463 { 39, "IFLA_BR_VLAN_DEFAULT_PVID" },
464 };
465
466 for (size_t k = 0; k < ARRAY_SIZE(u16_br_attrs); k++) {
467 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
468 2, "IFLA_INFO_DATA", "bridge",
469 u16_br_attrs[k].val, u16_br_attrs[k].name,
470 u16_val, pattern,
471 { 1, "\"" BE_LE("\\xde", "\\xed") "\"" },
472 { 2, "57069" },
473 { 3, "57069" });
474 }
475
476 static const struct val_name x16_br_attrs[] = {
477 { 9, "IFLA_BR_GROUP_FWD_MASK" },
478 };
479
480 for (size_t k = 0; k < ARRAY_SIZE(x16_br_attrs); k++) {
481 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
482 2, "IFLA_INFO_DATA", "bridge",
483 x16_br_attrs[k].val, x16_br_attrs[k].name,
484 u16_val, pattern,
485 { 1, "\"" BE_LE("\\xde", "\\xed") "\"" },
486 { 2, "0xdeed" },
487 { 3, "0xdeed" });
488 }
489
490 static const struct val_name u8_br_attrs[] = {
491 { 7, "IFLA_BR_VLAN_FILTERING" },
492 { 14, "IFLA_BR_TOPOLOGY_CHANGE" },
493 { 15, "IFLA_BR_TOPOLOGY_CHANGE_DETECTED" },
494 { 22, "IFLA_BR_MCAST_ROUTER" },
495 { 23, "IFLA_BR_MCAST_SNOOPING" },
496 { 24, "IFLA_BR_MCAST_QUERY_USE_IFADDR" },
497 { 25, "IFLA_BR_MCAST_QUERIER" },
498 { 36, "IFLA_BR_NF_CALL_IPTABLES" },
499 { 37, "IFLA_BR_NF_CALL_IP6TABLES" },
500 { 38, "IFLA_BR_NF_CALL_ARPTABLES" },
501 { 41, "IFLA_BR_VLAN_STATS_ENABLED" },
502 { 42, "IFLA_BR_MCAST_STATS_ENABLED" },
503 { 43, "IFLA_BR_MCAST_IGMP_VERSION" },
504 { 44, "IFLA_BR_MCAST_MLD_VERSION" },
505 { 45, "IFLA_BR_VLAN_STATS_PER_PORT" },
506 };
507
508 for (size_t k = 0; k < ARRAY_SIZE(u8_br_attrs); k++) {
509 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
510 2, "IFLA_INFO_DATA", "bridge",
511 u8_br_attrs[k].val, u8_br_attrs[k].name,
512 u8_val, pattern,
513 { 0, NULL },
514 { 1, "161" },
515 { 2, "161" });
516 }
517
518 unsigned short eth_p = htons(0x88C7);
519 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
520 2, "IFLA_INFO_DATA", "bridge",
521 8, "IFLA_BR_VLAN_PROTOCOL",
522 eth_p, pattern,
523 { 1, "\"\\x88\"" },
524 { 2, "htons(ETH_P_PREAUTH)" },
525 { 2, "htons(ETH_P_PREAUTH)" });
526
527 static const uint8_t bridge_id[]
528 = { 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xc0, 0xde, 0xad };
529 static const struct val_name br_id_attrs[] = {
530 { 10, "IFLA_BR_ROOT_ID" },
531 { 11, "IFLA_BR_BRIDGE_ID" },
532 };
533
534 for (size_t k = 0; k < ARRAY_SIZE(br_id_attrs); k++) {
535 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
536 2, "IFLA_INFO_DATA", "bridge",
537 br_id_attrs[k].val, br_id_attrs[k].name,
538 bridge_id, pattern,
539 { 7, "\"\\xbe\\xef\\xfa\\xce"
540 "\\xde\\xc0\\xde\"" },
541 { 8, "{prio=[190, 239]"
542 ", addr=fa:ce:de:c0:de:ad}" },
543 { 9, "{prio=[190, 239]"
544 ", addr=fa:ce:de:c0:de:ad}" });
545 }
546
547 static const struct {
548 struct br_boolopt_multi val;
549 const char *crop_str;
550 const char *str;
551 } boolopts[] = {
552 { { .optval = 0, .optmask = 0 },
553 "\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"",
554 "{optval=0, optmask=0}" },
555 { { .optval = 1, .optmask = 2 },
556 BE_LE("\"\\x00\\x00\\x00\\x01\\x00\\x00\\x00\"",
557 "\"\\x01\\x00\\x00\\x00\\x02\\x00\\x00\""),
558 "{optval=1<<BR_BOOLOPT_NO_LL_LEARN"
559 ", optmask=1<<BR_BOOLOPT_MCAST_VLAN_SNOOPING}" },
560 { { .optval = 0xdeadfae8, .optmask = 0xbadc0de8 },
561 BE_LE("\"\\xde\\xad\\xfa\\xe8\\xba\\xdc\\x0d\"",
562 "\"\\xe8\\xfa\\xad\\xde\\xe8\\x0d\\xdc\""),
563 "{optval=0xdeadfae8 /* 1<<BR_BOOLOPT_??? */"
564 ", optmask=0xbadc0de8 /* 1<<BR_BOOLOPT_??? */}" },
565 { { .optval = 0xfacebeef, .optmask = 0xfeedcafe },
566 BE_LE("\"\\xfa\\xce\\xbe\\xef\\xfe\\xed\\xca\"",
567 "\"\\xef\\xbe\\xce\\xfa\\xfe\\xca\\xed\""),
568 "{optval=1<<BR_BOOLOPT_NO_LL_LEARN"
569 "|1<<BR_BOOLOPT_MCAST_VLAN_SNOOPING"
570 "|1<<BR_BOOLOPT_MST_ENABLE|0xfacebee8"
571 ", optmask=1<<BR_BOOLOPT_MCAST_VLAN_SNOOPING"
572 "|1<<BR_BOOLOPT_MST_ENABLE|0xfeedcaf8}" },
573 };
574 for (size_t k = 0; k < ARRAY_SIZE(boolopts); k++) {
575 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
576 2, "IFLA_INFO_DATA", "bridge",
577 IFLA_BR_MULTI_BOOLOPT,
578 "IFLA_BR_MULTI_BOOLOPT",
579 boolopts[k].val, pattern,
580 { 7, boolopts[k].crop_str },
581 { 9, boolopts[k].str },
582 { 9, boolopts[k].str });
583 }
584
585 #define QSTATE_NLA(type_, type_str_, field_, crop_str_, str_, ...) \
586 { { .nla = { .nla_len = NLA_HDRLEN \
587 + sizeof(qstate_attrs[0].val.payload.field_), \
588 .nla_type = type_ }, \
589 .payload = { .field_ = __VA_ARGS__ } }, \
590 .sz = NLA_HDRLEN + sizeof(qstate_attrs[0].val.payload.field_), \
591 .type_str = type_str_, .crop_str = crop_str_, .str = str_ }
592
593 char ip_timer_crop[64];
594 char ip_timer[64];
595 char ipv6_timer_crop[64];
596 char ipv6_timer[64];
597 struct {
598 struct {
599 struct nlattr nla;
600 union {
601 uint8_t chr;
602 uint8_t ipv4[4];
603 uint8_t ipv6[16];
604 uint32_t ifindex;
605 uint32_t clk;
606 } payload;
607 } val;
608 size_t sz;
609 const char *type_str;
610 const char *crop_str;
611 const char *str;
612 } qstate_attrs[] = {
613 QSTATE_NLA(BRIDGE_QUERIER_UNSPEC, "BRIDGE_QUERIER_UNSPEC", ipv4,
614 "\"\\xde\\xad\\xfa\"",
615 "\"\\xde\\xad\\xfa\\xce\"",
616 { 0xde, 0xad, 0xfa, 0xce } ),
617 QSTATE_NLA(BRIDGE_QUERIER_IP_ADDRESS,
618 "BRIDGE_QUERIER_IP_ADDRESS", ipv4,
619 "\"\\x5d\\xb8\\xd8\"",
620 "inet_addr(\"93.184.216.34\")",
621 { 0x5d, 0xb8, 0xd8, 0x22 } ),
622 QSTATE_NLA(BRIDGE_QUERIER_IP_PORT,
623 "BRIDGE_QUERIER_IP_PORT", ifindex,
624 xasprintf("\"\\x%02x\\x%02x\\x%02x\"",
625 (ifindex_lo() >> BE_LE(24, 0)) & 0xff,
626 (ifindex_lo() >> BE_LE(16, 8)) & 0xff,
627 (ifindex_lo() >> BE_LE(8, 16)) & 0xff),
628 IFINDEX_LO_STR,
629 ifindex_lo() ),
630 QSTATE_NLA(BRIDGE_QUERIER_IP_OTHER_TIMER,
631 "BRIDGE_QUERIER_IP_OTHER_TIMER", clk,
632 clock_t_str(BE_LE(0xcafefe, 0xfefeed),
633 ARRSZ_PAIR(ip_timer_crop)),
634 clock_t_str(0xcafefeed, ARRSZ_PAIR(ip_timer)),
635 0xcafefeed ),
636 QSTATE_NLA(BRIDGE_QUERIER_PAD, "BRIDGE_QUERIER_PAD", ipv4,
637 "\"\\xfa\\xce\\xfe\"",
638 "\"\\xfa\\xce\\xfe\\xed\"",
639 { 0xfa, 0xce, 0xfe, 0xed } ),
640 QSTATE_NLA(BRIDGE_QUERIER_IPV6_ADDRESS,
641 "BRIDGE_QUERIER_IPV6_ADDRESS", ipv6,
642 "\"\\xde\\xad\\xfa\\xce\\x80\\x00\\x00\\x00"
643 "\\x00\\x00\\x00\\xad\\x00\\x00\\x00\"",
644 "inet_pton(AF_INET6, \"dead:face:8000::ad:0:ec\")",
645 { 0xde, 0xad, 0xfa, 0xce, 0x80, 0x00, 0x00, 0x00,
646 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xec } ),
647 QSTATE_NLA(BRIDGE_QUERIER_IPV6_PORT,
648 "BRIDGE_QUERIER_IPV6_PORT", ifindex,
649 BE_LE("\"\\xbb\\x40\\xe6\"", "\"\\x4d\\xe6\\x40\""),
650 "3141592653",
651 3141592653 ),
652 QSTATE_NLA(BRIDGE_QUERIER_IPV6_OTHER_TIMER,
653 "BRIDGE_QUERIER_IPV6_OTHER_TIMER", clk,
654 clock_t_str(BE_LE(0xfacebe, 0xcebeef),
655 ARRSZ_PAIR(ipv6_timer_crop)),
656 clock_t_str(0xfacebeef, ARRSZ_PAIR(ipv6_timer)),
657 0xfacebeef ),
658 QSTATE_NLA(8, "0x8 /* BRIDGE_QUERIER_??? */", chr,
659 "", "\"\\x69\"", 0x69 ),
660 };
661 for (size_t k = 0; k < ARRAY_SIZE(qstate_attrs); k++) {
662 char crop_str[256];
663 char str[256];
664
665 snprintf(crop_str, sizeof(crop_str),
666 "%s{nla_len=%zu, nla_type=%s}%s%s%s",
667 qstate_attrs[k].crop_str[0] ? "[" : "",
668 qstate_attrs[k].sz, qstate_attrs[k].type_str,
669 qstate_attrs[k].crop_str[0] ? ", " : "",
670 qstate_attrs[k].crop_str,
671 qstate_attrs[k].crop_str[0] ? "]" : "");
672 snprintf(str, sizeof(str), "[{nla_len=%zu, nla_type=%s}, %s]",
673 qstate_attrs[k].sz, qstate_attrs[k].type_str,
674 qstate_attrs[k].str);
675 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
676 2, "IFLA_INFO_DATA", "bridge",
677 IFLA_BR_MCAST_QUERIER_STATE,
678 "IFLA_BR_MCAST_QUERIER_STATE",
679 qstate_attrs[k].val, pattern,
680 { qstate_attrs[k].sz - 1, crop_str },
681 { qstate_attrs[k].sz, str });
682 }
683
684 /* tun attrs */
685 static const struct val_name u8_tun_attrs[] = {
686 { 4, "IFLA_TUN_PI" },
687 { 5, "IFLA_TUN_VNET_HDR" },
688 { 6, "IFLA_TUN_PERSIST" },
689 { 7, "IFLA_TUN_MULTI_QUEUE" },
690 };
691
692 for (size_t k = 0; k < ARRAY_SIZE(u8_tun_attrs); k++) {
693 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
694 2, "IFLA_INFO_DATA", "tun",
695 u8_tun_attrs[k].val, u8_tun_attrs[k].name,
696 u8_val, pattern,
697 { 0, NULL },
698 { 1, "161" },
699 { 2, "161" });
700 }
701
702 static const struct val_name u32_tun_attrs[] = {
703 { 8, "IFLA_TUN_NUM_QUEUES" },
704 { 9, "IFLA_TUN_NUM_DISABLED_QUEUES" },
705 };
706
707 for (size_t k = 0; k < ARRAY_SIZE(u32_tun_attrs); k++) {
708 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
709 2, "IFLA_INFO_DATA", "tun",
710 u32_tun_attrs[k].val,
711 u32_tun_attrs[k].name,
712 u32_val, pattern,
713 { 3, BE_LE("\"\\xba\\xdc\\x0d\"",
714 "\"\\xed\\x0d\\xdc\"") },
715 { 4, "3134983661" },
716 { 5, "3134983661" });
717 }
718
719 static const struct val_name und_tun_attrs[] = {
720 { 0, "IFLA_TUN_UNSPEC" },
721 { 10, "0xa /* IFLA_TUN_??? */" },
722 };
723
724 for (size_t k = 0; k < ARRAY_SIZE(und_tun_attrs); k++) {
725 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
726 2, "IFLA_INFO_DATA", "tun",
727 und_tun_attrs[k].val,
728 und_tun_attrs[k].name,
729 unknown_msg, pattern,
730 { 2, "\"\\xab\\xac\"" },
731 { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
732 { 6,
733 "\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
734 { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
735 "\\x63\\x64\"" },
736 { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
737 "\\x63\\x64\\x65\\x66\"" });
738 }
739
740 static const uint32_t minus_one = 0xffffffffU;
741 static const struct val_name uid_tun_attrs[] = {
742 { 1, "IFLA_TUN_OWNER" },
743 { 2, "IFLA_TUN_GROUP" },
744 };
745
746 for (size_t k = 0; k < ARRAY_SIZE(uid_tun_attrs); k++) {
747 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
748 2, "IFLA_INFO_DATA", "tun",
749 uid_tun_attrs[k].val,
750 uid_tun_attrs[k].name,
751 u32_val, pattern,
752 { 3, BE_LE("\"\\xba\\xdc\\x0d\"",
753 "\"\\xed\\x0d\\xdc\"") },
754 { 4, "3134983661" },
755 { 5, "3134983661" });
756
757 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
758 2, "IFLA_INFO_DATA", "tun",
759 uid_tun_attrs[k].val,
760 uid_tun_attrs[k].name,
761 minus_one, pattern,
762 { 3, "\"\\xff\\xff\\xff\"" },
763 { 4, "-1" },
764 { 5, "-1" });
765 }
766
767 static const struct {
768 uint8_t val;
769 const char *str;
770 } tun_types[] = {
771 { 0, "0 /* IFF_??? */"},
772 { 1, "IFF_TUN"},
773 { 2, "IFF_TAP"},
774 { 3, "0x3 /* IFF_??? */"},
775 { 0xda, "0xda /* IFF_??? */"},
776 };
777
778 for (size_t k = 0; k < ARRAY_SIZE(tun_types); k++) {
779 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_KIND,
780 2, "IFLA_INFO_DATA", "tun",
781 3, "IFLA_TUN_TYPE",
782 tun_types[k].val, pattern,
783 { 0, NULL },
784 { 1, tun_types[k].str },
785 { 2, tun_types[k].str });
786 }
787
788
789 /* IFLA_INFO_KIND + IFLA_INFO_XSTATS */
790 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
791 IFLA_INFO_XSTATS, "IFLA_INFO_XSTATS",
792 unknown_msg, sizeof(unknown_msg),
793 {unsupported_tunnel_types COMMA
794 /*
795 * can decoder decodes its data only if it's big
796 * enough.
797 */
798 unsupported_xstats_types COMMA
799 unsupported_data_types COMMA
800 NULL},
801 printf("\"\\xab\\xac\\xdb\\xcd\""));
802
803 uint32_t can_stats_data[] = {
804 0xbadc0de0, 0xbadc0de1, 0xbadc0de2, 0xbadc0de3,
805 0xbadc0de4, 0xbadc0de5,
806 };
807
808 TEST_LINKINFO(fd, nlh0, IFLA_INFO_KIND, IFLA_INFO_XSTATS, "can",
809 can_stats_data, pattern, print_quoted_hex,
810 printf("{bus_error=3134983648"
811 ", error_warning=3134983649"
812 ", error_passive=3134983650"
813 ", bus_off=3134983651"
814 ", arbitration_lost=3134983652"
815 ", restarts=3134983653}"));
816
817
818 /* IFLA_INFO_KIND + IFLA_INFO_SLAVE_KIND */
819 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
820 IFLA_INFO_SLAVE_KIND, "IFLA_INFO_SLAVE_KIND",
821 unknown_msg, sizeof(unknown_msg),
822 {unsupported_tunnel_types COMMA
823 supported_tunnel_types COMMA
824 NULL},
825 printf("\"\\253\\254\\333\\315\"..."));
826
827
828 /* IFLA_INFO_KIND + IFLA_INFO_SLAVE_DATA */
829 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
830 IFLA_INFO_SLAVE_DATA, "IFLA_INFO_SLAVE_DATA",
831 unknown_msg, sizeof(unknown_msg),
832 {unsupported_tunnel_types COMMA
833 supported_tunnel_types COMMA
834 NULL},
835 printf("\"\\xab\\xac\\xdb\\xcd\""));
836
837
838 /* IFLA_INFO_KIND + unknown type */
839 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND,
840 6, "0x6 /* IFLA_INFO_??? */",
841 unknown_msg, sizeof(unknown_msg),
842 {unsupported_tunnel_types COMMA
843 supported_tunnel_types COMMA
844 NULL},
845 printf("\"\\xab\\xac\\xdb\\xcd\""));
846
847
848 /* IFLA_INFO_SLAVE_KIND */
849 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
850 init_ifinfomsg, print_ifinfomsg,
851 IFLA_INFO_SLAVE_KIND,
852 "IFLA_INFO_SLAVE_KIND", pattern,
853 unknown_msg, print_quoted_stringn, 1,
854 printf("\"\\253\\254\\333\\315\"..."));
855
856
857 /* IFLA_INFO_SLAVE_KIND + IFLA_INFO_UNSPEC */
858 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_SLAVE_KIND,
859 IFLA_INFO_UNSPEC, "IFLA_INFO_UNSPEC",
860 unknown_msg, sizeof(unknown_msg),
861 {unsupported_tunnel_types COMMA
862 supported_tunnel_types COMMA
863 NULL},
864 printf("\"\\xab\\xac\\xdb\\xcd\""));
865
866
867 /* IFLA_INFO_SLAVE_KIND + IFLA_INFO_KIND */
868 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_SLAVE_KIND,
869 IFLA_INFO_KIND, "IFLA_INFO_KIND",
870 unknown_msg, sizeof(unknown_msg),
871 {unsupported_tunnel_types COMMA
872 supported_tunnel_types COMMA
873 NULL},
874 printf("\"\\253\\254\\333\\315\"..."));
875
876
877 /* IFLA_INFO_SLAVE_KIND + IFLA_INFO_DATA */
878 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_SLAVE_KIND,
879 IFLA_INFO_DATA, "IFLA_INFO_DATA",
880 unknown_msg, sizeof(unknown_msg),
881 {unsupported_tunnel_types COMMA
882 unsupported_data_types COMMA
883 NULL},
884 printf("\"\\xab\\xac\\xdb\\xcd\""));
885
886 /* IFLA_INFO_SLAVE_KIND + IFLA_INFO_SLAVE_DATA */
887 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_SLAVE_KIND,
888 IFLA_INFO_SLAVE_DATA, "IFLA_INFO_SLAVE_DATA",
889 unknown_msg, sizeof(unknown_msg),
890 {unsupported_tunnel_types COMMA
891 unsupported_slave_data_types COMMA
892 NULL},
893 printf("\"\\xab\\xac\\xdb\\xcd\""));
894
895 /* bridge attrs */
896 static const struct val_name und_brport_attrs[] = {
897 { 0, "IFLA_BRPORT_UNSPEC" },
898 { 24, "IFLA_BRPORT_FLUSH" },
899 { 26, "IFLA_BRPORT_PAD" },
900 { 44, "0x2c /* IFLA_BRPORT_??? */" },
901 { 2989, "0xbad /* IFLA_BRPORT_??? */" },
902 };
903
904 for (size_t k = 0; k < ARRAY_SIZE(und_brport_attrs); k++) {
905 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
906 5, "IFLA_INFO_SLAVE_DATA", "bridge",
907 und_brport_attrs[k].val,
908 und_brport_attrs[k].name,
909 unknown_msg, pattern,
910 { 2, "\"\\xab\\xac\"" },
911 { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
912 { 6,
913 "\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
914 { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
915 "\\x63\\x64\"" },
916 { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
917 "\\x63\\x64\\x65\\x66\"" });
918 }
919
920 static const struct val_name u8_brport_attrs[] = {
921 { ARG_STR(IFLA_BRPORT_STATE) },
922 { ARG_STR(IFLA_BRPORT_MODE) },
923 { ARG_STR(IFLA_BRPORT_GUARD) },
924 { ARG_STR(IFLA_BRPORT_PROTECT) },
925 { ARG_STR(IFLA_BRPORT_FAST_LEAVE) },
926 { ARG_STR(IFLA_BRPORT_LEARNING) },
927 { ARG_STR(IFLA_BRPORT_UNICAST_FLOOD) },
928 { ARG_STR(IFLA_BRPORT_PROXYARP) },
929 { ARG_STR(IFLA_BRPORT_LEARNING_SYNC) },
930 { ARG_STR(IFLA_BRPORT_PROXYARP_WIFI) },
931 { ARG_STR(IFLA_BRPORT_TOPOLOGY_CHANGE_ACK) },
932 { ARG_STR(IFLA_BRPORT_CONFIG_PENDING) },
933 { ARG_STR(IFLA_BRPORT_MULTICAST_ROUTER) },
934 { ARG_STR(IFLA_BRPORT_MCAST_FLOOD) },
935 { ARG_STR(IFLA_BRPORT_MCAST_TO_UCAST) },
936 { ARG_STR(IFLA_BRPORT_VLAN_TUNNEL) },
937 { ARG_STR(IFLA_BRPORT_BCAST_FLOOD) },
938 { ARG_STR(IFLA_BRPORT_NEIGH_SUPPRESS) },
939 { ARG_STR(IFLA_BRPORT_ISOLATED) },
940 { ARG_STR(IFLA_BRPORT_MRP_RING_OPEN) },
941 { ARG_STR(IFLA_BRPORT_MRP_IN_OPEN) },
942 { ARG_STR(IFLA_BRPORT_LOCKED) },
943 { ARG_STR(IFLA_BRPORT_MAB) },
944 { ARG_STR(IFLA_BRPORT_NEIGH_VLAN_SUPPRESS) },
945 };
946
947 for (size_t k = 0; k < ARRAY_SIZE(u8_brport_attrs); k++) {
948 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
949 5, "IFLA_INFO_SLAVE_DATA", "bridge",
950 u8_brport_attrs[k].val,
951 u8_brport_attrs[k].name,
952 u8_val, pattern,
953 { 0, NULL },
954 { 1, "161" },
955 { 2, "161" });
956 }
957
958 static const struct val_name u16_brport_attrs[] = {
959 { ARG_STR(IFLA_BRPORT_PRIORITY) },
960 { ARG_STR(IFLA_BRPORT_DESIGNATED_PORT) },
961 { ARG_STR(IFLA_BRPORT_DESIGNATED_COST) },
962 { ARG_STR(IFLA_BRPORT_ID) },
963 { ARG_STR(IFLA_BRPORT_NO) },
964 };
965
966 for (size_t k = 0; k < ARRAY_SIZE(u16_brport_attrs); k++) {
967 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
968 5, "IFLA_INFO_SLAVE_DATA", "bridge",
969 u16_brport_attrs[k].val,
970 u16_brport_attrs[k].name,
971 u16_val, pattern,
972 { 1, "\"" BE_LE("\\xde", "\\xed") "\"" },
973 { 2, "57069" },
974 { 3, "57069" });
975 }
976
977 static const struct val_name x16_brport_attrs[] = {
978 { ARG_STR(IFLA_BRPORT_GROUP_FWD_MASK) },
979 };
980
981 for (size_t k = 0; k < ARRAY_SIZE(x16_brport_attrs); k++) {
982 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
983 5, "IFLA_INFO_SLAVE_DATA", "bridge",
984 x16_brport_attrs[k].val,
985 x16_brport_attrs[k].name,
986 u16_val, pattern,
987 { 1, "\"" BE_LE("\\xde", "\\xed") "\"" },
988 { 2, "0xdeed" },
989 { 3, "0xdeed" });
990 }
991
992 static const struct val_name u32_brport_attrs[] = {
993 { 3, "IFLA_BRPORT_COST" },
994 { 37, "IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT" },
995 { 38, "IFLA_BRPORT_MCAST_EHT_HOSTS_CNT" },
996 { ARG_STR(IFLA_BRPORT_MCAST_N_GROUPS) },
997 { ARG_STR(IFLA_BRPORT_MCAST_MAX_GROUPS) },
998 };
999
1000 for (size_t k = 0; k < ARRAY_SIZE(u32_brport_attrs); k++) {
1001 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
1002 5, "IFLA_INFO_SLAVE_DATA", "bridge",
1003 u32_brport_attrs[k].val,
1004 u32_brport_attrs[k].name,
1005 u32_val, pattern,
1006 { 3, BE_LE("\"\\xba\\xdc\\x0d\"",
1007 "\"\\xed\\x0d\\xdc\"") },
1008 { 4, "3134983661" },
1009 { 5, "3134983661" });
1010 }
1011
1012 static const struct val_name brport_id_attrs[] = {
1013 { 13, "IFLA_BRPORT_ROOT_ID" },
1014 { 14, "IFLA_BRPORT_BRIDGE_ID" },
1015 };
1016
1017 for (size_t k = 0; k < ARRAY_SIZE(brport_id_attrs); k++) {
1018 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
1019 5, "IFLA_INFO_SLAVE_DATA", "bridge",
1020 brport_id_attrs[k].val,
1021 brport_id_attrs[k].name,
1022 bridge_id, pattern,
1023 { 7, "\"\\xbe\\xef\\xfa\\xce"
1024 "\\xde\\xc0\\xde\"" },
1025 { 8, "{prio=[190, 239]"
1026 ", addr=fa:ce:de:c0:de:ad}" },
1027 { 9, "{prio=[190, 239]"
1028 ", addr=fa:ce:de:c0:de:ad}" });
1029 }
1030
1031 static const struct val_name c_t_brport_attrs[] = {
1032 { 21, "IFLA_BRPORT_MESSAGE_AGE_TIMER" },
1033 { 22, "IFLA_BRPORT_FORWARD_DELAY_TIMER" },
1034 { 23, "IFLA_BRPORT_HOLD_TIMER" },
1035 };
1036
1037 for (size_t k = 0; k < ARRAY_SIZE(c_t_brport_attrs); k++) {
1038 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
1039 5, "IFLA_INFO_SLAVE_DATA", "bridge",
1040 c_t_brport_attrs[k].val,
1041 c_t_brport_attrs[k].name,
1042 u64_val, pattern,
1043 { 7, sz7_str },
1044 { 8, sz8_str },
1045 { 9, "\"" BE_LE("\\xde\\xad\\xc0\\xde"
1046 "\\xfa\\xce\\xfe\\xed",
1047 "\\xed\\xfe\\xce\\xfa"
1048 "\\xde\\xc0\\xad\\xde")
1049 "\\x61\"" });
1050 }
1051
1052 static const struct val_name ifidx_brport_attrs[] = {
1053 { 34, "IFLA_BRPORT_BACKUP_PORT" },
1054 };
1055 const uint32_t ifidx_lo = ifindex_lo();
1056
1057 for (size_t k = 0; k < ARRAY_SIZE(ifidx_brport_attrs); k++) {
1058 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
1059 5, "IFLA_INFO_SLAVE_DATA", "bridge",
1060 ifidx_brport_attrs[k].val,
1061 ifidx_brport_attrs[k].name,
1062 u32_val, pattern,
1063 { 3, BE_LE("\"\\xba\\xdc\\x0d\"",
1064 "\"\\xed\\x0d\\xdc\"") },
1065 { 4, "3134983661" },
1066 { 5, "3134983661" });
1067
1068 TEST_NESTED_LINKINFO(fd, nlh0, IFLA_INFO_SLAVE_KIND,
1069 5, "IFLA_INFO_SLAVE_DATA", "bridge",
1070 ifidx_brport_attrs[k].val,
1071 ifidx_brport_attrs[k].name,
1072 ifidx_lo, pattern,
1073 { 3, BE_LE("\"\\x00\\x00\\x00\"",
1074 "\"\\x01\\x00\\x00\"") },
1075 { 4, IFINDEX_LO_STR },
1076 { 5, IFINDEX_LO_STR });
1077 }
1078
1079 /* IFLA_INFO_SLAVE_KIND + unknown type */
1080 TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_SLAVE_KIND,
1081 6, "0x6 /* IFLA_INFO_??? */",
1082 unknown_msg, sizeof(unknown_msg),
1083 {unsupported_tunnel_types COMMA
1084 supported_tunnel_types COMMA
1085 NULL},
1086 printf("\"\\xab\\xac\\xdb\\xcd\""));
1087
1088
1089 puts("+++ exited with 0 +++");
1090 return 0;
1091 }