From 737762cb85429c559f2ee7df702f65b3a7035df4 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Wed, 21 Mar 2018 19:10:15 +0100 Subject: [PATCH] tests: refactor bpf test The aim of this change is to introduce an ability to perform multiple checks for a specific bpf command. In order to achieve so, all the related data is stored in check descriptor, and test_bpf iterates over it. There are also some provisions made in regard to future changes (specifically, the way bpf_attr_data union is defined). * tests/bpf.c (print_bpf_attr): New function, a wrapper around struct bpf_check.printer. (test_bpf_): Rename to... (test_bpf): ...this. Replace arguments with struct bpf_check pointer. Iterate over possible attribute variants. Account for changes in attribute initialisation routine: provide a pointer to locally defined union bpf_attr_data and perform memcpy afterwards. Initialise memory from data each time before a bpf call. (TEST_BPF, DEF_*, init_*, print_*): Remove. (init_BPF_PROG_LOAD_attr, print_BPF_PROG_LOAD_attr, init_BPF_OBJ_PIN_attr): New functions. (license, pathname): New variables. (BPF_MAP_CREATE_checks, BPF_MAP_LOOKUP_ELEM_checks, BPF_MAP_UPDATE_ELEM_checks, BPF_MAP_DELETE_ELEM_checks, BPF_MAP_GET_NEXT_KEY_checks, BPF_PROG_LOAD_checks, BPF_OBJ_PIN_checks, BPF_PROG_ATTACH_checks, BPF_PROG_DETACH_checks, BPF_PROG_TEST_RUN_checks, BPF_PROG_GET_NEXT_ID_checks, BPF_PROG_GET_FD_BY_ID_checks, BPF_MAP_GET_FD_BY_ID_checks, BPF_OBJ_GET_INFO_BY_FD_checks): New arrays. (BPF_OBJ_GET_checks, BPF_MAP_GET_NEXT_ID_checks): New macros. (CHK): New macro, a shorthand for initialising array of struct bpf_check. (main): New static constant checks, iterate over checks and run test_bpf with each element. Co-Authored-by: Dmitry V. Levin --- tests/bpf.c | 880 ++++++++++++++++++++++------------------------------ 1 file changed, 372 insertions(+), 508 deletions(-) diff --git a/tests/bpf.c b/tests/bpf.c index aa94e589..21d1c49b 100644 --- a/tests/bpf.c +++ b/tests/bpf.c @@ -78,6 +78,22 @@ union bpf_attr_data { char char_data[256]; }; +struct bpf_attr_check { + union bpf_attr_data data; + size_t size; + const char *str; + void (*init_fn)(struct bpf_attr_check *check); + void (*print_fn)(const struct bpf_attr_check *check, + unsigned long addr); +}; + +struct bpf_check { + kernel_ulong_t cmd; + const char *cmd_str; + const struct bpf_attr_check *checks; + size_t count; +}; + static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL; static const char *errstr; static unsigned int sizeof_attr = sizeof(union bpf_attr_data); @@ -103,77 +119,78 @@ sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size) #endif static void -test_bpf_(kernel_ulong_t cmd, const char *cmd_str, - unsigned int (*init_first)(const unsigned long eop), - void (*print_first)(const unsigned long eop), - unsigned int (*init_attr)(const unsigned long eop), - void (*print_attr)(const unsigned long eop)) +print_bpf_attr(const struct bpf_attr_check *check, unsigned long addr) { + if (check->print_fn) + check->print_fn(check, addr); + else + printf("%s", check->str); +} + +static void +test_bpf(const struct bpf_check *cmd_check) +{ + const struct bpf_attr_check *check = 0; + const union bpf_attr_data *data = 0; + unsigned int offset = 0; + /* zero addr */ - sys_bpf(cmd, 0, long_bits | sizeof(union bpf_attr_data)); + sys_bpf(cmd_check->cmd, 0, long_bits | sizeof(union bpf_attr_data)); printf("bpf(%s, NULL, %u) = %s\n", - cmd_str, sizeof_attr, errstr); + cmd_check->cmd_str, sizeof_attr, errstr); /* zero size */ unsigned long addr = end_of_page - sizeof_attr; - sys_bpf(cmd, addr, long_bits); + sys_bpf(cmd_check->cmd, addr, long_bits); printf("bpf(%s, %#lx, 0) = %s\n", - cmd_str, addr, errstr); + cmd_check->cmd_str, addr, errstr); - /* the first field only */ - unsigned int offset = init_first(end_of_page); - addr = end_of_page - offset; - sys_bpf(cmd, addr, offset); - printf("bpf(%s, {", cmd_str); - print_first(addr); - printf("}, %u) = %s\n", offset, errstr); + for (size_t i = 0; i < cmd_check->count; i++) { + check = &cmd_check->checks[i]; + if (check->init_fn) + check->init_fn((struct bpf_attr_check *) check); + data = &check->data; + offset = check->size; - /* efault after the first field */ - sys_bpf(cmd, addr, offset + 1); - printf("bpf(%s, %#lx, %u) = %s\n", - cmd_str, addr, offset + 1, errstr); + addr = end_of_page - offset; + memcpy((void *) addr, data, offset); - /* the relevant part of bpf_attr_data */ - offset = init_attr(end_of_page); - addr = end_of_page - offset; - sys_bpf(cmd, addr, offset); - printf("bpf(%s, {", cmd_str); - print_attr(addr); - printf("}, %u) = %s\n", offset, errstr); + /* starting piece of bpf_attr_data */ + sys_bpf(cmd_check->cmd, addr, offset); + printf("bpf(%s, {", cmd_check->cmd_str); + print_bpf_attr(check, addr); + printf("}, %u) = %s\n", offset, errstr); - /* short read of the relevant part of bpf_attr_data */ - sys_bpf(cmd, addr + 1, offset); - printf("bpf(%s, %#lx, %u) = %s\n", - cmd_str, addr + 1, offset, errstr); + /* short read of the starting piece */ + sys_bpf(cmd_check->cmd, addr + 1, offset); + printf("bpf(%s, %#lx, %u) = %s\n", + cmd_check->cmd_str, addr + 1, offset, errstr); + } if (offset < sizeof_attr) { /* short read of the whole bpf_attr_data */ - memmove((void *) end_of_page - sizeof_attr + 1, - (void *) addr, offset); + memcpy((void *) end_of_page - sizeof_attr + 1, data, offset); addr = end_of_page - sizeof_attr + 1; - memset((void *) addr + offset, 0, - sizeof_attr - offset - 1); - sys_bpf(cmd, addr, sizeof_attr); + memset((void *) addr + offset, 0, sizeof_attr - offset - 1); + sys_bpf(cmd_check->cmd, addr, sizeof_attr); printf("bpf(%s, %#lx, %u) = %s\n", - cmd_str, addr, sizeof_attr, errstr); + cmd_check->cmd_str, addr, sizeof_attr, errstr); /* the whole bpf_attr_data */ - memmove((void *) end_of_page - sizeof_attr, - (void *) addr, offset); + memcpy((void *) end_of_page - sizeof_attr, data, offset); addr = end_of_page - sizeof_attr; - memset((void *) addr + offset, 0, - sizeof_attr - offset); - sys_bpf(cmd, addr, sizeof_attr); - printf("bpf(%s, {", cmd_str); - print_attr(addr); + memset((void *) addr + offset, 0, sizeof_attr - offset); + sys_bpf(cmd_check->cmd, addr, sizeof_attr); + printf("bpf(%s, {", cmd_check->cmd_str); + print_bpf_attr(check, addr); printf("}, %u) = %s\n", sizeof_attr, errstr); /* non-zero bytes after the relevant part */ fill_memory_ex((void *) addr + offset, sizeof_attr - offset, '0', 10); - sys_bpf(cmd, addr, sizeof_attr); - printf("bpf(%s, {", cmd_str); - print_attr(addr); + sys_bpf(cmd_check->cmd, addr, sizeof_attr); + printf("bpf(%s, {", cmd_check->cmd_str); + print_bpf_attr(check, addr); printf(", "); print_extra_data((char *) addr, offset, sizeof_attr - offset); @@ -181,532 +198,379 @@ test_bpf_(kernel_ulong_t cmd, const char *cmd_str, } /* short read of the whole page */ - memmove((void *) end_of_page - page_size + 1, - (void *) addr, offset); + memcpy((void *) end_of_page - page_size + 1, data, offset); addr = end_of_page - page_size + 1; - memset((void *) addr + offset, 0, - page_size - offset - 1); - sys_bpf(cmd, addr, page_size); + memset((void *) addr + offset, 0, page_size - offset - 1); + sys_bpf(cmd_check->cmd, addr, page_size); printf("bpf(%s, %#lx, %u) = %s\n", - cmd_str, addr, page_size, errstr); + cmd_check->cmd_str, addr, page_size, errstr); /* the whole page */ - memmove((void *) end_of_page - page_size, - (void *) addr, offset); + memcpy((void *) end_of_page - page_size, data, offset); addr = end_of_page - page_size; memset((void *) addr + offset, 0, page_size - offset); - sys_bpf(cmd, addr, page_size); - printf("bpf(%s, {", cmd_str); - print_attr(addr); + sys_bpf(cmd_check->cmd, addr, page_size); + printf("bpf(%s, {", cmd_check->cmd_str); + print_bpf_attr(check, addr); printf("}, %u) = %s\n", page_size, errstr); /* non-zero bytes after the whole bpf_attr_data */ fill_memory_ex((void *) addr + offset, page_size - offset, '0', 10); - sys_bpf(cmd, addr, page_size); - printf("bpf(%s, {", cmd_str); - print_attr(addr); + sys_bpf(cmd_check->cmd, addr, page_size); + printf("bpf(%s, {", cmd_check->cmd_str); + print_bpf_attr(check, addr); printf(", "); print_extra_data((char *) addr, offset, page_size - offset); printf("}, %u) = %s\n", page_size, errstr); /* more than a page */ - sys_bpf(cmd, addr, page_size + 1); + sys_bpf(cmd_check->cmd, addr, page_size + 1); printf("bpf(%s, %#lx, %u) = %s\n", - cmd_str, addr, page_size + 1, errstr); + cmd_check->cmd_str, addr, page_size + 1, errstr); } -#define TEST_BPF(cmd_) \ - test_bpf_((cmd_), #cmd_, \ - init_ ## cmd_ ## _first, print_ ## cmd_ ## _first, \ - init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr) \ - /* End of TEST_BPF definition. */ +static const struct bpf_attr_check BPF_MAP_CREATE_checks[] = { + { + .data = { .BPF_MAP_CREATE_data = { .map_type = 2 } }, + .size = offsetofend(struct BPF_MAP_CREATE_struct, map_type), + .str = "map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0" + ", max_entries=0, map_flags=0, inner_map_fd=0" + }, + { + .data = { .BPF_MAP_CREATE_data = { + .map_type = 1, + .key_size = 4, + .value_size = 8, + .max_entries = 256, + .map_flags = 7, + .inner_map_fd = -1, + .numa_node = 42 + } }, + .size = offsetofend(struct BPF_MAP_CREATE_struct, numa_node), + .str = "map_type=BPF_MAP_TYPE_HASH, key_size=4" + ", value_size=8, max_entries=256" + ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU" + "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42" + } +}; -#define DEF_BPF_INIT_FIRST(cmd_, field_, value_) \ - static unsigned int \ - init_ ## cmd_ ## _first(const unsigned long eop) \ - { \ - static const struct cmd_ ## _struct attr = { \ - .field_ = value_ \ - }; \ - static const unsigned int offset = sizeof(attr.field_); \ - const unsigned long addr = eop - offset; \ - \ - memcpy((void *) addr, &attr.field_, offset); \ - return offset; \ - } \ - /* End of DEF_INIT_FIRST definition. */ +static const struct bpf_attr_check BPF_MAP_LOOKUP_ELEM_checks[] = { + { + .data = { .BPF_MAP_LOOKUP_ELEM_data = { .map_fd = -1 } }, + .size = offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, map_fd), + .str = "map_fd=-1, key=0, value=0" + }, + { + .data = { .BPF_MAP_LOOKUP_ELEM_data = { + .map_fd = -1, + .key = 0xdeadbeef, + .value = 0xbadc0ded + } }, + .size = offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, value), + .str = "map_fd=-1, key=0xdeadbeef, value=0xbadc0ded" + } +}; -DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2) +static const struct bpf_attr_check BPF_MAP_UPDATE_ELEM_checks[] = { + { + .data = { .BPF_MAP_UPDATE_ELEM_data = { .map_fd = -1 } }, + .size = offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, map_fd), + .str = "map_fd=-1, key=0, value=0, flags=BPF_ANY" + }, + { + .data = { .BPF_MAP_UPDATE_ELEM_data = { + .map_fd = -1, + .key = 0xdeadbeef, + .value = 0xbadc0ded, + .flags = 2 + } }, + .size = offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, flags), + .str = "map_fd=-1, key=0xdeadbeef, value=0xbadc0ded" + ", flags=BPF_EXIST" + } +}; -static void -print_BPF_MAP_CREATE_first(const unsigned long addr) -{ - printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0" - ", max_entries=0, map_flags=0, inner_map_fd=0"); -} +static const struct bpf_attr_check BPF_MAP_DELETE_ELEM_checks[] = { + { + .data = { .BPF_MAP_DELETE_ELEM_data = { .map_fd = -1 } }, + .size = offsetofend(struct BPF_MAP_DELETE_ELEM_struct, map_fd), + .str = "map_fd=-1, key=0" + }, + { + .data = { .BPF_MAP_DELETE_ELEM_data = { + .map_fd = -1, + .key = 0xdeadbeef + } }, + .size = offsetofend(struct BPF_MAP_DELETE_ELEM_struct, key), + .str = "map_fd=-1, key=0xdeadbeef" + } +}; -static unsigned int -init_BPF_MAP_CREATE_attr(const unsigned long eop) -{ - static const struct BPF_MAP_CREATE_struct attr = { - .map_type = 1, - .key_size = 4, - .value_size = 8, - .max_entries = 256, - .map_flags = 7, - .inner_map_fd = -1, - .numa_node = 42 - }; - static const unsigned int offset = - offsetofend(struct BPF_MAP_CREATE_struct, numa_node); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_MAP_CREATE_attr(const unsigned long addr) -{ - printf("map_type=BPF_MAP_TYPE_HASH, key_size=4" - ", value_size=8, max_entries=256" - ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU" - "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42"); -} - -DEF_BPF_INIT_FIRST(BPF_MAP_LOOKUP_ELEM, map_fd, -1) - -static void -print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr) -{ - printf("map_fd=-1, key=0, value=0"); -} - -static unsigned int -init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop) -{ - static const struct BPF_MAP_LOOKUP_ELEM_struct attr = { - .map_fd = -1, - .key = 0xdeadbeef, - .value = 0xbadc0ded - }; - static const unsigned int offset = - offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, value); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr) -{ - printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"); -} - -#define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first - -static void -print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr) -{ - printf("map_fd=-1, key=0, value=0, flags=BPF_ANY"); -} - -static unsigned int -init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop) -{ - static const struct BPF_MAP_UPDATE_ELEM_struct attr = { - .map_fd = -1, - .key = 0xdeadbeef, - .value = 0xbadc0ded, - .flags = 2 - }; - static const unsigned int offset = - offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, flags); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr) -{ - printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST"); -} - -#define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first - -static void -print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr) -{ - printf("map_fd=-1, key=0"); -} - -static unsigned int -init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop) -{ - static const struct BPF_MAP_DELETE_ELEM_struct attr = { - .map_fd = -1, - .key = 0xdeadbeef - }; - static const unsigned int offset = - offsetofend(struct BPF_MAP_DELETE_ELEM_struct, key); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr) -{ - printf("map_fd=-1, key=0xdeadbeef"); -} - -#define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first - -static void -print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr) -{ - printf("map_fd=-1, key=0, next_key=0"); -} - -static unsigned int -init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop) -{ - static const struct BPF_MAP_GET_NEXT_KEY_struct attr = { - .map_fd = -1, - .key = 0xdeadbeef, - .next_key = 0xbadc0ded - }; - static const unsigned int offset = - offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, next_key); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr) -{ - printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded"); -} - -DEF_BPF_INIT_FIRST(BPF_PROG_LOAD, prog_type, 1) - -static void -print_BPF_PROG_LOAD_first(const unsigned long addr) -{ - - printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0" - ", license=NULL"); -} +static const struct bpf_attr_check BPF_MAP_GET_NEXT_KEY_checks[] = { + { + .data = { .BPF_MAP_GET_NEXT_KEY_data = { .map_fd = -1 } }, + .size = offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, map_fd), + .str = "map_fd=-1, key=0, next_key=0" + }, + { + .data = { .BPF_MAP_GET_NEXT_KEY_data = { + .map_fd = -1, + .key = 0xdeadbeef, + .next_key = 0xbadc0ded + } }, + .size = offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, next_key), + .str = "map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded" + } +}; static const struct bpf_insn insns[] = { { .code = 0x95 } }; +static const char license[] = "GPL"; static char log_buf[4096]; +static const char pathname[] = "/sys/fs/bpf/foo/bar"; -static unsigned int -init_BPF_PROG_LOAD_attr(const unsigned long eop) +static void +init_BPF_PROG_LOAD_attr(struct bpf_attr_check *check) { - const struct BPF_PROG_LOAD_struct attr = { - .prog_type = 1, - .insn_cnt = ARRAY_SIZE(insns), - .insns = (uintptr_t) insns, - .license = (uintptr_t) "GPL", - .log_level = 42, - .log_size = sizeof(log_buf), - .log_buf = (uintptr_t) log_buf, - .kern_version = 0xcafef00d, - .prog_flags = 1 - }; - static const unsigned int offset = - offsetofend(struct BPF_PROG_LOAD_struct, prog_flags); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; + struct BPF_PROG_LOAD_struct *attr = &check->data.BPF_PROG_LOAD_data; + attr->insns = (uintptr_t) insns; + attr->license = (uintptr_t) license; + attr->log_buf = (uintptr_t) log_buf; } static void -print_BPF_PROG_LOAD_attr(const unsigned long addr) +print_BPF_PROG_LOAD_attr(const struct bpf_attr_check *check, unsigned long addr) { printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p" - ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p" + ", license=\"%s\", log_level=42, log_size=4096, log_buf=%p" ", kern_version=KERNEL_VERSION(51966, 240, 13)" ", prog_flags=BPF_F_STRICT_ALIGNMENT", (unsigned int) ARRAY_SIZE(insns), insns, - log_buf); + license, log_buf); } -DEF_BPF_INIT_FIRST(BPF_OBJ_PIN, pathname, 0) - -static void -print_BPF_OBJ_PIN_first(const unsigned long addr) -{ - - printf("pathname=NULL, bpf_fd=0"); -} - -static unsigned int -init_BPF_OBJ_PIN_attr(const unsigned long eop) -{ - const struct BPF_OBJ_PIN_struct attr = { - .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar", - .bpf_fd = -1 - }; - static const unsigned int offset = - offsetofend(struct BPF_OBJ_PIN_struct, bpf_fd); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_OBJ_PIN_attr(const unsigned long addr) -{ - printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1"); -} - -#define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first -#define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first -#define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr -#define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr - -DEF_BPF_INIT_FIRST(BPF_PROG_ATTACH, target_fd, -1) - -static void -print_BPF_PROG_ATTACH_first(const unsigned long addr) -{ - printf("target_fd=-1, attach_bpf_fd=0" - ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0"); -} - -static unsigned int -init_BPF_PROG_ATTACH_attr(const unsigned long eop) -{ - static const struct BPF_PROG_ATTACH_struct attr = { - .target_fd = -1, - .attach_bpf_fd = -2, - .attach_type = 2, - .attach_flags = 1 - }; - static const unsigned int offset = - offsetofend(struct BPF_PROG_ATTACH_struct, attach_flags); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - -static void -print_BPF_PROG_ATTACH_attr(const unsigned long addr) -{ - printf("target_fd=-1, attach_bpf_fd=-2" - ", attach_type=BPF_CGROUP_INET_SOCK_CREATE" - ", attach_flags=BPF_F_ALLOW_OVERRIDE"); -} - -#define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first - -static unsigned int -init_BPF_PROG_DETACH_attr(const unsigned long eop) -{ - static const struct BPF_PROG_DETACH_struct attr = { - .target_fd = -1, - .attach_type = 2 - }; - static const unsigned int offset = - offsetofend(struct BPF_PROG_DETACH_struct, attach_type); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &attr, offset); - return offset; -} - - -static void -print_BPF_PROG_DETACH_first(const unsigned long addr) -{ - printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS"); -} - -static void -print_BPF_PROG_DETACH_attr(const unsigned long addr) -{ - printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE"); -} - -DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, prog_fd, -1) - -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 struct BPF_PROG_TEST_RUN_struct sample_BPF_PROG_TEST_RUN_attr = { - .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 struct bpf_attr_check BPF_PROG_LOAD_checks[] = { + { + .data = { .BPF_PROG_LOAD_data = { .prog_type = 1 } }, + .size = offsetofend(struct BPF_PROG_LOAD_struct, prog_type), + .str = "prog_type=BPF_PROG_TYPE_SOCKET_FILTER" + ", insn_cnt=0, insns=0, license=NULL" + }, + { + .data = { .BPF_PROG_LOAD_data = { + .prog_type = 1, + .insn_cnt = ARRAY_SIZE(insns), + .log_level = 42, + .log_size = sizeof(log_buf), + .kern_version = 0xcafef00d, + .prog_flags = 1 + } }, + .size = offsetofend(struct BPF_PROG_LOAD_struct, prog_flags), + .init_fn = init_BPF_PROG_LOAD_attr, + .print_fn = print_BPF_PROG_LOAD_attr + } }; -static unsigned int -init_BPF_PROG_TEST_RUN_attr(const unsigned long eop) -{ - static const unsigned int offset = - offsetofend(struct BPF_PROG_TEST_RUN_struct, duration); - 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) +init_BPF_OBJ_PIN_attr(struct bpf_attr_check *check) { - PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr, prog_fd); - PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, retval); - PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, data_size_in); - PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, data_size_out); - PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr, data_in); - PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr, data_out); - PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, repeat); - PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, duration); - printf("}"); + struct BPF_OBJ_PIN_struct *attr = &check->data.BPF_OBJ_PIN_data; + attr->pathname = (uintptr_t) pathname; } -DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef) +static struct bpf_attr_check BPF_OBJ_PIN_checks[] = { + { + .data = { .BPF_OBJ_PIN_data = { .pathname = 0 } }, + .size = offsetofend(struct BPF_OBJ_PIN_struct, pathname), + .str = "pathname=NULL, bpf_fd=0" + }, + { + .data = { .BPF_OBJ_PIN_data = { .bpf_fd = -1 } }, + .size = offsetofend(struct BPF_OBJ_PIN_struct, bpf_fd), + .init_fn = init_BPF_OBJ_PIN_attr, + .str = "pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1" + } +}; -static void -print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr) -{ - printf("start_id=%u, next_id=0", 0xdeadbeef); -} +#define BPF_OBJ_GET_checks BPF_OBJ_PIN_checks -static unsigned int -init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop) -{ - static const struct BPF_PROG_GET_NEXT_ID_struct attr = { - .start_id = 0xbadc0ded, - .next_id = 0xcafef00d - }; - static const unsigned int offset = - offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, next_id); - const unsigned long addr = eop - offset; +static const struct bpf_attr_check BPF_PROG_ATTACH_checks[] = { + { + .data = { .BPF_PROG_ATTACH_data = { .target_fd = -1 } }, + .size = offsetofend(struct BPF_PROG_ATTACH_struct, target_fd), + .str = "target_fd=-1, attach_bpf_fd=0" + ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0" + }, + { + .data = { .BPF_PROG_ATTACH_data = { + .target_fd = -1, + .attach_bpf_fd = -2, + .attach_type = 2, + .attach_flags = 1 + } }, + .size = offsetofend(struct BPF_PROG_ATTACH_struct, attach_flags), + .str = "target_fd=-1, attach_bpf_fd=-2" + ", attach_type=BPF_CGROUP_INET_SOCK_CREATE" + ", attach_flags=BPF_F_ALLOW_OVERRIDE" + } +}; - memcpy((void *) addr, &attr, offset); - return offset; -} -static void -print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr) -{ - printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); -} +static const struct bpf_attr_check BPF_PROG_DETACH_checks[] = { + { + .data = { .BPF_PROG_DETACH_data = { .target_fd = -1 } }, + .size = offsetofend(struct BPF_PROG_DETACH_struct, target_fd), + .str = "target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS" + }, + { + .data = { .BPF_PROG_DETACH_data = { + .target_fd = -1, + .attach_type = 2 + } }, + .size = offsetofend(struct BPF_PROG_DETACH_struct, attach_type), + .str = "target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE" + } +}; -#define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first -#define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first -#define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr -#define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr +static const struct bpf_attr_check BPF_PROG_TEST_RUN_checks[] = { + { + .data = { .BPF_PROG_TEST_RUN_data = { .prog_fd = -1 } }, + .size = offsetofend(struct BPF_PROG_TEST_RUN_struct, prog_fd), + .str = "test={prog_fd=-1, retval=0, data_size_in=0" + ", data_size_out=0, data_in=0, data_out=0" + ", repeat=0, duration=0}" + }, + { + .data = { .BPF_PROG_TEST_RUN_data = { + .prog_fd = -1, + .retval = 0xfac1fed2, + .data_size_in = 0xfac3fed4, + .data_size_out = 0xfac5fed6, + .data_in = (uint64_t) 0xfacef11dbadc2dedULL, + .data_out = (uint64_t) 0xfacef33dbadc4dedULL, + .repeat = 0xfac7fed8, + .duration = 0xfac9feda + } }, + .size = offsetofend(struct BPF_PROG_TEST_RUN_struct, duration), + .str = "test={prog_fd=-1, retval=4207017682" + ", data_size_in=4207148756, data_size_out=4207279830" + ", data_in=0xfacef11dbadc2ded" + ", data_out=0xfacef33dbadc4ded" + ", repeat=4207410904, duration=4207541978}" + } +}; -#define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first -#define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr +static const struct bpf_attr_check BPF_PROG_GET_NEXT_ID_checks[] = { + { + .data = { .BPF_PROG_GET_NEXT_ID_data = { + .start_id = 0xdeadbeef + } }, + .size = offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, start_id), + .str = "start_id=3735928559, next_id=0" + }, + { + .data = { .BPF_PROG_GET_NEXT_ID_data = { + .start_id = 0xbadc0ded, + .next_id = 0xcafef00d + } }, + .size = offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, next_id), + .str = "start_id=3134983661, next_id=3405705229" + } +}; -static void -print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr) -{ - printf("prog_id=%u, next_id=0", 0xdeadbeef); -} +#define BPF_MAP_GET_NEXT_ID_checks BPF_PROG_GET_NEXT_ID_checks -static void -print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr) -{ - printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); -} +static const struct bpf_attr_check BPF_PROG_GET_FD_BY_ID_checks[] = { + { + .data = { .BPF_PROG_GET_FD_BY_ID_data = { + .prog_id = 0xdeadbeef + } }, + .size = offsetofend(struct BPF_PROG_GET_FD_BY_ID_struct, prog_id), + .str = "prog_id=3735928559, next_id=0" + }, + { + .data = { .BPF_PROG_GET_FD_BY_ID_data = { + .prog_id = 0xbadc0ded, + .next_id = 0xcafef00d + } }, + .size = offsetofend(struct BPF_PROG_GET_FD_BY_ID_struct, next_id), + .str = "prog_id=3134983661, next_id=3405705229" + } +}; -#define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first -#define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr +static const struct bpf_attr_check BPF_MAP_GET_FD_BY_ID_checks[] = { + { + .data = { .BPF_MAP_GET_FD_BY_ID_data = { + .map_id = 0xdeadbeef + } }, + .size = offsetofend(struct BPF_MAP_GET_FD_BY_ID_struct, map_id), + .str = "map_id=3735928559, next_id=0" + }, + { + .data = { .BPF_MAP_GET_FD_BY_ID_data = { + .map_id = 0xbadc0ded, + .next_id = 0xcafef00d + } }, + .size = offsetofend(struct BPF_MAP_GET_FD_BY_ID_struct, next_id), + .str = "map_id=3134983661, next_id=3405705229" + } +}; -static void -print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr) -{ - printf("map_id=%u, next_id=0", 0xdeadbeef); -} +static const struct bpf_attr_check BPF_OBJ_GET_INFO_BY_FD_checks[] = { + { + .data = { .BPF_OBJ_GET_INFO_BY_FD_data = { .bpf_fd = -1 } }, + .size = offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, bpf_fd), + .str = "info={bpf_fd=-1, info_len=0, info=0}" + }, + { + .data = { .BPF_OBJ_GET_INFO_BY_FD_data = { + .bpf_fd = -1, + .info_len = 0xdeadbeef, + .info = (uint64_t) 0xfacefeedbadc0dedULL + } }, + .size = offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, info), + .str = "info={bpf_fd=-1, info_len=3735928559" + ", info=0xfacefeedbadc0ded}" + } +}; -static void -print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr) -{ - printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); -} - -DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, bpf_fd, -1) - -static void -print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr) -{ - printf("info={bpf_fd=-1, info_len=0, info=0}"); -} - -static const struct BPF_OBJ_GET_INFO_BY_FD_struct - sample_BPF_OBJ_GET_INFO_BY_FD_attr = { - .bpf_fd = -1, - .info_len = 0xdeadbeef, - .info = (uint64_t) 0xfacefeedbadc0ded - }; -static unsigned int -init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop) -{ - static const unsigned int offset = - offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, info); - const unsigned long addr = eop - offset; - - memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset); - return offset; -} - -static void -print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr) -{ - PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr, bpf_fd); - PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr, info_len); - PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr, info); - printf("}"); -} +#define CHK(cmd_) \ + { \ + cmd_, #cmd_, \ + cmd_##_checks, ARRAY_SIZE(cmd_##_checks), \ + } \ + /* End of CHK definition */ int main(void) { + static const struct bpf_check checks[] = { + CHK(BPF_MAP_CREATE), + CHK(BPF_MAP_LOOKUP_ELEM), + CHK(BPF_MAP_UPDATE_ELEM), + CHK(BPF_MAP_DELETE_ELEM), + CHK(BPF_MAP_GET_NEXT_KEY), + CHK(BPF_PROG_LOAD), + CHK(BPF_OBJ_PIN), + CHK(BPF_OBJ_GET), + CHK(BPF_PROG_ATTACH), + CHK(BPF_PROG_DETACH), + CHK(BPF_PROG_TEST_RUN), + CHK(BPF_PROG_GET_NEXT_ID), + CHK(BPF_MAP_GET_NEXT_ID), + CHK(BPF_PROG_GET_FD_BY_ID), + CHK(BPF_MAP_GET_FD_BY_ID), + CHK(BPF_OBJ_GET_INFO_BY_FD), + }; + page_size = get_page_size(); end_of_page = (unsigned long) tail_alloc(1) + 1; - TEST_BPF(BPF_MAP_CREATE); - TEST_BPF(BPF_MAP_LOOKUP_ELEM); - TEST_BPF(BPF_MAP_UPDATE_ELEM); - TEST_BPF(BPF_MAP_DELETE_ELEM); - TEST_BPF(BPF_MAP_GET_NEXT_KEY); - TEST_BPF(BPF_PROG_LOAD); - TEST_BPF(BPF_OBJ_PIN); - TEST_BPF(BPF_OBJ_GET); - TEST_BPF(BPF_PROG_ATTACH); - TEST_BPF(BPF_PROG_DETACH); - TEST_BPF(BPF_PROG_TEST_RUN); - TEST_BPF(BPF_PROG_GET_NEXT_ID); - TEST_BPF(BPF_MAP_GET_NEXT_ID); - TEST_BPF(BPF_PROG_GET_FD_BY_ID); - TEST_BPF(BPF_MAP_GET_FD_BY_ID); - TEST_BPF(BPF_OBJ_GET_INFO_BY_FD); + for (size_t i = 0; i < ARRAY_SIZE(checks); i++) + test_bpf(checks + i); sys_bpf(0xfacefeed, 0, (kernel_ulong_t) 0xfacefeedbadc0dedULL); printf("bpf(0xfacefeed /* BPF_??? */, NULL, %u) = %s\n",