int
main(void)
{
	skip_if_unavailable("/proc/self/fd/");

	const int fd = create_nl_socket(NETLINK_ROUTE);
	const unsigned int hdrlen = sizeof(struct ndmsg);
	void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen),
				   NLA_HDRLEN + sizeof(struct nda_cacheinfo));

	static char pattern[4096];
	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);

	const unsigned int nla_type = 0xffff & NLA_TYPE_MASK;
	char nla_type_str[256];
	sprintf(nla_type_str, "%#x /* NDA_??? */", nla_type);
	TEST_NLATTR_(fd, nlh0, hdrlen,
		     init_ndmsg, print_ndmsg,
		     nla_type, nla_type_str,
		     4, pattern, 4,
		     print_quoted_hex(pattern, 4));

	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ndmsg, print_ndmsg,
		    NDA_DST, 4, pattern, 4,
		    print_quoted_hex(pattern, 4));

	static const struct nda_cacheinfo ci = {
		.ndm_confirmed = 0xabcdedad,
		.ndm_used = 0xbcdaedad,
		.ndm_updated = 0xcdbadeda,
		.ndm_refcnt = 0xdeadbeda
	};

	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
			   init_ndmsg, print_ndmsg,
			   NDA_CACHEINFO, pattern, ci,
			   PRINT_FIELD_U("{", ci, ndm_confirmed);
			   PRINT_FIELD_U(", ", ci, ndm_used);
			   PRINT_FIELD_U(", ", ci, ndm_updated);
			   PRINT_FIELD_U(", ", ci, ndm_refcnt);
			   printf("}"));

	const uint16_t port = 0xabcd;
	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
			   init_ndmsg, print_ndmsg,
			   NDA_PORT, pattern, port,
			   printf("htons(%u)", ntohs(port)));

	puts("+++ exited with 0 +++");
	return 0;
}
static void
test_inet_diag_bc_dev_cond(const int fd)
{
	static const struct inet_diag_bc_op op = {
		.code = INET_DIAG_BC_DEV_COND,
	};
	const uint32_t ifindex = ifindex_lo();
	char buf[sizeof(op) + sizeof(ifindex)];
	memcpy(buf, &op, sizeof(op));
	memcpy(buf + sizeof(op), pattern, sizeof(ifindex));

	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf) - 1, buf, sizeof(buf) - 1,
		    print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
		    print_quoted_hex(pattern, sizeof(ifindex) - 1);
		    printf("}"));

	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf), buf, sizeof(buf) - 1,
		    print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
		    printf("%p}", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));

	memcpy(buf + sizeof(op), &ifindex, sizeof(ifindex));
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf), buf, sizeof(buf),
		    print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
		    printf(IFINDEX_LO_STR "}"));
}
Esempio n. 3
0
int
main(void)
{
	skip_if_unavailable("/proc/self/fd/");

	const int fd = create_nl_socket(NETLINK_ROUTE);

	const unsigned int hdrlen = sizeof(struct netconfmsg);
	void *nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));

	static char pattern[4096];
	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);

	const unsigned int nla_type = 0xffff & NLA_TYPE_MASK;
	char nla_type_str[256];
	sprintf(nla_type_str, "%#x /* NETCONFA_??? */", nla_type);
	TEST_NLATTR_(fd, nlh0, hdrlen,
		     init_netconfmsg, print_netconfmsg,
		     nla_type, nla_type_str,
		     4, pattern, 4,
		     print_quoted_hex(pattern, 4));

	puts("+++ exited with 0 +++");
	return 0;
}
static void
print_packet_diag_mclist(const struct packet_diag_mclist *const dml, size_t i)
{
	printf("{pdmc_index=" IFINDEX_LO_STR);
	PRINT_FIELD_U(", ", *dml, pdmc_count);
	PRINT_FIELD_U(", ", *dml, pdmc_type);
	PRINT_FIELD_U(", ", *dml, pdmc_alen);
	printf(", pdmc_addr=");
	print_quoted_hex(dml->pdmc_addr, dml->pdmc_alen);
	printf("}");
}
static void
test_in6_addr(const int fd)
{
	const char address6[] = "12:34:56:78:90:ab:cd:ef";
	static const struct inet_diag_bc_op op = {
		.code = INET_DIAG_BC_S_COND,
	};
	static const struct inet_diag_hostcond cond = {
		.family = AF_INET6,
	};
	struct in6_addr addr;
	if (!inet_pton(AF_INET6, address6, &addr))
		perror_msg_and_skip("inet_pton");

	char buf[sizeof(op) + sizeof(cond) + sizeof(addr)];
	memcpy(buf, &op, sizeof(op));
	memcpy(buf + sizeof(op), &cond, sizeof(cond));

	const unsigned int plen = sizeof(addr) - 1 > DEFAULT_STRLEN ?
		sizeof(cond) + sizeof(cond) + DEFAULT_STRLEN : sizeof(buf) - 1;
	memcpy(buf + sizeof(op) + sizeof(cond), &pattern, sizeof(addr));
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    plen, buf, plen,
		    print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
		    print_inet_diag_hostcond("AF_INET6");
		    printf("addr=");
		    print_quoted_hex(pattern, plen - sizeof(op) - sizeof(cond));
		    printf("}}"));

	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf), buf, sizeof(buf) - 1,
		    print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
		    print_inet_diag_hostcond("AF_INET6");
		    printf("addr=%p}}",
			   RTA_DATA(TEST_NLATTR_nla)
			   + sizeof(op) + sizeof(cond)));

	memcpy(buf + sizeof(op) + sizeof(cond), &addr, sizeof(addr));
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf), buf, sizeof(buf),
		    print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
		    print_inet_diag_hostcond("AF_INET6");
		    printf("inet_pton(AF_INET6, \"%s\", &addr)}}", address6));
}
static void
test_inet_diag_bc_s_cond(const int fd)
{
	static const struct inet_diag_bc_op op = {
		.code = INET_DIAG_BC_S_COND,
	};
	static const struct inet_diag_hostcond cond = {
		.family = AF_UNSPEC,
		.prefix_len = 0xad,
		.port = 0xadfa
	};
	char buf[sizeof(op) + sizeof(cond)];
	memcpy(buf, &op, sizeof(op));

	const unsigned int plen = sizeof(cond) - 1 > DEFAULT_STRLEN ?
		sizeof(op) + DEFAULT_STRLEN : sizeof(buf) - 1;
	memcpy(buf + sizeof(op), &pattern, sizeof(cond));
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    plen, buf, plen,
		    print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
		    print_quoted_hex(buf + sizeof(op), plen - sizeof(op));
		    printf("}"));

	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf), buf, sizeof(buf) - 1,
		    print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
		    printf("%p}", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));

	memcpy(buf + sizeof(op), &cond, sizeof(cond));
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_inet_diag_req_v2, print_inet_diag_req_v2,
		    INET_DIAG_REQ_BYTECODE,
		    sizeof(buf), buf, sizeof(buf),
		    print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
		    printf("{family=AF_UNSPEC");
		    PRINT_FIELD_U(", ", cond, prefix_len);
		    PRINT_FIELD_U(", ", cond, port);
		    printf("}}"));
}

static void
print_inet_diag_hostcond(const char *const family)
{
	printf("{family=%s, prefix_len=0, port=0, ", family);
}
int
main(void)
{
	skip_if_unavailable("/proc/self/fd/");

	static const struct rtnl_link_stats st = {
		.rx_packets = 0xabcdefac,
		.tx_packets = 0xbcdacdab,
		.rx_bytes = 0xcdbafaab,
		.tx_bytes = 0xdafabadb,
		.rx_errors = 0xeabcdaeb,
		.tx_errors = 0xfefabeab,
		.rx_dropped = 0xadbafafb,
		.tx_dropped = 0xbdffabda,
		.multicast = 0xcdabdfea,
		.collisions = 0xefadbaeb,
		.rx_length_errors = 0xfabffabd,
		.rx_over_errors = 0xafbafabc,
		.rx_crc_errors = 0xbfdabdad,
		.rx_frame_errors = 0xcfdabfad,
		.rx_fifo_errors = 0xddfdebad,
		.rx_missed_errors = 0xefabdcba,
		.tx_aborted_errors = 0xefdadbfa,
		.tx_carrier_errors = 0xfaefbada,
		.tx_fifo_errors = 0xaebdffab,
		.tx_heartbeat_errors = 0xbadebaaf,
		.tx_window_errors = 0xcdafbada,
		.rx_compressed = 0xdeffadbd,
		.tx_compressed = 0xefdadfab
	};
	const int fd = create_nl_socket(NETLINK_ROUTE);
	const unsigned int hdrlen = sizeof(struct ifinfomsg);
	void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen),
				   NLA_HDRLEN + sizeof(st));

	static char pattern[4096];
	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);

	const unsigned int nla_type = 0xffff & NLA_TYPE_MASK;
	char nla_type_str[256];
	sprintf(nla_type_str, "%#x /* IFLA_??? */", nla_type);
	TEST_NLATTR_(fd, nlh0, hdrlen,
		     init_ifinfomsg, print_ifinfomsg,
		     nla_type, nla_type_str,
		     4, pattern, 4,
		     print_quoted_hex(pattern, 4));

	const int32_t netnsid = 0xacbdabda;
	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
			   init_ifinfomsg, print_ifinfomsg,
			   IFLA_LINK_NETNSID, pattern, netnsid,
			   printf("%d", netnsid));

	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
			   init_ifinfomsg, print_ifinfomsg,
			   IFLA_STATS, pattern, st,
			   PRINT_FIELD_U("{", st, rx_packets);
			   PRINT_FIELD_U(", ", st, tx_packets);
			   PRINT_FIELD_U(", ", st, rx_bytes);
			   PRINT_FIELD_U(", ", st, tx_bytes);
			   PRINT_FIELD_U(", ", st, rx_errors);
			   PRINT_FIELD_U(", ", st, tx_errors);
			   PRINT_FIELD_U(", ", st, rx_dropped);
			   PRINT_FIELD_U(", ", st, tx_dropped);
			   PRINT_FIELD_U(", ", st, multicast);
			   PRINT_FIELD_U(", ", st, collisions);
			   PRINT_FIELD_U(", ", st, rx_length_errors);
			   PRINT_FIELD_U(", ", st, rx_over_errors);
			   PRINT_FIELD_U(", ", st, rx_crc_errors);
			   PRINT_FIELD_U(", ", st, rx_frame_errors);
			   PRINT_FIELD_U(", ", st, rx_fifo_errors);
			   PRINT_FIELD_U(", ", st, rx_missed_errors);
			   PRINT_FIELD_U(", ", st, tx_aborted_errors);
			   PRINT_FIELD_U(", ", st, tx_carrier_errors);
			   PRINT_FIELD_U(", ", st, tx_fifo_errors);
			   PRINT_FIELD_U(", ", st, tx_heartbeat_errors);
			   PRINT_FIELD_U(", ", st, tx_window_errors);
			   PRINT_FIELD_U(", ", st, rx_compressed);
			   PRINT_FIELD_U(", ", st, tx_compressed);
#ifdef HAVE_STRUCT_RTNL_LINK_STATS_RX_NOHANDLER
			   PRINT_FIELD_U(", ", st, rx_nohandler);
#endif
			   printf("}"));

#ifdef HAVE_STRUCT_RTNL_LINK_STATS_RX_NOHANDLER
	const unsigned int sizeof_stats =
		offsetofend(struct rtnl_link_stats, tx_compressed);
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_STATS, sizeof_stats, &st, sizeof_stats,
		    PRINT_FIELD_U("{", st, rx_packets);
		    PRINT_FIELD_U(", ", st, tx_packets);
		    PRINT_FIELD_U(", ", st, rx_bytes);
		    PRINT_FIELD_U(", ", st, tx_bytes);
		    PRINT_FIELD_U(", ", st, rx_errors);
		    PRINT_FIELD_U(", ", st, tx_errors);
		    PRINT_FIELD_U(", ", st, rx_dropped);
		    PRINT_FIELD_U(", ", st, tx_dropped);
		    PRINT_FIELD_U(", ", st, multicast);
		    PRINT_FIELD_U(", ", st, collisions);
		    PRINT_FIELD_U(", ", st, rx_length_errors);
		    PRINT_FIELD_U(", ", st, rx_over_errors);
		    PRINT_FIELD_U(", ", st, rx_crc_errors);
		    PRINT_FIELD_U(", ", st, rx_frame_errors);
		    PRINT_FIELD_U(", ", st, rx_fifo_errors);
		    PRINT_FIELD_U(", ", st, rx_missed_errors);
		    PRINT_FIELD_U(", ", st, tx_aborted_errors);
		    PRINT_FIELD_U(", ", st, tx_carrier_errors);
		    PRINT_FIELD_U(", ", st, tx_fifo_errors);
		    PRINT_FIELD_U(", ", st, tx_heartbeat_errors);
		    PRINT_FIELD_U(", ", st, tx_window_errors);
		    PRINT_FIELD_U(", ", st, rx_compressed);
		    PRINT_FIELD_U(", ", st, tx_compressed);
		    printf("}"));
#endif /* HAVE_STRUCT_RTNL_LINK_STATS_RX_NOHANDLER */

	static const struct rtnl_link_ifmap map = {
		.mem_start = 0xadcbefedefbcdedb,
		.mem_end = 0xefcbeabdecdcdefa,
		.base_addr = 0xaddbeabdfaacdbae,
		.irq = 0xefaf,
		.dma = 0xab,
		.port = 0xcd
	};
	const unsigned int sizeof_ifmap =
		offsetofend(struct rtnl_link_ifmap, port);
	const unsigned int plen = sizeof_ifmap - 1 > DEFAULT_STRLEN
				  ? DEFAULT_STRLEN
				  : (int) sizeof_ifmap - 1;
	/* len < sizeof_ifmap */
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_MAP, plen, pattern, plen,
		    print_quoted_hex(pattern, plen));

	/* short read of sizeof_ifmap */
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_MAP, sizeof_ifmap, &map, sizeof_ifmap - 1,
		    printf("%p", RTA_DATA(TEST_NLATTR_nla)));

	/* sizeof_ifmap */
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_MAP, sizeof_ifmap, &map, sizeof_ifmap,
		    PRINT_FIELD_X("{", map, mem_start);
		    PRINT_FIELD_X(", ", map, mem_end);
		    PRINT_FIELD_X(", ", map, base_addr);
		    PRINT_FIELD_U(", ", map, irq);
		    PRINT_FIELD_U(", ", map, dma);
		    PRINT_FIELD_U(", ", map, port);
		    printf("}"));

#ifdef HAVE_STRUCT_RTNL_LINK_STATS64
	static const struct rtnl_link_stats64 st64 = {
		.rx_packets = 0xadcbefedefbcdedb,
		.tx_packets = 0xbdabdedabdcdeabd,
		.rx_bytes = 0xcdbaefbaeadfabec,
		.tx_bytes = 0xdbaedbafabbeacdb,
		.rx_errors = 0xefabfdaefabaefab,
		.tx_errors = 0xfaebfabfabbaeabf,
		.rx_dropped = 0xacdbaedbadbabeba,
		.tx_dropped = 0xbcdeffebdabeadbe,
		.multicast = 0xeeffbaeabaeffabe,
		.collisions = 0xffbaefcefbafacef,
		.rx_length_errors = 0xaabbdeabceffdecb,
		.rx_over_errors = 0xbbdcdadebadeaeed,
		.rx_crc_errors= 0xccdeabecefaedbef,
		.rx_frame_errors = 0xddbedaedebcedaef,
		.rx_fifo_errors = 0xeffbadefafdaeaab,
		.rx_missed_errors = 0xfefaebccceadeecd,
		.tx_aborted_errors = 0xabcdadefcdadef,
		.tx_carrier_errors = 0xbccdafaeeaaefe,
		.tx_fifo_errors = 0xcddefdbedeadce,
		.tx_heartbeat_errors = 0xedaededdadcdea,
		.tx_window_errors = 0xfdacdeaccedcda,
		.rx_compressed = 0xacdbbcacdbccef,
		.tx_compressed = 0xbcdadefcdedfea
	};
	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
			   init_ifinfomsg, print_ifinfomsg,
			   IFLA_STATS64, pattern, st64,
			   PRINT_FIELD_U("{", st64, rx_packets);
			   PRINT_FIELD_U(", ", st64, tx_packets);
			   PRINT_FIELD_U(", ", st64, rx_bytes);
			   PRINT_FIELD_U(", ", st64, tx_bytes);
			   PRINT_FIELD_U(", ", st64, rx_errors);
			   PRINT_FIELD_U(", ", st64, tx_errors);
			   PRINT_FIELD_U(", ", st64, rx_dropped);
			   PRINT_FIELD_U(", ", st64, tx_dropped);
			   PRINT_FIELD_U(", ", st64, multicast);
			   PRINT_FIELD_U(", ", st64, collisions);
			   PRINT_FIELD_U(", ", st64, rx_length_errors);
			   PRINT_FIELD_U(", ", st64, rx_over_errors);
			   PRINT_FIELD_U(", ", st64, rx_crc_errors);
			   PRINT_FIELD_U(", ", st64, rx_frame_errors);
			   PRINT_FIELD_U(", ", st64, rx_fifo_errors);
			   PRINT_FIELD_U(", ", st64, rx_missed_errors);
			   PRINT_FIELD_U(", ", st64, tx_aborted_errors);
			   PRINT_FIELD_U(", ", st64, tx_carrier_errors);
			   PRINT_FIELD_U(", ", st64, tx_fifo_errors);
			   PRINT_FIELD_U(", ", st64, tx_heartbeat_errors);
			   PRINT_FIELD_U(", ", st64, tx_window_errors);
			   PRINT_FIELD_U(", ", st64, rx_compressed);
			   PRINT_FIELD_U(", ", st64, tx_compressed);
#ifdef HAVE_STRUCT_RTNL_LINK_STATS64_RX_NOHANDLER
			   PRINT_FIELD_U(", ", st64, rx_nohandler);
#endif
			   printf("}"));

#ifdef HAVE_STRUCT_RTNL_LINK_STATS64_RX_NOHANDLER
	const unsigned int sizeof_stats64 =
		offsetofend(struct rtnl_link_stats64, tx_compressed);
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_STATS64, sizeof_stats64, &st64, sizeof_stats64,
		    PRINT_FIELD_U("{", st64, rx_packets);
		    PRINT_FIELD_U(", ", st64, tx_packets);
		    PRINT_FIELD_U(", ", st64, rx_bytes);
		    PRINT_FIELD_U(", ", st64, tx_bytes);
		    PRINT_FIELD_U(", ", st64, rx_errors);
		    PRINT_FIELD_U(", ", st64, tx_errors);
		    PRINT_FIELD_U(", ", st64, rx_dropped);
		    PRINT_FIELD_U(", ", st64, tx_dropped);
		    PRINT_FIELD_U(", ", st64, multicast);
		    PRINT_FIELD_U(", ", st64, collisions);
		    PRINT_FIELD_U(", ", st64, rx_length_errors);
		    PRINT_FIELD_U(", ", st64, rx_over_errors);
		    PRINT_FIELD_U(", ", st64, rx_crc_errors);
		    PRINT_FIELD_U(", ", st64, rx_frame_errors);
		    PRINT_FIELD_U(", ", st64, rx_fifo_errors);
		    PRINT_FIELD_U(", ", st64, rx_missed_errors);
		    PRINT_FIELD_U(", ", st64, tx_aborted_errors);
		    PRINT_FIELD_U(", ", st64, tx_carrier_errors);
		    PRINT_FIELD_U(", ", st64, tx_fifo_errors);
		    PRINT_FIELD_U(", ", st64, tx_heartbeat_errors);
		    PRINT_FIELD_U(", ", st64, tx_window_errors);
		    PRINT_FIELD_U(", ", st64, rx_compressed);
		    PRINT_FIELD_U(", ", st64, tx_compressed);
		    printf("}"));
#endif /* HAVE_STRUCT_RTNL_LINK_STATS64_RX_NOHANDLER */
#endif /* HAVE_STRUCT_RTNL_LINK_STATS64 */

	struct nlattr nla = {
		.nla_len = sizeof(nla),
		.nla_type = IFLA_INFO_KIND,
	};
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_LINKINFO, sizeof(nla), &nla, sizeof(nla),
		    printf("{nla_len=%u, nla_type=IFLA_INFO_KIND}",
			   nla.nla_len));

	nla.nla_type = IFLA_VF_PORT;
	TEST_NLATTR(fd, nlh0, hdrlen,
		    init_ifinfomsg, print_ifinfomsg,
		    IFLA_VF_PORTS, sizeof(nla), &nla, sizeof(nla),
		    printf("{nla_len=%u, nla_type=IFLA_VF_PORT}",
			   nla.nla_len));

	static const struct {
		uint32_t val;
		const char *str;
	} ifla_events[] = {
		{ 0, "IFLA_EVENT_NONE" },
		{ 6, "IFLA_EVENT_BONDING_OPTIONS" },
		{ ARG_STR(0x7) " /* IFLA_EVENT_??? */" },
		{ ARG_STR(0xdeadfeed) " /* IFLA_EVENT_??? */" },
	};
	for (size_t i = 0; i < ARRAY_SIZE(ifla_events); i++) {
		TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
				   init_ifinfomsg, print_ifinfomsg,
				   IFLA_EVENT, pattern, ifla_events[i].val,
				   printf("%s", ifla_events[i].str));
	}

	puts("+++ exited with 0 +++");
	return 0;
}
int
main(void)
{
	skip_if_unavailable("/proc/self/fd/");

	const int fd = create_nl_socket(NETLINK_ROUTE);

	void *nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));

	static char pattern[4096];
	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);

	const unsigned int nla_type = 0xffff & NLA_TYPE_MASK;
	char nla_type_str[256];
	sprintf(nla_type_str, "%#x /* MDBA_MDB_ENTRY_??? */", nla_type);
	TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN * 2, hdrlen + NLA_HDRLEN * 2,
		     init_br_port_msg, print_br_port_msg,
		     nla_type, nla_type_str,
		     4, pattern, 4,
		     print_quoted_hex(pattern, 4);
		     printf("}}"));

# ifdef HAVE_STRUCT_BR_MDB_ENTRY
	struct br_mdb_entry entry = {
		.ifindex = ifindex_lo(),
		.state = MDB_TEMPORARY,
#  ifdef HAVE_STRUCT_BR_MDB_ENTRY_FLAGS
		.flags = MDB_FLAGS_OFFLOAD,
#  endif
#  ifdef HAVE_STRUCT_BR_MDB_ENTRY_VID
		.vid = 0xcdef,
#  endif
		.addr = {
			.proto = htons(AF_UNSPEC)
		}
	};

	memcpy(&entry.addr.u, pattern, sizeof(entry.addr.u));
	TEST_NESTED_NLATTR_OBJECT_EX(fd, nlh0, hdrlen,
				     init_br_port_msg, print_br_port_msg,
				     MDBA_MDB_ENTRY_INFO, pattern, entry, 2,
				     printf("{ifindex=" IFINDEX_LO_STR);
				     printf(", state=MDB_TEMPORARY");
#  ifdef HAVE_STRUCT_BR_MDB_ENTRY_FLAGS
				     printf(", flags=MDB_FLAGS_OFFLOAD");
#  endif
#  ifdef HAVE_STRUCT_BR_MDB_ENTRY_VID
				     PRINT_FIELD_U(", ", entry, vid);
#  endif
				     printf(", addr={u=");
				     print_quoted_hex(&entry.addr.u,
						      sizeof(entry.addr.u));
				     printf(", proto=htons(AF_UNSPEC)}}"));

	static const struct nlattr nla = {
		.nla_len = sizeof(nla),
		.nla_type = MDBA_MDB_EATTR_TIMER
	};
	char buf[NLMSG_ALIGN(sizeof(entry)) + sizeof(nla)];
	memcpy(buf, &entry, sizeof(entry));
	memcpy(buf + NLMSG_ALIGN(sizeof(entry)), &nla, sizeof(nla));
	TEST_NLATTR(fd, nlh0 - NLA_HDRLEN * 2, hdrlen + NLA_HDRLEN * 2,
		    init_br_port_msg, print_br_port_msg,
		    MDBA_MDB_ENTRY_INFO, sizeof(buf), buf, sizeof(buf),
		    printf("{ifindex=" IFINDEX_LO_STR);
		    printf(", state=MDB_TEMPORARY");
#  ifdef HAVE_STRUCT_BR_MDB_ENTRY_FLAGS
		    printf(", flags=MDB_FLAGS_OFFLOAD");
#  endif
#  ifdef HAVE_STRUCT_BR_MDB_ENTRY_VID
		    PRINT_FIELD_U(", ", entry, vid);
#  endif
		    printf(", addr={u=");
		    print_quoted_hex(&entry.addr.u, sizeof(entry.addr.u));
		    printf(", proto=htons(AF_UNSPEC)}}"
			   ", {nla_len=%u, nla_type=MDBA_MDB_EATTR_TIMER}}}",
			   nla.nla_len));
# endif /* HAVE_STRUCT_BR_MDB_ENTRY */

	puts("+++ exited with 0 +++");
	return 0;
}

#else

SKIP_MAIN_UNDEFINED("HAVE_STRUCT_BR_PORT_MSG")