]> granicus.if.org Git - strace/commitdiff
tests: enhance nlattr_inet_diag_msg test
authorDmitry V. Levin <ldv@altlinux.org>
Fri, 30 Jun 2017 21:38:49 +0000 (21:38 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Fri, 30 Jun 2017 21:38:49 +0000 (21:38 +0000)
* tests/test_nlattr.h: New file.
* tests/Makefile.am (libtests_a_SOURCES): Add it.
* tests/nlattr_inet_diag_msg.c: Include "test_nlattr.h".
(test_inet_diag_meminfo, test_inet_diag_vegasinfo,
test_inet_diag_dctcpinfo, test_inet_diag_bbrinfo): Remove.
(address): New variable.
(init_inet_diag_msg): Remove "address" argument, add const qualifier
to all remaining arguments.
(print_inet_diag_msg, print_uint): New functions.
(main): Use macros from test_nlattr.h file.

tests/Makefile.am
tests/nlattr_inet_diag_msg.c
tests/test_nlattr.h [new file with mode: 0644]

index 275e9f8d466f6a06c80813f146c8c684f36f7231..fd07b03c582fb741187d7f5fc5572dad363985ef 100644 (file)
@@ -63,6 +63,7 @@ libtests_a_SOURCES = \
        skip_unavailable.c \
        sprintrc.c \
        tail_alloc.c \
+       test_nlattr.h \
        tests.h \
        tprintf.c \
        # end of libtests_a_SOURCES
index dd0c46cc1af595b2e19f4d91576119ab2484b1f7..65ca667b5e08e453d04bfca4337f412130d05648 100644 (file)
  */
 
 #include "tests.h"
-#include "netlink.h"
 
 #include <stdio.h>
 #include <string.h>
-#include <sys/socket.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include "test_nlattr.h"
 #include <linux/inet_diag.h>
-#include <linux/rtnetlink.h>
 #include <linux/sock_diag.h>
 
+static const char address[] = "10.11.12.13";
+
 static void
-init_inet_diag_msg(struct nlmsghdr *nlh, unsigned int msg_len,
-                  const char *address)
+init_inet_diag_msg(struct nlmsghdr *const nlh, const unsigned int msg_len)
 {
-       struct inet_diag_msg *msg;
-
        SET_STRUCT(struct nlmsghdr, nlh,
                .nlmsg_len = msg_len,
                .nlmsg_type = SOCK_DIAG_BY_FAMILY,
                .nlmsg_flags = NLM_F_DUMP
        );
 
-       msg = NLMSG_DATA(nlh);
+       struct inet_diag_msg *const msg = NLMSG_DATA(nlh);
        SET_STRUCT(struct inet_diag_msg, msg,
                .idiag_family = AF_INET,
                .idiag_state = TCP_LISTEN
@@ -62,33 +59,9 @@ init_inet_diag_msg(struct nlmsghdr *nlh, unsigned int msg_len,
 }
 
 static void
-test_inet_diag_meminfo(const int fd)
+print_inet_diag_msg(const unsigned int msg_len)
 {
-       const int hdrlen = sizeof(struct inet_diag_msg);
-       const char address[] = "87.65.43.21";
-       struct nlmsghdr *nlh;
-       struct nlattr *nla;
-       unsigned int nla_len;
-       unsigned int msg_len;
-       void *const nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
-       long rc;
-
-       /* len < sizeof(struct inet_diag_meminfo) */
-       nla_len = NLA_HDRLEN + 2;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_MEMINFO
-       );
-       memcpy(RTA_DATA(nla), "12", 2);
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
+       printf("{len=%u, type=SOCK_DIAG_BY_FAMILY"
               ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
               ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
               ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
@@ -96,358 +69,60 @@ test_inet_diag_meminfo(const int fd)
               ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
               ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
               ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_MEMINFO}"
-              ", \"12\"}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              msg_len, sprintrc(rc));
-
-       /* short read of inet_diag_meminfo */
-       nla_len = NLA_HDRLEN + sizeof(struct inet_diag_meminfo);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - (nla_len - 1);
-       init_inet_diag_msg(nlh, msg_len, address);
+              ", idiag_inode=0}",
+              msg_len, address, address);
+}
 
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_MEMINFO
-       );
+static void
+print_uint(const unsigned int *p)
+{
+       printf("%u", *p);
+}
 
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
+int
+main(void)
+{
+       skip_if_unavailable("/proc/self/fd/");
 
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_MEMINFO}"
-              ", %p}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              RTA_DATA(nla), msg_len, sprintrc(rc));
+       const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
+       const unsigned int hdrlen = sizeof(struct inet_diag_msg);
+       void *const nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
 
-       /* inet_diag_meminfo */
-       nla_len = NLA_HDRLEN + sizeof(struct inet_diag_meminfo);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
+#define DEFAULT_STRLEN 32
+       static char pattern[DEFAULT_STRLEN];
+       fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
 
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_MEMINFO
-       );
        static const struct inet_diag_meminfo minfo = {
                .idiag_rmem = 0xfadcacdb,
                .idiag_wmem = 0xbdabcada,
                .idiag_fmem = 0xbadbfafb,
                .idiag_tmem = 0xfdacdadf
        };
-       memcpy(RTA_DATA(nla), &minfo, sizeof(minfo));
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_MEMINFO}"
-              ", {idiag_rmem=%u, idiag_wmem=%u, idiag_fmem=%u, idiag_tmem=%u}}}"
-              ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              minfo.idiag_rmem, minfo.idiag_wmem,
-              minfo.idiag_fmem, minfo.idiag_tmem,
-              msg_len, sprintrc(rc));
-}
-
-static void
-test_inet_diag_vegasinfo(const int fd)
-{
-       const int hdrlen = sizeof(struct inet_diag_msg);
-       const char address[] = "87.65.43.21";
-       struct nlmsghdr *nlh;
-       struct nlattr *nla;
-       unsigned int nla_len;
-       unsigned int msg_len;
-       void *const nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
-       long rc;
-
-       /* len < sizeof(struct tcpvegas_info) */
-       nla_len = NLA_HDRLEN + 2;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_VEGASINFO
-       );
-       memcpy(RTA_DATA(nla), "12", 2);
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_VEGASINFO}"
-              ", \"12\"}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              msg_len, sprintrc(rc));
+       TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
+                          init_inet_diag_msg, print_inet_diag_msg,
+                          INET_DIAG_MEMINFO, pattern, minfo,
+                          PRINT_FIELD_U("{", minfo, idiag_rmem);
+                          PRINT_FIELD_U(", ", minfo, idiag_wmem);
+                          PRINT_FIELD_U(", ", minfo, idiag_fmem);
+                          PRINT_FIELD_U(", ", minfo, idiag_tmem);
+                          printf("}"));
 
-       /* short read of tcpvegas_info */
-       nla_len = NLA_HDRLEN + sizeof(struct tcpvegas_info);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - (nla_len - 1);
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_VEGASINFO
-       );
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_VEGASINFO}"
-              ", %p}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              RTA_DATA(nla), msg_len, sprintrc(rc));
-
-       /* tcpvegas_info */
-       nla_len = NLA_HDRLEN + sizeof(struct tcpvegas_info);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_VEGASINFO
-       );
        static const struct tcpvegas_info vegas = {
                .tcpv_enabled = 0xfadcacdb,
                .tcpv_rttcnt = 0xbdabcada,
                .tcpv_rtt = 0xbadbfafb,
                .tcpv_minrtt = 0xfdacdadf
        };
-       memcpy(RTA_DATA(nla), &vegas, sizeof(vegas));
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_VEGASINFO}"
-              ", {tcpv_enabled=%u, tcpv_rttcnt=%u, tcpv_rtt=%u"
-              ", tcpv_minrtt=%u}}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              vegas.tcpv_enabled, vegas.tcpv_rttcnt,
-              vegas.tcpv_rtt, vegas.tcpv_minrtt,
-              msg_len, sprintrc(rc));
-}
-
-static void
-test_inet_diag_skmeminfo(const int fd)
-{
-       const int hdrlen = sizeof(struct inet_diag_msg);
-       const char address[] = "87.65.43.21";
-       struct nlmsghdr *nlh;
-       struct nlattr *nla;
-       unsigned int nla_len;
-       unsigned int msg_len;
-       void *const nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
-       long rc;
-
-       /* len < sizeof(uint32_t) */
-       nla_len = NLA_HDRLEN + 2;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_SKMEMINFO
-       );
-       memcpy(RTA_DATA(nla), "12", 2);
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u"
-              ", nla_type=INET_DIAG_SKMEMINFO}, \"12\"}}"
-              ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              msg_len, sprintrc(rc));
-
-       /* len = sizeof(uint32_t) * 2 - 1 */
-       nla_len = NLA_HDRLEN + sizeof(uint32_t) * 2 - 1;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_SKMEMINFO
-       );
-       static const uint32_t mem[] = { 0xaffacbad, 0xffadbcab };
-       memcpy(RTA_DATA(nla), mem, sizeof(mem[0]));
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_SKMEMINFO}"
-              ", [%u]}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              mem[0], msg_len, sprintrc(rc));
-
-       /* len = sizeof(uint32_t) * 2 */
-       nla_len = NLA_HDRLEN + sizeof(uint32_t) * 2;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_SKMEMINFO
-       );
-       memcpy(RTA_DATA(nla), mem, sizeof(mem));
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_SKMEMINFO}"
-              ", [%u, %u]}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              mem[0], mem[1], msg_len, sprintrc(rc));
-}
-
-static void
-test_inet_diag_dctcpinfo(const int fd)
-{
-       const int hdrlen = sizeof(struct inet_diag_msg);
-       const char address[] = "87.65.43.21";
-       struct nlmsghdr *nlh;
-       struct nlattr *nla;
-       unsigned int nla_len;
-       unsigned int msg_len;
-       void *const nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
-       long rc;
+       TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
+                          init_inet_diag_msg, print_inet_diag_msg,
+                          INET_DIAG_VEGASINFO, pattern, vegas,
+                          PRINT_FIELD_U("{", vegas, tcpv_enabled);
+                          PRINT_FIELD_U(", ", vegas, tcpv_rttcnt);
+                          PRINT_FIELD_U(", ", vegas, tcpv_rtt);
+                          PRINT_FIELD_U(", ", vegas, tcpv_minrtt);
+                          printf("}"));
 
-       /* len < sizeof(struct tcp_dctcp_info) */
-       nla_len = NLA_HDRLEN + 2;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
 
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_DCTCPINFO
-       );
-       memcpy(RTA_DATA(nla), "12", 2);
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_DCTCPINFO}"
-              ", \"12\"}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              msg_len, sprintrc(rc));
-
-       /* short read of tcp_dctcp_info */
-       nla_len = NLA_HDRLEN + sizeof(struct tcp_dctcp_info);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - (nla_len - 1);
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_DCTCPINFO
-       );
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_DCTCPINFO}"
-              ", %p}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              RTA_DATA(nla), msg_len, sprintrc(rc));
-
-       /* tcp_dctcp_info */
-       nla_len = NLA_HDRLEN + sizeof(struct tcp_dctcp_info);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_DCTCPINFO
-       );
        static const struct tcp_dctcp_info dctcp = {
                .dctcp_enabled = 0xfdac,
                .dctcp_ce_state = 0xfadc,
@@ -455,106 +130,16 @@ test_inet_diag_dctcpinfo(const int fd)
                .dctcp_ab_ecn = 0xbadbfafb,
                .dctcp_ab_tot = 0xfdacdadf
        };
-       memcpy(RTA_DATA(nla), &dctcp, sizeof(dctcp));
+       TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
+                          init_inet_diag_msg, print_inet_diag_msg,
+                          INET_DIAG_DCTCPINFO, pattern, dctcp,
+                          PRINT_FIELD_U("{", dctcp, dctcp_enabled);
+                          PRINT_FIELD_U(", ", dctcp, dctcp_ce_state);
+                          PRINT_FIELD_U(", ", dctcp, dctcp_alpha);
+                          PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn);
+                          PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot);
+                          printf("}"));
 
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_DCTCPINFO}"
-              ", {dctcp_enabled=%u, dctcp_ce_state=%u"
-              ", dctcp_alpha=%u, dctcp_ab_ecn=%u, dctcp_ab_tot=%u}}}"
-              ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              dctcp.dctcp_enabled, dctcp.dctcp_ce_state,
-              dctcp.dctcp_alpha, dctcp.dctcp_ab_ecn,
-              dctcp.dctcp_ab_tot, msg_len, sprintrc(rc));
-}
-
-static void
-test_inet_diag_bbrinfo(const int fd)
-{
-       const int hdrlen = sizeof(struct inet_diag_msg);
-       const char address[] = "12.34.56.78";
-       struct nlmsghdr *nlh;
-       struct nlattr *nla;
-       unsigned int nla_len;
-       unsigned int msg_len;
-       void *const nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
-       long rc;
-
-       /* len < sizeof(struct tcp_bbr_info) */
-       nla_len = NLA_HDRLEN + 2;
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_BBRINFO
-       );
-       memcpy(RTA_DATA(nla), "12", 2);
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_BBRINFO}"
-              ", \"12\"}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              msg_len, sprintrc(rc));
-
-       /* short read of tcp_bbr_info */
-       nla_len = NLA_HDRLEN + sizeof(struct tcp_bbr_info);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - (nla_len - 1);
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_BBRINFO
-       );
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
-
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_BBRINFO}"
-              ", %p}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              RTA_DATA(nla), msg_len, sprintrc(rc));
-
-       /* tcp_bbr_info */
-       nla_len = NLA_HDRLEN + sizeof(struct tcp_bbr_info);
-       msg_len = NLMSG_SPACE(hdrlen) + nla_len;
-       nlh = nlh0 - nla_len;
-       init_inet_diag_msg(nlh, msg_len, address);
-
-       nla = NLMSG_ATTR(nlh, hdrlen);
-       SET_STRUCT(struct nlattr, nla,
-               .nla_len = nla_len,
-               .nla_type = INET_DIAG_BBRINFO
-       );
        static const struct tcp_bbr_info bbr = {
                .bbr_bw_lo = 0xfdacdadf,
                .bbr_bw_hi = 0xfadcacdb,
@@ -562,41 +147,21 @@ test_inet_diag_bbrinfo(const int fd)
                .bbr_pacing_gain = 0xbadbfafb,
                .bbr_cwnd_gain = 0xfdacdadf
        };
-       memcpy(RTA_DATA(nla), &bbr, sizeof(bbr));
-
-       rc = sendto(fd, nlh, msg_len, MSG_DONTWAIT, NULL, 0);
+       TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
+                          init_inet_diag_msg, print_inet_diag_msg,
+                          INET_DIAG_BBRINFO, pattern, bbr,
+                          PRINT_FIELD_X("{", bbr, bbr_bw_lo);
+                          PRINT_FIELD_X(", ", bbr, bbr_bw_hi);
+                          PRINT_FIELD_U(", ", bbr, bbr_min_rtt);
+                          PRINT_FIELD_U(", ", bbr, bbr_pacing_gain);
+                          PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain);
+                          printf("}"));
 
-       printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
-              ", flags=NLM_F_DUMP, seq=0, pid=0}, {idiag_family=AF_INET"
-              ", idiag_state=TCP_LISTEN, idiag_timer=0, idiag_retrans=0"
-              ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_src)"
-              ", inet_pton(AF_INET, \"%s\", &idiag_dst)"
-              ", idiag_if=0, idiag_cookie=[0, 0]}, idiag_expires=0"
-              ", idiag_rqueue=0, idiag_wqueue=0, idiag_uid=0"
-              ", idiag_inode=0}, {{nla_len=%u, nla_type=INET_DIAG_BBRINFO}"
-              ", {bbr_bw_lo=%#x, bbr_bw_hi=%#x, bbr_min_rtt=%u"
-              ", bbr_pacing_gain=%u, bbr_cwnd_gain=%u}}}"
-              ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
-              fd, msg_len, address, address, nla_len,
-              bbr.bbr_bw_lo, bbr.bbr_bw_hi, bbr.bbr_min_rtt,
-              bbr.bbr_pacing_gain, bbr.bbr_cwnd_gain,
-              msg_len, sprintrc(rc));
-}
-
-int main(void)
-{
-       skip_if_unavailable("/proc/self/fd/");
-
-       int fd = create_nl_socket(NETLINK_SOCK_DIAG);
-
-       test_inet_diag_meminfo(fd);
-       test_inet_diag_vegasinfo(fd);
-       test_inet_diag_skmeminfo(fd);
-       test_inet_diag_dctcpinfo(fd);
-       test_inet_diag_bbrinfo(fd);
-
-       printf("+++ exited with 0 +++\n");
+       static const uint32_t mem[] = { 0xaffacbad, 0xffadbcab };
+       TEST_NLATTR_ARRAY(fd, nlh0, hdrlen,
+                         init_inet_diag_msg, print_inet_diag_msg,
+                         INET_DIAG_SKMEMINFO, pattern, mem, print_uint);
 
+       puts("+++ exited with 0 +++");
        return 0;
 }
diff --git a/tests/test_nlattr.h b/tests/test_nlattr.h
new file mode 100644 (file)
index 0000000..fb23f34
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2017 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 <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include "netlink.h"
+#include <linux/rtnetlink.h>
+
+static void
+init_nlattr(struct nlattr *const nla,
+           const uint16_t nla_len,
+           const uint16_t nla_type,
+           const void *const src,
+           const size_t n)
+{
+       SET_STRUCT(struct nlattr, nla,
+               .nla_len = nla_len,
+               .nla_type = nla_type,
+       );
+
+       memcpy(RTA_DATA(nla), src, n);
+}
+
+static void
+print_nlattr(const unsigned int nla_len, const char *const nla_type)
+{
+       printf(", {{nla_len=%u, nla_type=%s}, ", nla_len, nla_type);
+}
+
+#define TEST_NLATTR_(fd_, nlh0_, hdrlen_,                              \
+                    init_msg_, print_msg_,                             \
+                    nla_type_, nla_type_str_,                          \
+                    nla_data_len_, src_, slen_, ...)                   \
+       do {                                                            \
+               struct nlmsghdr *const nlh =                            \
+                       (nlh0_) - (NLA_HDRLEN + (slen_));               \
+               struct nlattr *const nla = NLMSG_ATTR(nlh, (hdrlen_));  \
+               const unsigned int nla_len =                            \
+                       NLA_HDRLEN + (nla_data_len_);                   \
+               const unsigned int msg_len =                            \
+                       NLMSG_SPACE(hdrlen_) + nla_len;                 \
+                                                                       \
+               (init_msg_)(nlh, msg_len);                              \
+               init_nlattr(nla, nla_len, (nla_type_),                  \
+                          (src_), (slen_));                            \
+                                                                       \
+               const char *const errstr =                              \
+                       sprintrc(sendto((fd_), nlh, msg_len,            \
+                                       MSG_DONTWAIT, NULL, 0));        \
+                                                                       \
+               printf("sendto(%d, {", (fd_));                          \
+               (print_msg_)(msg_len);                                  \
+               print_nlattr(nla_len, (nla_type_str_));                 \
+                                                                       \
+               { __VA_ARGS__; }                                        \
+                                                                       \
+               printf("}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",         \
+                      msg_len, errstr);                                \
+       } while (0)
+
+#define TEST_NLATTR(fd_, nlh0_, hdrlen_,                               \
+                   init_msg_, print_msg_,                              \
+                   nla_type_,                                          \
+                   nla_data_len_, src_, slen_, ...)                    \
+       TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                         \
+               (init_msg_), (print_msg_),                              \
+               (nla_type_), #nla_type_,                                \
+               (nla_data_len_), (src_), (slen_), __VA_ARGS__)
+
+#define TEST_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,                                \
+                          init_msg_, print_msg_,                       \
+                          nla_type_, pattern_, obj_, ...)              \
+       do {                                                            \
+               /* len < sizeof(obj_) */                                \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof(obj_) - 1,                               \
+                       (pattern_), sizeof(obj_) - 1,                   \
+                       printf("\"%.*s\"",                              \
+                       (int) sizeof(obj_) - 1, (pattern_)));           \
+               /* short read of sizeof(obj_) */                        \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof(obj_),                                   \
+                       (pattern_), sizeof(obj_) - 1,                   \
+                       printf("%p",                                    \
+                              RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))));  \
+               /* sizeof(obj_) */                                      \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof(obj_),                                   \
+                       &(obj_), sizeof(obj_),                          \
+                       __VA_ARGS__);                                   \
+       } while (0)
+
+#define TEST_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,                         \
+                         init_msg_, print_msg_,                        \
+                         nla_type_, pattern_, obj_, print_elem_)       \
+       do {                                                            \
+               /* len < sizeof((obj_)[0]) */                           \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof((obj_)[0]) - 1,                          \
+                       (pattern_), sizeof((obj_)[0]) - 1,              \
+                       printf("\"%.*s\"",                              \
+                              (int) sizeof((obj_)[0]) - 1,             \
+                              (pattern_)));                            \
+               /* sizeof((obj_)[0]) < len < sizeof(obj_) */            \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof(obj_) - 1,                               \
+                       &(obj_), sizeof(obj_) - 1,                      \
+                       printf("[");                                    \
+                       size_t i;                                       \
+                       for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {    \
+                               if (i) printf(", ");                    \
+                               (print_elem_)(&(obj_)[i]);              \
+                       }                                               \
+                       printf("]"));                                   \
+               /* short read of sizeof(obj_) */                        \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof(obj_),                                   \
+                       &(obj_), sizeof(obj_) - 1,                      \
+                       printf("[");                                    \
+                       size_t i;                                       \
+                       for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {    \
+                               if (i) printf(", ");                    \
+                               (print_elem_)(&(obj_)[i]);              \
+                       }                                               \
+                       printf(", %p]",                                 \
+                              RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))     \
+                               + sizeof((obj_)[0])));                  \
+               /* sizeof(obj_) */                                      \
+               TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),                 \
+                       (init_msg_), (print_msg_),                      \
+                       (nla_type_), #nla_type_,                        \
+                       sizeof(obj_),                                   \
+                       &(obj_), sizeof(obj_),                          \
+                       printf("[");                                    \
+                       size_t i;                                       \
+                       for (i = 0; i < ARRAY_SIZE(obj_); ++i) {        \
+                               if (i) printf(", ");                    \
+                               (print_elem_)(&(obj_)[i]);              \
+                       }                                               \
+                       printf("]"));                                   \
+       } while (0)
+
+#define PRINT_FIELD_U(prefix_, where_, field_)                         \
+       printf("%s%s=%u", (prefix_), #field_, ((where_).field_))
+
+#define PRINT_FIELD_X(prefix_, where_, field_)                         \
+       printf("%s%s=%#x", (prefix_), #field_, ((where_).field_))