summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2018-06-10 12:54:08 +0200
committerDmitry V. Levin <ldv@altlinux.org>2018-06-11 14:02:06 +0000
commitd2aa5046e95b35a83fcfd91758d0a24e99792c6d (patch)
tree4b7ee91d9560d84e380f2235e915afe103f80c8b
parent418625eaaacd43b84736788d6fe40c30a2a0a3d5 (diff)
downloadstrace-d2aa5046e95b35a83fcfd91758d0a24e99792c6d.tar.gz
tests: check decoding of IFLA_LINKINFO netlink attribute
* tests/nlattr_ifla_linkinfo.c: New file. * tests/pure_executables.list: Add nlattr_ifla_linkinfo. * tests/.gitignore: Likewise. * tests/gen_tests.in (nlattr_ifla_linkinfo): New test. Co-Authored-by: Dmitry V. Levin <ldv@altlinux.org>
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/gen_tests.in1
-rw-r--r--tests/nlattr_ifla_linkinfo.c711
-rwxr-xr-xtests/pure_executables.list1
4 files changed, 714 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
index 4c5fd7fab..b42b13124 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -289,6 +289,7 @@ nlattr_ifaddrmsg
nlattr_ifinfomsg
nlattr_ifla_af_spec
nlattr_ifla_brport
+nlattr_ifla_linkinfo
nlattr_ifla_port
nlattr_ifla_xdp
nlattr_inet_diag_msg
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 9d6c00bea..fcee324ed 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -264,6 +264,7 @@ nlattr_ifaddrmsg +netlink_sock_diag.test
nlattr_ifinfomsg +netlink_sock_diag.test
nlattr_ifla_af_spec +netlink_sock_diag.test
nlattr_ifla_brport +netlink_sock_diag.test
+nlattr_ifla_linkinfo +netlink_sock_diag.test
nlattr_ifla_port +netlink_sock_diag.test
nlattr_ifla_xdp +netlink_sock_diag.test
nlattr_inet_diag_msg +netlink_sock_diag.test
diff --git a/tests/nlattr_ifla_linkinfo.c b/tests/nlattr_ifla_linkinfo.c
new file mode 100644
index 000000000..1bf1befa5
--- /dev/null
+++ b/tests/nlattr_ifla_linkinfo.c
@@ -0,0 +1,711 @@
+/*
+ * IFLA_LINKINFO netlink attribute decoding check.
+ *
+ * Copyright (c) 2018 The strace developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <arpa/inet.h>
+
+#include "test_nlattr.h"
+
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#ifdef HAVE_LINUX_IF_LINK_H
+# include <linux/if_link.h>
+#endif
+#include <linux/rtnetlink.h>
+
+#define XLAT_MACROS_ONLY
+# include <xlat/rtnl_link_attrs.h>
+# include <xlat/rtnl_ifla_info_attrs.h>
+#undef XLAT_MACROS_ONLY
+
+#define IFLA_ATTR IFLA_LINKINFO
+#include "nlattr_ifla.h"
+
+#define COMMA ,
+#define TEST_UNKNOWN_TUNNELS(fd_, nlh0_, objtype_, objtype_str_, \
+ obj_, objsz_, arrstrs_, ...) \
+ do { \
+ /* 64 is guestimate for maximum unknown type len */ \
+ char buf[8 * 2 + 64 + objsz_]; \
+ const char **arrstrs[] = arrstrs_; \
+ const char ***arrstrs_pos = arrstrs; \
+ const char **arrstr = *arrstrs_pos; \
+ const char *type = NULL; \
+ \
+ for (type = arrstr ? arrstr[0] : NULL; type && arrstr; \
+ type = (++arrstr)[0] ? arrstr[0] \
+ : (++arrstrs_pos)[0] \
+ ? (arrstr = arrstrs_pos[0])[0] \
+ : NULL) \
+ { \
+ size_t type_len = strlen(type) + 1; \
+ \
+ if (type_len > 64) \
+ error_msg_and_fail("Unexpectedly long " \
+ "unknown type: \"%s\" " \
+ "(length is %zu)", \
+ type, type_len); \
+ \
+ struct nlattr obj_nla = { \
+ .nla_len = NLA_HDRLEN + (objsz_), \
+ .nla_type = (objtype_), \
+ }; \
+ \
+ char *pos = buf; \
+ memcpy(pos, type, type_len); \
+ pos += NLA_ALIGN(type_len); \
+ memcpy(pos, &obj_nla, sizeof(obj_nla)); \
+ pos += sizeof(obj_nla); \
+ memcpy(pos, (obj_), (objsz_)); \
+ \
+ TEST_NLATTR_EX_((fd_), \
+ (nlh0_) - hdrlen - (pos - buf), \
+ hdrlen + NLA_HDRLEN, \
+ init_ifinfomsg, print_ifinfomsg, \
+ IFLA_INFO_KIND, "IFLA_INFO_KIND", \
+ type_len, objsz_ + (pos - buf), \
+ buf, objsz_ + (pos - buf), \
+ printf("\"%s\"}", type); \
+ printf(", {{nla_len=%zu" \
+ ", nla_type=%s}, ", \
+ (objsz_) + NLA_HDRLEN, \
+ (objtype_str_)); \
+ \
+ { __VA_ARGS__; } \
+ \
+ printf("}")); \
+ } \
+ } while (0)
+
+#define TEST_LINKINFO_(fd_, nlh0_, nla_type_, nla_type_str_, tuntype_, \
+ obj_, objsz_, pattern_, fallback_func_, ...) \
+ do { \
+ size_t tuntype_len = strlen(tuntype_) + 1; \
+ char *buf = tail_alloc(NLA_ALIGN(tuntype_len) \
+ + NLA_HDRLEN + (objsz_)); \
+ char *pos = buf; \
+ \
+ struct nlattr obj_nla = { \
+ .nla_len = NLA_HDRLEN + (objsz_), \
+ .nla_type = (nla_type_), \
+ }; \
+ \
+ memcpy(pos, (tuntype_), tuntype_len); \
+ pos += NLA_ALIGN(tuntype_len); \
+ memcpy(pos, &obj_nla, sizeof(obj_nla)); \
+ pos += sizeof(obj_nla); \
+ memcpy(pos, &(obj_), (objsz_)); \
+ \
+ if (fallback_func_ == print_quoted_hex) { \
+ TEST_NLATTR_EX_((fd_), \
+ (nlh0_) - NLA_HDRLEN, \
+ hdrlen + NLA_HDRLEN, \
+ init_ifinfomsg, print_ifinfomsg, \
+ IFLA_INFO_KIND, "IFLA_INFO_KIND", \
+ tuntype_len, \
+ objsz_ + (pos - buf) - 1, \
+ buf, objsz_ + (pos - buf) - 1, \
+ printf("\"%s\"}", (tuntype_)); \
+ printf(", {{nla_len=%zu" \
+ ", nla_type=%s}, ", \
+ (objsz_) + NLA_HDRLEN, \
+ (nla_type_str_)); \
+ (fallback_func_)((obj_), \
+ (objsz_) - 1); \
+ printf("}")); \
+ } \
+ \
+ TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN, \
+ hdrlen + NLA_HDRLEN, \
+ init_ifinfomsg, print_ifinfomsg, \
+ IFLA_INFO_KIND, "IFLA_INFO_KIND", \
+ tuntype_len, objsz_ + (pos - buf), \
+ buf, objsz_ + (pos - buf) - 1, \
+ printf("\"%s\"}", (tuntype_)); \
+ printf(", {{nla_len=%zu, nla_type=%s}, ", \
+ (objsz_) + NLA_HDRLEN, \
+ (nla_type_str_)); \
+ printf("%p}", \
+ RTA_DATA(NLMSG_ATTR(nlh, \
+ (hdrlen + NLA_HDRLEN + (pos - buf)))) \
+ ) \
+ ); \
+ \
+ TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN, \
+ hdrlen + NLA_HDRLEN, \
+ init_ifinfomsg, print_ifinfomsg, \
+ IFLA_INFO_KIND, "IFLA_INFO_KIND", \
+ tuntype_len, objsz_ + (pos - buf), \
+ buf, objsz_ + (pos - buf), \
+ printf("\"%s\"}", (tuntype_)); \
+ printf(", {{nla_len=%zu, nla_type=%s}, ", \
+ (objsz_) + NLA_HDRLEN, \
+ (nla_type_str_)); \
+ \
+ { __VA_ARGS__; } \
+ \
+ printf("}")); \
+ } while (0)
+
+#define TEST_LINKINFO(fd_, nlh0_, nla_type_, tuntype_, \
+ obj_, pattern_, fallback_func_, ...) \
+ TEST_LINKINFO_((fd_), (nlh0_), nla_type_, #nla_type_, (tuntype_), \
+ (obj_), sizeof(obj_), pattern_, fallback_func_, \
+ __VA_ARGS__)
+
+#define TEST_NESTED_LINKINFO(fd_, nlh0_, \
+ nla_type_, nla_type_str_, tuntype_, \
+ subnla_type_, subnla_type_str_, \
+ obj_, pattern_, ...) \
+ do { \
+ size_t tuntype_len = strlen(tuntype_) + 1; \
+ struct { \
+ size_t sz; \
+ const char *str; \
+ } attrs[] = { __VA_ARGS__ }; \
+ size_t tunhdrlen; \
+ size_t buflen = NLA_ALIGN(tuntype_len) + NLA_HDRLEN; \
+ size_t attrsz = 0; \
+ \
+ for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
+ attrsz += NLA_HDRLEN + NLA_ALIGN(attrs[i].sz); \
+ \
+ buflen += attrsz; \
+ \
+ char *buf = tail_alloc(buflen); \
+ char *pos = buf; \
+ \
+ struct nlattr nla = { \
+ .nla_len = NLA_HDRLEN + attrsz, \
+ .nla_type = (nla_type_), \
+ }; \
+ \
+ memcpy(pos, (tuntype_), tuntype_len); \
+ pos += NLA_ALIGN(tuntype_len); \
+ memcpy(pos, &nla, sizeof(nla)); \
+ pos += sizeof(nla); \
+ \
+ tunhdrlen = pos - buf; \
+ \
+ nla.nla_type = subnla_type_; \
+ \
+ for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) { \
+ nla.nla_len = NLA_HDRLEN + attrs[i].sz; \
+ memcpy(pos, &nla, sizeof(nla)); \
+ pos += sizeof(nla); \
+ \
+ memcpy(pos, &(obj_), MIN(sizeof(obj_), attrs[i].sz)); \
+ \
+ if (attrs[i].sz > sizeof(obj_)) \
+ memcpy(pos + sizeof(obj_), \
+ &(pattern_), \
+ attrs[i].sz - sizeof(obj_)); \
+ \
+ pos += NLA_ALIGN(attrs[i].sz); \
+ } \
+ \
+ TEST_NLATTR_EX_((fd_), (nlh0_) - hdrlen - tunhdrlen, \
+ hdrlen + NLA_HDRLEN, \
+ init_ifinfomsg, print_ifinfomsg, \
+ IFLA_INFO_KIND, "IFLA_INFO_KIND", \
+ tuntype_len, buflen, \
+ buf, buflen, \
+ printf("\"%s\"}", (tuntype_)); \
+ printf(", {{nla_len=%zu, nla_type=%s}, [", \
+ attrsz + NLA_HDRLEN, \
+ (nla_type_str_)); \
+ \
+ for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
+ printf("%s%s{nla_len=%zu" \
+ ", nla_type=%s}%s%s%s", \
+ i ? ", " : "", \
+ attrs[i].str ? "{": "", \
+ attrs[i].sz + NLA_HDRLEN, \
+ subnla_type_str_, \
+ attrs[i].str ? ", ": "", \
+ attrs[i].str ?: "", \
+ attrs[i].str ? "}" : ""); \
+ \
+ printf("]}")); \
+ } while (0)
+
+int
+main(void)
+{
+ static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd };
+ static const char *unsupported_tunnel_types[] = {
+ "batadv", "bond",
+ "caif", "cfhsi",
+ "dummy",
+ "erspan",
+ "geneve", "gre", "gretap", "gtp",
+ "hsr",
+ "ifb", "ip6erspan", "ip6gre", "ip6gretap", "ip6tnl",
+ "ipip", "ipoib", "ipvlan", "ipvtap",
+ "lowpan",
+ "macsec", "macvlan", "macvtap",
+ "netdevsim", "nlmon",
+ "openvswitch",
+ "ppp",
+ "rmnet",
+ "sit",
+ "team",
+ "vcan", "veth", "vlan", "vrf", "vsockmon",
+ "vti", "vti6", "vxcan", "vxlan",
+ NULL
+ };
+ static const char *unsupported_xstats_types[] = {
+ "bridge",
+ "tun",
+ NULL
+ };
+ static const char *unsupported_data_types[] = {
+ "can",
+ NULL
+ };
+
+ skip_if_unavailable("/proc/self/fd/");
+
+ const int fd = create_nl_socket(NETLINK_ROUTE);
+
+ const unsigned int hdrlen = sizeof(struct ifinfomsg);
+ void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 2 * NLA_HDRLEN + 256);
+
+ static char pattern[4096];
+ fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
+
+
+ /* unknown AF_INFO_* type */
+ TEST_NESTED_NLATTR_OBJECT(fd, nlh0, hdrlen,
+ init_ifinfomsg, print_ifinfomsg,
+ IFLA_INFO_UNSPEC, pattern, unknown_msg,
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+ TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
+ init_ifinfomsg, print_ifinfomsg,
+ 6, "0x6 /* IFLA_INFO_??? */", pattern,
+ unknown_msg, print_quoted_hex, 1,
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+
+ /* IFLA_INFO_KIND */
+ TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
+ init_ifinfomsg, print_ifinfomsg,
+ IFLA_INFO_KIND, "IFLA_INFO_KIND", pattern,
+ unknown_msg, print_quoted_stringn, 1,
+ printf("\"\\253\\254\\333\\315\"..."));
+
+
+ /* IFLA_INFO_KIND + IFLA_INFO_UNSPEC */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_UNSPEC, "IFLA_INFO_UNSPEC",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ unsupported_xstats_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+
+ /* IFLA_INFO_KIND + IFLA_INFO_KIND */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND, "IFLA_INFO_KIND",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ unsupported_xstats_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\253\\254\\333\\315\"..."));
+
+
+ /* IFLA_INFO_KIND + IFLA_INFO_DATA */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_DATA, "IFLA_INFO_DATA",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+ struct val_name {
+ unsigned int val;
+ const char *name;
+ };
+
+ static const uint64_t u64_val = 0xdeadc0defacefeedULL;
+ static const uint32_t u32_val = 0xbadc0dedU;
+ static const uint16_t u16_val = 0xdeed;
+ static const uint8_t u8_val = 0xa1;
+
+ /* bridge attrs */
+ static const struct val_name und_br_attrs[] = {
+ { 0, "IFLA_BR_UNSPEC" },
+ { 20, "IFLA_BR_GROUP_ADDR" },
+ { 21, "IFLA_BR_FDB_FLUSH" },
+ { 40, "IFLA_BR_PAD" },
+ { 45, "0x2d /* IFLA_BR_??? */" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(und_br_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ und_br_attrs[k].val, und_br_attrs[k].name,
+ unknown_msg, pattern,
+ { 2, "\"\\xab\\xac\"" },
+ { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
+ { 6,
+ "\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
+ { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
+ "\\x63\\x64\"" },
+ { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
+ "\\x63\\x64\\x65\\x66\"" });
+ }
+
+ static const struct val_name u64_br_attrs[] = {
+ { 16, "IFLA_BR_HELLO_TIMER" },
+ { 17, "IFLA_BR_TCN_TIMER" },
+ { 18, "IFLA_BR_TOPOLOGY_CHANGE_TIMER" },
+ { 19, "IFLA_BR_GC_TIMER" },
+ { 30, "IFLA_BR_MCAST_LAST_MEMBER_INTVL" },
+ { 31, "IFLA_BR_MCAST_MEMBERSHIP_INTVL" },
+ { 32, "IFLA_BR_MCAST_QUERIER_INTVL" },
+ { 33, "IFLA_BR_MCAST_QUERY_INTVL" },
+ { 34, "IFLA_BR_MCAST_QUERY_RESPONSE_INTVL" },
+ { 35, "IFLA_BR_MCAST_STARTUP_QUERY_INTVL" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(u64_br_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ u64_br_attrs[k].val, u64_br_attrs[k].name,
+ u64_val, pattern,
+ { 7, "\""
+#if WORDS_BIGENDIAN
+ "\\xde\\xad\\xc0\\xde\\xfa\\xce\\xfe"
+#else
+ "\\xed\\xfe\\xce\\xfa\\xde\\xc0\\xad"
+#endif
+ "\"" },
+ { 8, "16045693111314087661" },
+ { 9, "16045693111314087661" });
+ }
+
+ static const struct val_name u32_br_attrs[] = {
+ { 1, "IFLA_BR_FORWARD_DELAY" },
+ { 2, "IFLA_BR_HELLO_TIME" },
+ { 3, "IFLA_BR_MAX_AGE" },
+ { 4, "IFLA_BR_AGEING_TIME" },
+ { 5, "IFLA_BR_STP_STATE" },
+ { 13, "IFLA_BR_ROOT_PATH_COST" },
+ { 26, "IFLA_BR_MCAST_HASH_ELASTICITY" },
+ { 27, "IFLA_BR_MCAST_HASH_MAX" },
+ { 28, "IFLA_BR_MCAST_LAST_MEMBER_CNT" },
+ { 29, "IFLA_BR_MCAST_STARTUP_QUERY_CNT" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(u32_br_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ u32_br_attrs[k].val, u32_br_attrs[k].name,
+ u32_val, pattern,
+ { 3, "\""
+#if WORDS_BIGENDIAN
+ "\\xba\\xdc\\x0d"
+#else
+ "\\xed\\x0d\\xdc"
+#endif
+ "\"" },
+ { 4, "3134983661" },
+ { 5, "3134983661" });
+ }
+
+ static const struct val_name u16_br_attrs[] = {
+ { 6, "IFLA_BR_PRIORITY" },
+ { 12, "IFLA_BR_ROOT_PORT" },
+ { 39, "IFLA_BR_VLAN_DEFAULT_PVID" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(u16_br_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ u16_br_attrs[k].val, u16_br_attrs[k].name,
+ u16_val, pattern,
+ { 1, "\""
+#if WORDS_BIGENDIAN
+ "\\xde"
+#else
+ "\\xed"
+#endif
+ "\"" },
+ { 2, "57069" },
+ { 3, "57069" });
+ }
+
+
+ static const struct val_name x16_br_attrs[] = {
+ { 9, "IFLA_BR_GROUP_FWD_MASK" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(x16_br_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ x16_br_attrs[k].val, x16_br_attrs[k].name,
+ u16_val, pattern,
+ { 1, "\""
+#if WORDS_BIGENDIAN
+ "\\xde"
+#else
+ "\\xed"
+#endif
+ "\"" },
+ { 2, "0xdeed" },
+ { 3, "0xdeed" });
+ }
+
+ static const struct val_name u8_br_attrs[] = {
+ { 7, "IFLA_BR_VLAN_FILTERING" },
+ { 14, "IFLA_BR_TOPOLOGY_CHANGE" },
+ { 15, "IFLA_BR_TOPOLOGY_CHANGE_DETECTED" },
+ { 22, "IFLA_BR_MCAST_ROUTER" },
+ { 23, "IFLA_BR_MCAST_SNOOPING" },
+ { 24, "IFLA_BR_MCAST_QUERY_USE_IFADDR" },
+ { 25, "IFLA_BR_MCAST_QUERIER" },
+ { 36, "IFLA_BR_NF_CALL_IPTABLES" },
+ { 37, "IFLA_BR_NF_CALL_IP6TABLES" },
+ { 38, "IFLA_BR_NF_CALL_ARPTABLES" },
+ { 41, "IFLA_BR_VLAN_STATS_ENABLED" },
+ { 42, "IFLA_BR_MCAST_STATS_ENABLED" },
+ { 43, "IFLA_BR_MCAST_IGMP_VERSION" },
+ { 44, "IFLA_BR_MCAST_MLD_VERSION" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(u8_br_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ u8_br_attrs[k].val, u8_br_attrs[k].name,
+ u8_val, pattern,
+ { 0, NULL },
+ { 1, "161" },
+ { 2, "161" });
+ }
+
+ unsigned short eth_p = htons(0x88C7);
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ 8, "IFLA_BR_VLAN_PROTOCOL",
+ eth_p, pattern,
+ { 1, "\"\\x88\"" },
+ { 2, "htons(ETH_P_PREAUTH)" },
+ { 2, "htons(ETH_P_PREAUTH)" });
+
+ static const uint8_t bridge_id[]
+ = { 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xc0, 0xde, 0xad };
+ static const struct val_name br_id_attrs[] = {
+ { 10, "IFLA_BR_ROOT_ID" },
+ { 11, "IFLA_BR_BRIDGE_ID" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(br_id_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
+ br_id_attrs[k].val, br_id_attrs[k].name,
+ bridge_id, pattern,
+ { 7, "\"\\xbe\\xef\\xfa\\xce"
+ "\\xde\\xc0\\xde\"" },
+ { 8, "{prio=[190, 239]"
+ ", addr=fa:ce:de:c0:de:ad}" },
+ { 9, "{prio=[190, 239]"
+ ", addr=fa:ce:de:c0:de:ad}" });
+ }
+
+ /* tun attrs */
+ static const struct val_name u8_tun_attrs[] = {
+ { 4, "IFLA_TUN_PI" },
+ { 5, "IFLA_TUN_VNET_HDR" },
+ { 6, "IFLA_TUN_PERSIST" },
+ { 7, "IFLA_TUN_MULTI_QUEUE" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(u8_tun_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
+ u8_tun_attrs[k].val, u8_tun_attrs[k].name,
+ u8_val, pattern,
+ { 0, NULL },
+ { 1, "161" },
+ { 2, "161" });
+ }
+
+ static const struct val_name u32_tun_attrs[] = {
+ { 8, "IFLA_TUN_NUM_QUEUES" },
+ { 9, "IFLA_TUN_NUM_DISABLED_QUEUES" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(u32_tun_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
+ u32_tun_attrs[k].val,
+ u32_tun_attrs[k].name,
+ u32_val, pattern,
+ { 3, "\""
+#if WORDS_BIGENDIAN
+ "\\xba\\xdc\\x0d"
+#else
+ "\\xed\\x0d\\xdc"
+#endif
+ "\"" },
+ { 4, "3134983661" },
+ { 5, "3134983661" });
+ }
+
+ static const struct val_name und_tun_attrs[] = {
+ { 0, "IFLA_TUN_UNSPEC" },
+ { 10, "0xa /* IFLA_TUN_??? */" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(und_tun_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
+ und_tun_attrs[k].val,
+ und_tun_attrs[k].name,
+ unknown_msg, pattern,
+ { 2, "\"\\xab\\xac\"" },
+ { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
+ { 6,
+ "\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
+ { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
+ "\\x63\\x64\"" },
+ { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
+ "\\x63\\x64\\x65\\x66\"" });
+ }
+
+ static const uint32_t minus_one = 0xffffffffU;
+ static const struct val_name uid_tun_attrs[] = {
+ { 1, "IFLA_TUN_OWNER" },
+ { 2, "IFLA_TUN_GROUP" },
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(uid_tun_attrs); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
+ uid_tun_attrs[k].val,
+ uid_tun_attrs[k].name,
+ u32_val, pattern,
+ { 3, "\""
+#if WORDS_BIGENDIAN
+ "\\xba\\xdc\\x0d"
+#else
+ "\\xed\\x0d\\xdc"
+#endif
+ "\"" },
+ { 4, "3134983661" },
+ { 5, "3134983661" });
+
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
+ uid_tun_attrs[k].val,
+ uid_tun_attrs[k].name,
+ minus_one, pattern,
+ { 3, "\"\\xff\\xff\\xff\"" },
+ { 4, "-1" },
+ { 5, "-1" });
+ }
+
+ static const struct {
+ uint8_t val;
+ const char *str;
+ } tun_types[] = {
+ { 0, "0 /* IFF_??? */"},
+ { 1, "IFF_TUN"},
+ { 2, "IFF_TAP"},
+ { 3, "0x3 /* IFF_??? */"},
+ { 0xda, "0xda /* IFF_??? */"},
+ };
+
+ for (size_t k = 0; k < ARRAY_SIZE(tun_types); k++) {
+ TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
+ 3, "IFLA_TUN_TYPE",
+ tun_types[k].val, pattern,
+ { 0, NULL },
+ { 1, tun_types[k].str },
+ { 2, tun_types[k].str });
+ }
+
+
+ /* IFLA_INFO_KIND + IFLA_INFO_XSTATS */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_XSTATS, "IFLA_INFO_XSTATS",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ /*
+ * can decoder decodes its data only if it's big
+ * enough.
+ */
+ unsupported_xstats_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+ uint32_t can_stats_data[] = {
+ 0xbadc0de0, 0xbadc0de1, 0xbadc0de2, 0xbadc0de3,
+ 0xbadc0de4, 0xbadc0de5,
+ };
+
+ TEST_LINKINFO(fd, nlh0, IFLA_INFO_XSTATS, "can",
+ can_stats_data, pattern, print_quoted_hex,
+ printf("{bus_error=3134983648"
+ ", error_warning=3134983649"
+ ", error_passive=3134983650"
+ ", bus_off=3134983651"
+ ", arbitration_lost=3134983652"
+ ", restarts=3134983653}"));
+
+
+ /* IFLA_INFO_KIND + IFLA_INFO_SLVAE_KIND */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0,
+ IFLA_INFO_SLAVE_KIND, "IFLA_INFO_SLAVE_KIND",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ unsupported_xstats_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\253\\254\\333\\315\"..."));
+
+
+ /* IFLA_INFO_KIND + IFLA_INFO_SLAVE_DATA */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0,
+ IFLA_INFO_SLAVE_DATA, "IFLA_INFO_SLAVE_DATA",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ unsupported_xstats_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+
+ /* IFLA_INFO_KIND + unknown type */
+ TEST_UNKNOWN_TUNNELS(fd, nlh0, 6, "0x6 /* IFLA_INFO_??? */",
+ unknown_msg, sizeof(unknown_msg),
+ {unsupported_tunnel_types COMMA
+ unsupported_xstats_types COMMA
+ unsupported_data_types COMMA
+ NULL},
+ printf("\"\\xab\\xac\\xdb\\xcd\""));
+
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index dea26745f..866767527 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -240,6 +240,7 @@ nlattr_ifaddrmsg
nlattr_ifinfomsg
nlattr_ifla_af_spec
nlattr_ifla_brport
+nlattr_ifla_linkinfo
nlattr_ifla_port
nlattr_ifla_xdp
nlattr_inet_diag_msg