(root)/
strace-6.5/
tests/
nlattr_ifla_linkinfo.c
       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  }