Implement decoding of BPF_PROG_TEST_RUN command of bpf syscall
authorDmitry V. Levin <ldv@altlinux.org>
Mon, 20 Nov 2017 00:29:10 +0000 (00:29 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 20 Nov 2017 21:39:59 +0000 (21:39 +0000)
* configure.ac: Check for union bpf_attr.test.duration.
* bpf.c (decode_BPF_PROG_TEST_RUN): New function.
(SYS_FUNC(bpf)) <bpf_cmd_decoders>: Use it.
* NEWS: Mention this.
* tests/bpf.c: Include "print_fields.h".
Add macro guard for BPF_PROG_TEST_RUN decoder test.
[HAVE_UNION_BPF_ATTR_TEST_DURATION] (sample_BPF_PROG_TEST_RUN_attr):
New variable.
[HAVE_UNION_BPF_ATTR_TEST_DURATION] (init_BPF_PROG_TEST_RUN_first,
print_BPF_PROG_TEST_RUN_first, init_BPF_PROG_TEST_RUN_attr,
print_BPF_PROG_TEST_RUN_attr): New functions.
(main) [HAVE_UNION_BPF_ATTR_TEST_DURATION]: Use them.

NEWS
bpf.c
configure.ac
tests/bpf.c

diff --git a/NEWS b/NEWS
index d1d7972d78eff32d9a9ee60b18d50e4a90588d8d..d52b5c36c025e6ecfd4b1c1c6f4f6ff3564e6113 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Noteworthy changes in release ?.?? (????-??-??)
 * Improvements
   * Implemented decoding of netlink descriptor attributes as file descriptors.
   * Implemented decoding of hugetlb page size selection flags.
+  * Implemented decoding of BPF_PROG_TEST_RUN command of bpf syscall.
   * Enhanced decoding of getsockopt and setsockopt syscalls for SOL_NETLINK
     level.
   * Enhanced decoding of BPF_MAP_CREATE command of bpf syscall.
diff --git a/bpf.c b/bpf.c
index 4507d5e36dc35587c428f590042e3ed804c307ae..5b4035efb3f4687de566f9ea451fc74817834303 100644 (file)
--- a/bpf.c
+++ b/bpf.c
@@ -280,6 +280,32 @@ DEF_BPF_CMD_DECODER(BPF_PROG_DETACH)
        return RVAL_DECODED;
 }
 
+DEF_BPF_CMD_DECODER(BPF_PROG_TEST_RUN)
+{
+       struct {
+               uint32_t prog_fd, retval, data_size_in, data_size_out;
+               uint64_t ATTRIBUTE_ALIGNED(8) data_in, data_out;
+               uint32_t repeat, duration;
+       } attr = {};
+       const unsigned int len = size < sizeof(attr) ? size : sizeof(attr);
+
+       memcpy(&attr, data, len);
+
+       PRINT_FIELD_FD("{test={", attr, prog_fd, tcp);
+       PRINT_FIELD_U(", ", attr, retval);
+       PRINT_FIELD_U(", ", attr, data_size_in);
+       PRINT_FIELD_U(", ", attr, data_size_out);
+       PRINT_FIELD_X(", ", attr, data_in);
+       PRINT_FIELD_X(", ", attr, data_out);
+       PRINT_FIELD_U(", ", attr, repeat);
+       PRINT_FIELD_U(", ", attr, duration);
+       tprints("}");
+       decode_attr_extra_data(tcp, data, size, sizeof(attr));
+       tprints("}");
+
+       return RVAL_DECODED;
+}
+
 SYS_FUNC(bpf)
 {
        static const bpf_cmd_decoder_t bpf_cmd_decoders[] = {
@@ -293,6 +319,7 @@ SYS_FUNC(bpf)
                BPF_CMD_ENTRY(BPF_OBJ_GET),
                BPF_CMD_ENTRY(BPF_PROG_ATTACH),
                BPF_CMD_ENTRY(BPF_PROG_DETACH),
+               BPF_CMD_ENTRY(BPF_PROG_TEST_RUN),
        };
 
        const unsigned int cmd = tcp->u_arg[0];
index b077791a72cee54449b349e13b0a1a27a3d43d1d..e57e8989d39db7cb029d4db41facc32d9fd84709 100644 (file)
@@ -464,6 +464,7 @@ AC_CHECK_HEADERS([linux/bpf.h], [
        st_CHECK_UNION_BPF_ATTR([flags])
        st_CHECK_UNION_BPF_ATTR([numa_node])
        st_CHECK_UNION_BPF_ATTR([prog_flags])
+       AC_CHECK_MEMBERS([union bpf_attr.test.duration],,, [#include <linux/bpf.h>])
 ])
 
 AC_CHECK_TYPES(m4_normalize([
index 810f6cbde34f7b0e918810f55b7691ee2251c17b..c5e1293a071501d72d525077fe544a7eef661191 100644 (file)
@@ -35,7 +35,8 @@
   || defined HAVE_UNION_BPF_ATTR_BPF_FD                \
   || defined HAVE_UNION_BPF_ATTR_FLAGS         \
   || defined HAVE_UNION_BPF_ATTR_NUMA_NODE     \
-  || defined HAVE_UNION_BPF_ATTR_PROG_FLAGS)
+  || defined HAVE_UNION_BPF_ATTR_PROG_FLAGS    \
+  || defined HAVE_UNION_BPF_ATTR_TEST_DURATION)
 
 # include <stddef.h>
 # include <stdio.h>
@@ -43,6 +44,7 @@
 # include <string.h>
 # include <unistd.h>
 # include <linux/bpf.h>
+# include "print_fields.h"
 
 static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL;
 static const char *errstr;
@@ -561,6 +563,66 @@ print_BPF_PROG_DETACH_attr(const unsigned long addr)
 
 # endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */
 
+/* BPF_PROG_TEST_RUN command appears in kernel 4.12. */
+# ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
+
+static unsigned int
+init_BPF_PROG_TEST_RUN_first(const unsigned long eop)
+{
+       static const union bpf_attr attr = { .test.prog_fd = -1 };
+       static const unsigned int offset = sizeof(attr.test.prog_fd);
+       const unsigned long addr = eop - offset;
+
+       memcpy((void *) addr, &attr.test.prog_fd, offset);
+       return offset;
+}
+
+static void
+print_BPF_PROG_TEST_RUN_first(const unsigned long addr)
+{
+       printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0"
+              ", data_in=0, data_out=0, repeat=0, duration=0}");
+}
+
+static const union bpf_attr sample_BPF_PROG_TEST_RUN_attr = {
+       .test = {
+               .prog_fd = -1,
+               .retval = 0xfac1fed2,
+               .data_size_in = 0xfac3fed4,
+               .data_size_out = 0xfac5fed6,
+               .data_in = (uint64_t) 0xfacef11dbadc2ded,
+               .data_out = (uint64_t) 0xfacef33dbadc4ded,
+               .repeat = 0xfac7fed8,
+               .duration = 0xfac9feda
+       }
+};
+static unsigned int
+init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)
+{
+       static const unsigned int offset =
+               offsetofend(union bpf_attr, test);
+       const unsigned long addr = eop - offset;
+
+       memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset);
+       return offset;
+}
+
+static void
+print_BPF_PROG_TEST_RUN_attr(const unsigned long addr)
+{
+       PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr.test, prog_fd);
+       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, retval);
+       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_in);
+       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_out);
+       PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_in);
+       PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_out);
+       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, repeat);
+       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, duration);
+       printf("}");
+}
+
+# endif /* HAVE_UNION_BPF_ATTR_TEST_DURATION */
+
 int
 main(void)
 {
@@ -592,6 +654,10 @@ main(void)
        TEST_BPF(BPF_PROG_DETACH);
 # endif
 
+# ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
+       TEST_BPF(BPF_PROG_TEST_RUN);
+# endif
+
        sys_bpf(0xfacefeed, end_of_page, 40);
        printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n",
               end_of_page, errstr);