]> granicus.if.org Git - strace/commitdiff
tests: check decoding of IFLA_LINKINFO netlink attribute
authorEugene Syromyatnikov <evgsyr@gmail.com>
Sun, 10 Jun 2018 10:54:08 +0000 (12:54 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 11 Jun 2018 14:02:06 +0000 (14:02 +0000)
* 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>
tests/.gitignore
tests/gen_tests.in
tests/nlattr_ifla_linkinfo.c [new file with mode: 0644]
tests/pure_executables.list

index 4c5fd7fab6e2ff924257e66358611ad0903a2b76..b42b13124bfa12b012b696212c135f50cb665d68 100644 (file)
@@ -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
index 9d6c00beaf78b408820e3688f6790a04b86d1ee3..fcee324ed587ecd002aa86e5c94e304e123b4799 100644 (file)
@@ -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 (file)
index 0000000..1bf1bef
--- /dev/null
@@ -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;
+}
index dea26745fee608cb5e85d6f3ba70fff515fe329a..866767527cfd13ba79d385cea16d991d02dd9861 100755 (executable)
@@ -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