* [LTP] [PATCH v4 0/4] Basic eBPF tests
@ 2019-08-26 11:10 Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 1/4] BPF: Essential headers for map creation Cyril Hrubis
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:10 UTC (permalink / raw)
To: ltp
I've ended up playing with the patchset and fixed a few loose ends on
the map test and as I had the code at hand I decided to send v4 instead
of pointing out the mistakes in a review.
There were numerous small changes for the map test:
* Make sure the key buffer is sized exactly for the content
* Initialized the array/hash element value in test setup
* Made the code flow a bit more obvious, it was hard to tell which
part was run for n == 0 and which for n == 1
Also it looks that for me the test that loads the eBPF program ends up
with EPERM randomly at about 10th iteration both as unpriviledged and
priviledged user, which is really strange.
Richard Palethorpe (4):
BPF: Essential headers for map creation
BPF: Sanity check creating and updating maps
BPF: Essential headers for a basic program
BPF: Sanity check creating a program
include/lapi/bpf.h | 526 +++++++++++++++++++++
include/lapi/socket.h | 4 +
include/lapi/syscalls/aarch64.in | 1 +
include/lapi/syscalls/i386.in | 1 +
include/lapi/syscalls/s390.in | 1 +
include/lapi/syscalls/sparc.in | 1 +
include/lapi/syscalls/x86_64.in | 1 +
runtest/syscalls | 3 +
testcases/kernel/syscalls/bpf/.gitignore | 2 +
testcases/kernel/syscalls/bpf/Makefile | 10 +
testcases/kernel/syscalls/bpf/bpf_map01.c | 158 +++++++
testcases/kernel/syscalls/bpf/bpf_prog01.c | 162 +++++++
12 files changed, 870 insertions(+)
create mode 100644 include/lapi/bpf.h
create mode 100644 testcases/kernel/syscalls/bpf/.gitignore
create mode 100644 testcases/kernel/syscalls/bpf/Makefile
create mode 100644 testcases/kernel/syscalls/bpf/bpf_map01.c
create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c
--
2.21.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 1/4] BPF: Essential headers for map creation
2019-08-26 11:10 [LTP] [PATCH v4 0/4] Basic eBPF tests Cyril Hrubis
@ 2019-08-26 11:10 ` Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps Cyril Hrubis
` (3 subsequent siblings)
4 siblings, 0 replies; 17+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:10 UTC (permalink / raw)
To: ltp
From: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
Acked-by: Cyril Hrubis <chrubis@suse.cz>
---
include/lapi/bpf.h | 242 +++++++++++++++++++++++++++++++
include/lapi/syscalls/aarch64.in | 1 +
include/lapi/syscalls/i386.in | 1 +
include/lapi/syscalls/s390.in | 1 +
include/lapi/syscalls/sparc.in | 1 +
include/lapi/syscalls/x86_64.in | 1 +
6 files changed, 247 insertions(+)
create mode 100644 include/lapi/bpf.h
diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h
new file mode 100644
index 000000000..369de0175
--- /dev/null
+++ b/include/lapi/bpf.h
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Essential Extended Berkeley Packet Filter (eBPF) headers
+ *
+ * Mostly copied/adapted from linux/bpf.h and libbpf so that we can perform
+ * some eBPF testing without any external dependencies.
+ */
+
+#ifndef BPF_H
+# define BPF_H
+
+#include <stdint.h>
+
+#include "lapi/syscalls.h"
+
+/* Start copy from linux/bpf.h */
+enum bpf_cmd {
+ BPF_MAP_CREATE,
+ BPF_MAP_LOOKUP_ELEM,
+ BPF_MAP_UPDATE_ELEM,
+ BPF_MAP_DELETE_ELEM,
+ BPF_MAP_GET_NEXT_KEY,
+ BPF_PROG_LOAD,
+ BPF_OBJ_PIN,
+ BPF_OBJ_GET,
+ BPF_PROG_ATTACH,
+ BPF_PROG_DETACH,
+ BPF_PROG_TEST_RUN,
+ BPF_PROG_GET_NEXT_ID,
+ BPF_MAP_GET_NEXT_ID,
+ BPF_PROG_GET_FD_BY_ID,
+ BPF_MAP_GET_FD_BY_ID,
+ BPF_OBJ_GET_INFO_BY_FD,
+ BPF_PROG_QUERY,
+ BPF_RAW_TRACEPOINT_OPEN,
+ BPF_BTF_LOAD,
+ BPF_BTF_GET_FD_BY_ID,
+ BPF_TASK_FD_QUERY,
+ BPF_MAP_LOOKUP_AND_DELETE_ELEM,
+ BPF_MAP_FREEZE,
+};
+
+enum bpf_map_type {
+ BPF_MAP_TYPE_UNSPEC,
+ BPF_MAP_TYPE_HASH,
+ BPF_MAP_TYPE_ARRAY,
+ BPF_MAP_TYPE_PROG_ARRAY,
+ BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+ BPF_MAP_TYPE_PERCPU_HASH,
+ BPF_MAP_TYPE_PERCPU_ARRAY,
+ BPF_MAP_TYPE_STACK_TRACE,
+ BPF_MAP_TYPE_CGROUP_ARRAY,
+ BPF_MAP_TYPE_LRU_HASH,
+ BPF_MAP_TYPE_LRU_PERCPU_HASH,
+ BPF_MAP_TYPE_LPM_TRIE,
+ BPF_MAP_TYPE_ARRAY_OF_MAPS,
+ BPF_MAP_TYPE_HASH_OF_MAPS,
+ BPF_MAP_TYPE_DEVMAP,
+ BPF_MAP_TYPE_SOCKMAP,
+ BPF_MAP_TYPE_CPUMAP,
+ BPF_MAP_TYPE_XSKMAP,
+ BPF_MAP_TYPE_SOCKHASH,
+ BPF_MAP_TYPE_CGROUP_STORAGE,
+ BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
+ BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
+ BPF_MAP_TYPE_QUEUE,
+ BPF_MAP_TYPE_STACK,
+ BPF_MAP_TYPE_SK_STORAGE,
+};
+
+#define BPF_OBJ_NAME_LEN 16U
+
+#define BPF_ANY 0 /* create new element or update existing */
+#define BPF_NOEXIST 1 /* create new element if it didn't exist */
+#define BPF_EXIST 2 /* update existing element */
+#define BPF_F_LOCK 4 /* spin_lock-ed map_lookup/map_update */
+
+#define aligned_uint64_t uint64_t __attribute__((aligned(8)))
+
+union bpf_attr {
+ struct { /* anonymous struct used by BPF_MAP_CREATE command */
+ uint32_t map_type; /* one of enum bpf_map_type */
+ uint32_t key_size; /* size of key in bytes */
+ uint32_t value_size; /* size of value in bytes */
+ uint32_t max_entries; /* max number of entries in a map */
+ uint32_t map_flags; /* BPF_MAP_CREATE related
+ * flags defined above.
+ */
+ uint32_t inner_map_fd; /* fd pointing to the inner map */
+ uint32_t numa_node; /* numa node (effective only if
+ * BPF_F_NUMA_NODE is set).
+ */
+ char map_name[BPF_OBJ_NAME_LEN];
+ uint32_t map_ifindex; /* ifindex of netdev to create on */
+ uint32_t btf_fd; /* fd pointing to a BTF type data */
+ uint32_t btf_key_type_id; /* BTF type_id of the key */
+ uint32_t btf_value_type_id; /* BTF type_id of the value */
+ };
+
+ struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
+ uint32_t map_fd;
+ aligned_uint64_t key;
+ union {
+ aligned_uint64_t value;
+ aligned_uint64_t next_key;
+ };
+ uint64_t flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_LOAD command */
+ uint32_t prog_type; /* one of enum bpf_prog_type */
+ uint32_t insn_cnt;
+ aligned_uint64_t insns;
+ aligned_uint64_t license;
+ uint32_t log_level; /* verbosity level of verifier */
+ uint32_t log_size; /* size of user buffer */
+ aligned_uint64_t log_buf; /* user supplied buffer */
+ uint32_t kern_version; /* not used */
+ uint32_t prog_flags;
+ char prog_name[BPF_OBJ_NAME_LEN];
+ uint32_t prog_ifindex; /* ifindex of netdev to prep for */
+ /* For some prog types expected attach type must be known at
+ * load time to verify attach type specific parts of prog
+ * (context accesses, allowed helpers, etc).
+ */
+ uint32_t expected_attach_type;
+ uint32_t prog_btf_fd; /* fd pointing to BTF type data */
+ uint32_t func_info_rec_size; /* userspace bpf_func_info size */
+ aligned_uint64_t func_info; /* func info */
+ uint32_t func_info_cnt; /* number of bpf_func_info records */
+ uint32_t line_info_rec_size; /* userspace bpf_line_info size */
+ aligned_uint64_t line_info; /* line info */
+ uint32_t line_info_cnt; /* number of bpf_line_info records */
+ };
+
+ struct { /* anonymous struct used by BPF_OBJ_* commands */
+ aligned_uint64_t pathname;
+ uint32_t bpf_fd;
+ uint32_t file_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
+ uint32_t target_fd; /* container object to attach to */
+ uint32_t attach_bpf_fd; /* eBPF program to attach */
+ uint32_t attach_type;
+ uint32_t attach_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
+ uint32_t prog_fd;
+ uint32_t retval;
+ uint32_t data_size_in; /* input: len of data_in */
+ uint32_t data_size_out; /* input/output: len of data_out
+ * returns ENOSPC if data_out
+ * is too small.
+ */
+ aligned_uint64_t data_in;
+ aligned_uint64_t data_out;
+ uint32_t repeat;
+ uint32_t duration;
+ uint32_t ctx_size_in; /* input: len of ctx_in */
+ uint32_t ctx_size_out; /* input/output: len of ctx_out
+ * returns ENOSPC if ctx_out
+ * is too small.
+ */
+ aligned_uint64_t ctx_in;
+ aligned_uint64_t ctx_out;
+ } test;
+
+ struct { /* anonymous struct used by BPF_*_GET_*_ID */
+ union {
+ uint32_t start_id;
+ uint32_t prog_id;
+ uint32_t map_id;
+ uint32_t btf_id;
+ };
+ uint32_t next_id;
+ uint32_t open_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
+ uint32_t bpf_fd;
+ uint32_t info_len;
+ aligned_uint64_t info;
+ } info;
+
+ struct { /* anonymous struct used by BPF_PROG_QUERY command */
+ uint32_t target_fd; /* container object to query */
+ uint32_t attach_type;
+ uint32_t query_flags;
+ uint32_t attach_flags;
+ aligned_uint64_t prog_ids;
+ uint32_t prog_cnt;
+ } query;
+
+ struct {
+ uint64_t name;
+ uint32_t prog_fd;
+ } raw_tracepoint;
+
+ struct { /* anonymous struct for BPF_BTF_LOAD */
+ aligned_uint64_t btf;
+ aligned_uint64_t btf_log_buf;
+ uint32_t btf_size;
+ uint32_t btf_log_size;
+ uint32_t btf_log_level;
+ };
+
+ struct {
+ uint32_t pid; /* input: pid */
+ uint32_t fd; /* input: fd */
+ uint32_t flags; /* input: flags */
+ uint32_t buf_len; /* input/output: buf len */
+ aligned_uint64_t buf; /* input/output:
+ * tp_name for tracepoint
+ * symbol for kprobe
+ * filename for uprobe
+ */
+ uint32_t prog_id; /* output: prod_id */
+ uint32_t fd_type; /* output: BPF_FD_TYPE_* */
+ uint64_t probe_offset; /* output: probe_offset */
+ uint64_t probe_addr; /* output: probe_addr */
+ } task_fd_query;
+} __attribute__((aligned(8)));
+
+/* End copy from linux/bpf.h */
+
+/* Start copy from tools/lib/bpf */
+inline uint64_t ptr_to_u64(const void *ptr)
+{
+ return (uint64_t) (unsigned long) ptr;
+}
+
+inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size)
+{
+ return tst_syscall(__NR_bpf, cmd, attr, size);
+}
+/* End copy from tools/lib/bpf */
+
+#endif /* BPF_H */
diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in
index 7db6e281c..0e00641bc 100644
--- a/include/lapi/syscalls/aarch64.in
+++ b/include/lapi/syscalls/aarch64.in
@@ -258,6 +258,7 @@ process_vm_writev 271
kcmp 272
getrandom 278
memfd_create 279
+bpf 280
userfaultfd 282
membarrier 283
execveat 281
diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
index 02f3955ba..87ab46933 100644
--- a/include/lapi/syscalls/i386.in
+++ b/include/lapi/syscalls/i386.in
@@ -340,6 +340,7 @@ sched_getattr 352
renameat2 354
getrandom 355
memfd_create 356
+bpf 357
execveat 358
userfaultfd 374
membarrier 375
diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
index c304ef4b7..d3f7eb1f6 100644
--- a/include/lapi/syscalls/s390.in
+++ b/include/lapi/syscalls/s390.in
@@ -331,6 +331,7 @@ sched_getattr 346
renameat2 347
getrandom 349
memfd_create 350
+bpf 351
userfaultfd 355
membarrier 356
execveat 354
diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
index ab7204663..94a672428 100644
--- a/include/lapi/syscalls/sparc.in
+++ b/include/lapi/syscalls/sparc.in
@@ -336,6 +336,7 @@ kcmp 341
renameat2 345
getrandom 347
memfd_create 348
+bpf 349
membarrier 351
userfaultfd 352
execveat 350
diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
index fdb414c10..b1cbd4f2f 100644
--- a/include/lapi/syscalls/x86_64.in
+++ b/include/lapi/syscalls/x86_64.in
@@ -307,6 +307,7 @@ sched_getattr 315
renameat2 316
getrandom 318
memfd_create 319
+bpf 321
execveat 322
userfaultfd 323
membarrier 324
--
2.21.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps
2019-08-26 11:10 [LTP] [PATCH v4 0/4] Basic eBPF tests Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 1/4] BPF: Essential headers for map creation Cyril Hrubis
@ 2019-08-26 11:10 ` Cyril Hrubis
2019-08-26 12:52 ` Jan Stancek
2019-08-26 11:10 ` [LTP] [PATCH v4 3/4] BPF: Essential headers for a basic program Cyril Hrubis
` (2 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:10 UTC (permalink / raw)
To: ltp
From: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
runtest/syscalls | 2 +
testcases/kernel/syscalls/bpf/.gitignore | 1 +
testcases/kernel/syscalls/bpf/Makefile | 10 ++
testcases/kernel/syscalls/bpf/bpf_map01.c | 158 ++++++++++++++++++++++
4 files changed, 171 insertions(+)
create mode 100644 testcases/kernel/syscalls/bpf/.gitignore
create mode 100644 testcases/kernel/syscalls/bpf/Makefile
create mode 100644 testcases/kernel/syscalls/bpf/bpf_map01.c
diff --git a/runtest/syscalls b/runtest/syscalls
index c41ba2a0d..6ddfc2178 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -32,6 +32,8 @@ bind01 bind01
bind02 bind02
bind03 bind03
+bpf_map01 bpf_map01
+
brk01 brk01
capget01 capget01
diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore
new file mode 100644
index 000000000..f33532484
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/.gitignore
@@ -0,0 +1 @@
+bpf_map01
diff --git a/testcases/kernel/syscalls/bpf/Makefile b/testcases/kernel/syscalls/bpf/Makefile
new file mode 100644
index 000000000..990c8c83c
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2019 Linux Test Project
+
+top_srcdir ?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+CFLAGS += -D_GNU_SOURCE
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/bpf/bpf_map01.c b/testcases/kernel/syscalls/bpf/bpf_map01.c
new file mode 100644
index 000000000..597a98417
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/bpf_map01.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Trivial Extended Berkeley Packet Filter (eBPF) test.
+ *
+ * Sanity check creating and updating maps.
+ */
+
+#include <limits.h>
+#include <string.h>
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/bpf.h"
+
+#define VAL_SZ 1024
+
+static void *key4;
+static void *key8;
+static char *val_set;
+static char *val_get;
+static union bpf_attr *attr;
+
+struct map_type {
+ uint32_t id;
+ char *name;
+ int key_size;
+ void **key;
+};
+
+static const struct map_type map_types[] = {
+ {BPF_MAP_TYPE_HASH, "hash", 8, &key8},
+ {BPF_MAP_TYPE_ARRAY, "array", 4, &key4}
+};
+
+void run(unsigned int n)
+{
+ int fd, i;
+ void *key = *map_types[n].key;
+
+ memset(attr, 0, sizeof(*attr));
+ attr->map_type = map_types[n].id;
+ attr->key_size = map_types[n].key_size;
+ attr->value_size = VAL_SZ;
+ attr->max_entries = 1;
+
+ TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)));
+ if (TST_RET == -1) {
+ if (TST_ERR == EPERM) {
+ tst_brk(TCONF | TTERRNO,
+ "bpf() requires CAP_SYS_ADMIN on this system");
+ } else {
+ tst_res(TFAIL | TTERRNO, "Failed to create %s map",
+ map_types[n].name);
+ return;
+ }
+ }
+ tst_res(TPASS, "Created %s map", map_types[n].name);
+ fd = TST_RET;
+
+ memset(attr, 0, sizeof(*attr));
+ attr->map_fd = fd;
+ attr->key = ptr_to_u64(key);
+ attr->value = ptr_to_u64(val_get);
+
+ TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
+
+ switch (n) {
+ case 0:
+ if (TST_RET != -1 || TST_ERR != ENOENT) {
+ tst_res(TFAIL | TTERRNO,
+ "Empty hash map lookup should fail with ENOENT");
+ } else {
+ tst_res(TPASS | TTERRNO, "Empty hash map lookup");
+ }
+ break;
+ case 1:
+ if (TST_RET != -1) {
+ for (i = 0;;) {
+ if (val_get[i] != 0) {
+ tst_res(TFAIL,
+ "Preallocated array map val not zero");
+ } else if (++i >= VAL_SZ) {
+ tst_res(TPASS,
+ "Preallocated array map lookup");
+ break;
+ }
+ }
+ } else {
+ tst_res(TFAIL | TERRNO, "Prellocated array map lookup");
+ }
+ break;
+ }
+
+ memset(attr, 0, sizeof(*attr));
+ attr->map_fd = fd;
+ attr->key = ptr_to_u64(key);
+ attr->value = ptr_to_u64(val_set);
+ attr->flags = BPF_ANY;
+
+ TEST(bpf(BPF_MAP_UPDATE_ELEM, attr, sizeof(*attr)));
+ if (TST_RET == -1) {
+ tst_brk(TFAIL | TTERRNO,
+ "Update %s map element",
+ map_types[n].name);
+ } else {
+ tst_res(TPASS,
+ "Update %s map element",
+ map_types[n].name);
+ }
+
+ memset(attr, 0, sizeof(*attr));
+ attr->map_fd = fd;
+ attr->key = ptr_to_u64(key);
+ attr->value = ptr_to_u64(val_get);
+
+ TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
+ if (TST_RET == -1) {
+ tst_res(TFAIL | TTERRNO,
+ "%s map lookup missing",
+ map_types[n].name);
+ } else if (memcmp(val_set, val_get, (size_t) VAL_SZ)) {
+ tst_res(TFAIL,
+ "%s map lookup returned different value",
+ map_types[n].name);
+ } else {
+ tst_res(TPASS, "%s map lookup", map_types[n].name);
+ }
+
+ SAFE_CLOSE(fd);
+}
+
+static void setup(void)
+{
+ unsigned int i;
+
+ memcpy(key8, "12345678", 8);
+ memset(key4, 0, 4);
+
+ for (i = 0; i < VAL_SZ; i++)
+ val_set[i] = i % 256;
+}
+
+static struct tst_test test = {
+ .tcnt = 2,
+ .test = run,
+ .setup = setup,
+ .min_kver = "3.18",
+ .bufs = (struct tst_buffers []) {
+ {&key4, .size = 4},
+ {&key8, .size = 8},
+ {&val_set, .size = VAL_SZ},
+ {&val_get, .size = VAL_SZ},
+ {&attr, .size = sizeof(*attr)},
+ {},
+ },
+};
--
2.21.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 3/4] BPF: Essential headers for a basic program
2019-08-26 11:10 [LTP] [PATCH v4 0/4] Basic eBPF tests Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 1/4] BPF: Essential headers for map creation Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps Cyril Hrubis
@ 2019-08-26 11:10 ` Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program Cyril Hrubis
2019-08-26 14:29 ` [LTP] [PATCH v4 0/4] Basic eBPF tests Jan Stancek
4 siblings, 0 replies; 17+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:10 UTC (permalink / raw)
To: ltp
From: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
Acked-by: Cyril Hrubis <chrubis@suse.cz>
---
include/lapi/bpf.h | 286 +++++++++++++++++++++++++++++++++++++++++-
include/lapi/socket.h | 4 +
2 files changed, 289 insertions(+), 1 deletion(-)
diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h
index 369de0175..122eb5469 100644
--- a/include/lapi/bpf.h
+++ b/include/lapi/bpf.h
@@ -15,7 +15,57 @@
#include "lapi/syscalls.h"
-/* Start copy from linux/bpf.h */
+/* Start copy from linux/bpf_(common).h */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_ST 0x02
+#define BPF_JMP 0x05
+
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_DW 0x18 /* double word (64-bit) */
+
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_MEM 0x60
+
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+
+#define BPF_JEQ 0x10
+
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+#define BPF_ALU64 0x07 /* alu mode in double word width */
+#define BPF_MOV 0xb0 /* mov reg to reg */
+#define BPF_CALL 0x80 /* function call */
+#define BPF_EXIT 0x90 /* function return */
+
+/* Register numbers */
+enum {
+ BPF_REG_0 = 0,
+ BPF_REG_1,
+ BPF_REG_2,
+ BPF_REG_3,
+ BPF_REG_4,
+ BPF_REG_5,
+ BPF_REG_6,
+ BPF_REG_7,
+ BPF_REG_8,
+ BPF_REG_9,
+ BPF_REG_10,
+ MAX_BPF_REG,
+};
+
+struct bpf_insn {
+ uint8_t code; /* opcode */
+ uint8_t dst_reg:4; /* dest register */
+ uint8_t src_reg:4; /* source register */
+ int16_t off; /* signed offset */
+ int32_t imm; /* signed immediate constant */
+};
+
enum bpf_cmd {
BPF_MAP_CREATE,
BPF_MAP_LOOKUP_ELEM,
@@ -70,6 +120,37 @@ enum bpf_map_type {
BPF_MAP_TYPE_SK_STORAGE,
};
+enum bpf_prog_type {
+ BPF_PROG_TYPE_UNSPEC,
+ BPF_PROG_TYPE_SOCKET_FILTER,
+ BPF_PROG_TYPE_KPROBE,
+ BPF_PROG_TYPE_SCHED_CLS,
+ BPF_PROG_TYPE_SCHED_ACT,
+ BPF_PROG_TYPE_TRACEPOINT,
+ BPF_PROG_TYPE_XDP,
+ BPF_PROG_TYPE_PERF_EVENT,
+ BPF_PROG_TYPE_CGROUP_SKB,
+ BPF_PROG_TYPE_CGROUP_SOCK,
+ BPF_PROG_TYPE_LWT_IN,
+ BPF_PROG_TYPE_LWT_OUT,
+ BPF_PROG_TYPE_LWT_XMIT,
+ BPF_PROG_TYPE_SOCK_OPS,
+ BPF_PROG_TYPE_SK_SKB,
+ BPF_PROG_TYPE_CGROUP_DEVICE,
+ BPF_PROG_TYPE_SK_MSG,
+ BPF_PROG_TYPE_RAW_TRACEPOINT,
+ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
+ BPF_PROG_TYPE_LWT_SEG6LOCAL,
+ BPF_PROG_TYPE_LIRC_MODE2,
+ BPF_PROG_TYPE_SK_REUSEPORT,
+ BPF_PROG_TYPE_FLOW_DISSECTOR,
+ BPF_PROG_TYPE_CGROUP_SYSCTL,
+ BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
+ BPF_PROG_TYPE_CGROUP_SOCKOPT,
+};
+
+#define BPF_PSEUDO_MAP_FD 1
+
#define BPF_OBJ_NAME_LEN 16U
#define BPF_ANY 0 /* create new element or update existing */
@@ -225,8 +306,211 @@ union bpf_attr {
} task_fd_query;
} __attribute__((aligned(8)));
+#define __BPF_FUNC_MAPPER(FN) \
+ FN(unspec), \
+ FN(map_lookup_elem), \
+ FN(map_update_elem), \
+ FN(map_delete_elem), \
+ FN(probe_read), \
+ FN(ktime_get_ns), \
+ FN(trace_printk), \
+ FN(get_prandom_u32), \
+ FN(get_smp_processor_id), \
+ FN(skb_store_bytes), \
+ FN(l3_csum_replace), \
+ FN(l4_csum_replace), \
+ FN(tail_call), \
+ FN(clone_redirect), \
+ FN(get_current_pid_tgid), \
+ FN(get_current_uid_gid), \
+ FN(get_current_comm), \
+ FN(get_cgroup_classid), \
+ FN(skb_vlan_push), \
+ FN(skb_vlan_pop), \
+ FN(skb_get_tunnel_key), \
+ FN(skb_set_tunnel_key), \
+ FN(perf_event_read), \
+ FN(redirect), \
+ FN(get_route_realm), \
+ FN(perf_event_output), \
+ FN(skb_load_bytes), \
+ FN(get_stackid), \
+ FN(csum_diff), \
+ FN(skb_get_tunnel_opt), \
+ FN(skb_set_tunnel_opt), \
+ FN(skb_change_proto), \
+ FN(skb_change_type), \
+ FN(skb_under_cgroup), \
+ FN(get_hash_recalc), \
+ FN(get_current_task), \
+ FN(probe_write_user), \
+ FN(current_task_under_cgroup), \
+ FN(skb_change_tail), \
+ FN(skb_pull_data), \
+ FN(csum_update), \
+ FN(set_hash_invalid), \
+ FN(get_numa_node_id), \
+ FN(skb_change_head), \
+ FN(xdp_adjust_head), \
+ FN(probe_read_str), \
+ FN(get_socket_cookie), \
+ FN(get_socket_uid), \
+ FN(set_hash), \
+ FN(setsockopt), \
+ FN(skb_adjust_room), \
+ FN(redirect_map), \
+ FN(sk_redirect_map), \
+ FN(sock_map_update), \
+ FN(xdp_adjust_meta), \
+ FN(perf_event_read_value), \
+ FN(perf_prog_read_value), \
+ FN(getsockopt), \
+ FN(override_return), \
+ FN(sock_ops_cb_flags_set), \
+ FN(msg_redirect_map), \
+ FN(msg_apply_bytes), \
+ FN(msg_cork_bytes), \
+ FN(msg_pull_data), \
+ FN(bind), \
+ FN(xdp_adjust_tail), \
+ FN(skb_get_xfrm_state), \
+ FN(get_stack), \
+ FN(skb_load_bytes_relative), \
+ FN(fib_lookup), \
+ FN(sock_hash_update), \
+ FN(msg_redirect_hash), \
+ FN(sk_redirect_hash), \
+ FN(lwt_push_encap), \
+ FN(lwt_seg6_store_bytes), \
+ FN(lwt_seg6_adjust_srh), \
+ FN(lwt_seg6_action), \
+ FN(rc_repeat), \
+ FN(rc_keydown), \
+ FN(skb_cgroup_id), \
+ FN(get_current_cgroup_id), \
+ FN(get_local_storage), \
+ FN(sk_select_reuseport), \
+ FN(skb_ancestor_cgroup_id), \
+ FN(sk_lookup_tcp), \
+ FN(sk_lookup_udp), \
+ FN(sk_release), \
+ FN(map_push_elem), \
+ FN(map_pop_elem), \
+ FN(map_peek_elem), \
+ FN(msg_push_data), \
+ FN(msg_pop_data), \
+ FN(rc_pointer_rel), \
+ FN(spin_lock), \
+ FN(spin_unlock), \
+ FN(sk_fullsock), \
+ FN(tcp_sock), \
+ FN(skb_ecn_set_ce), \
+ FN(get_listener_sock), \
+ FN(skc_lookup_tcp), \
+ FN(tcp_check_syncookie), \
+ FN(sysctl_get_name), \
+ FN(sysctl_get_current_value), \
+ FN(sysctl_get_new_value), \
+ FN(sysctl_set_new_value), \
+ FN(strtol), \
+ FN(strtoul), \
+ FN(sk_storage_get), \
+ FN(sk_storage_delete), \
+ FN(send_signal),
+
+/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+ * function eBPF program intends to call
+ */
+#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
+enum bpf_func_id {
+ __BPF_FUNC_MAPPER(__BPF_ENUM_FN)
+ __BPF_FUNC_MAX_ID,
+};
+#undef __BPF_ENUM_FN
+
/* End copy from linux/bpf.h */
+/* Start copy from tools/include/filter.h */
+
+#define BPF_ALU64_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_MOV64_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_LD_IMM64(DST, IMM) \
+ BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_DW | BPF_IMM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = (uint32_t) (IMM) }), \
+ ((struct bpf_insn) { \
+ .code = 0, /* zero is reserved opcode */ \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((uint64_t) (IMM)) >> 32 })
+
+/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
+#define BPF_LD_MAP_FD(DST, MAP_FD) \
+ BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+#define BPF_MOV64_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_EMIT_CALL(FUNC) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_CALL, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((FUNC) - BPF_FUNC_unspec) })
+
+#define BPF_EXIT_INSN() \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_EXIT, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = 0 })
+
+/* End copy from tools/include/filter.h */
+
/* Start copy from tools/lib/bpf */
inline uint64_t ptr_to_u64(const void *ptr)
{
diff --git a/include/lapi/socket.h b/include/lapi/socket.h
index 6d9e9fe30..f32782fed 100644
--- a/include/lapi/socket.h
+++ b/include/lapi/socket.h
@@ -38,6 +38,10 @@
# define SO_BUSY_POLL 46
#endif
+#ifndef SO_ATTACH_BPF
+# define SO_ATTACH_BPF 50
+#endif
+
#ifndef SO_ZEROCOPY
# define SO_ZEROCOPY 60
#endif
--
2.21.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program
2019-08-26 11:10 [LTP] [PATCH v4 0/4] Basic eBPF tests Cyril Hrubis
` (2 preceding siblings ...)
2019-08-26 11:10 ` [LTP] [PATCH v4 3/4] BPF: Essential headers for a basic program Cyril Hrubis
@ 2019-08-26 11:10 ` Cyril Hrubis
2019-08-26 16:05 ` Jan Stancek
2019-08-28 7:41 ` Clemens Famulla-Conrad
2019-08-26 14:29 ` [LTP] [PATCH v4 0/4] Basic eBPF tests Jan Stancek
4 siblings, 2 replies; 17+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:10 UTC (permalink / raw)
To: ltp
From: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/bpf/.gitignore | 1 +
testcases/kernel/syscalls/bpf/bpf_prog01.c | 162 +++++++++++++++++++++
3 files changed, 164 insertions(+)
create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c
diff --git a/runtest/syscalls b/runtest/syscalls
index 6ddfc2178..ec9f5ef6d 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -33,6 +33,7 @@ bind02 bind02
bind03 bind03
bpf_map01 bpf_map01
+bpf_prog01 bpf_prog01
brk01 brk01
diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore
index f33532484..7eb5f7c92 100644
--- a/testcases/kernel/syscalls/bpf/.gitignore
+++ b/testcases/kernel/syscalls/bpf/.gitignore
@@ -1 +1,2 @@
bpf_map01
+bpf_prog01
diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c b/testcases/kernel/syscalls/bpf/bpf_prog01.c
new file mode 100644
index 000000000..135324efb
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Trivial Extended Berkeley Packet Filter (eBPF) test.
+ *
+ * Sanity check loading and running bytecode.
+ *
+ * Test flow:
+ * 1. Create array map
+ * 2. Load eBPF program
+ * 3. Attach program to socket
+ * 4. Send packet on socket
+ * 5. This should trigger eBPF program which writes to array map
+ * 6. Verify array map was written to
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/socket.h"
+#include "lapi/bpf.h"
+
+const char MSG[] = "Ahoj!";
+static char *msg;
+
+/*
+ * The following is a byte code template. We copy it to a guarded buffer and
+ * substitute the runtime value of our map file descriptor.
+ *
+ * r0 - r10 = registers 0 to 10
+ * r0 = return code
+ * r1 - r5 = scratch registers, used for function arguments
+ * r6 - r9 = registers preserved across function calls
+ * fp/r10 = stack frame pointer
+ */
+const struct bpf_insn PROG[] = {
+ /* Load the map FD into r1 (place holder) */
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ /* Put (key = 0) on stack and key ptr into r2 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = r2 - 8 */
+ BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), /* *r2 = 0 */
+ /* r0 = bpf_map_lookup_elem(r1, r2) */
+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+ /* if r0 == 0 goto exit */
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+ /* Set map[0] = 1 */
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* r1 = r0 */
+ BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 1), /* *r1 = 1 */
+ BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */
+ BPF_EXIT_INSN(), /* return r0 */
+};
+
+static struct bpf_insn *prog;
+static char *log;
+static union bpf_attr *attr;
+
+int load_prog(int fd)
+{
+ prog[0] = BPF_LD_MAP_FD(BPF_REG_1, fd);
+
+ memset(attr, 0, sizeof(*attr));
+ attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
+ attr->insns = ptr_to_u64(prog);
+ attr->insn_cnt = ARRAY_SIZE(PROG);
+ attr->license = ptr_to_u64("GPL");
+ attr->log_buf = ptr_to_u64(log);
+ attr->log_size = BUFSIZ;
+ attr->log_level = 1;
+
+ TEST(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)));
+ if (TST_RET == -1) {
+ if (log[0] != 0) {
+ tst_brk(TFAIL | TTERRNO,
+ "Failed verification: %s",
+ log);
+ } else {
+ tst_brk(TFAIL | TTERRNO, "Failed to load program");
+ }
+ } else {
+ tst_res(TPASS, "Loaded program");
+ }
+
+ return TST_RET;
+}
+
+void setup(void)
+{
+ memcpy(prog, PROG, sizeof(PROG));
+ memcpy(msg, MSG, sizeof(MSG));
+}
+
+void run(void)
+{
+ int map_fd, prog_fd;
+ int sk[2];
+ uint32_t key = 0;
+ uint64_t val;
+
+ memset(attr, 0, sizeof(*attr));
+ attr->map_type = BPF_MAP_TYPE_ARRAY;
+ attr->key_size = 4;
+ attr->value_size = 8;
+ attr->max_entries = 1;
+
+ TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)));
+ if (TST_RET == -1) {
+ if (TST_ERR == EPERM) {
+ tst_brk(TCONF | TTERRNO,
+ "bpf() requires CAP_SYS_ADMIN on this system");
+ } else {
+ tst_brk(TBROK | TTERRNO, "Failed to create array map");
+ }
+ }
+ map_fd = TST_RET;
+
+ prog_fd = load_prog(map_fd);
+
+ SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
+ SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF,
+ &prog_fd, sizeof(prog_fd));
+
+ SAFE_WRITE(1, sk[0], msg, sizeof(MSG));
+
+ memset(attr, 0, sizeof(*attr));
+ attr->map_fd = map_fd;
+ attr->key = ptr_to_u64(&key);
+ attr->value = ptr_to_u64(&val);
+
+ TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
+ if (TST_RET == -1) {
+ tst_res(TFAIL | TTERRNO, "array map lookup");
+ } else if (val != 1) {
+ tst_res(TFAIL,
+ "val = %lu, but should be val = 1",
+ val);
+ } else {
+ tst_res(TPASS, "val = 1");
+ }
+
+ SAFE_CLOSE(prog_fd);
+ SAFE_CLOSE(map_fd);
+ SAFE_CLOSE(sk[0]);
+ SAFE_CLOSE(sk[1]);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .min_kver = "3.18",
+ .bufs = (struct tst_buffers []) {
+ {&log, .size = BUFSIZ},
+ {&prog, .size = sizeof(PROG)},
+ {&attr, .size = sizeof(*attr)},
+ {&msg, .size = sizeof(MSG)},
+ {},
+ }
+};
--
2.21.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps
2019-08-26 11:10 ` [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps Cyril Hrubis
@ 2019-08-26 12:52 ` Jan Stancek
2019-09-02 14:05 ` Cyril Hrubis
0 siblings, 1 reply; 17+ messages in thread
From: Jan Stancek @ 2019-08-26 12:52 UTC (permalink / raw)
To: ltp
----- Original Message -----
> +
> +static const struct map_type map_types[] = {
> + {BPF_MAP_TYPE_HASH, "hash", 8, &key8},
> + {BPF_MAP_TYPE_ARRAY, "array", 4, &key4}
> +};
> +
> +void run(unsigned int n)
> +{
> + int fd, i;
> + void *key = *map_types[n].key;
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->map_type = map_types[n].id;
> + attr->key_size = map_types[n].key_size;
> + attr->value_size = VAL_SZ;
> + attr->max_entries = 1;
> +
> + TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)));
> + if (TST_RET == -1) {
> + if (TST_ERR == EPERM) {
> + tst_brk(TCONF | TTERRNO,
> + "bpf() requires CAP_SYS_ADMIN on this system");
> + } else {
> + tst_res(TFAIL | TTERRNO, "Failed to create %s map",
> + map_types[n].name);
> + return;
> + }
> + }
> + tst_res(TPASS, "Created %s map", map_types[n].name);
> + fd = TST_RET;
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->map_fd = fd;
> + attr->key = ptr_to_u64(key);
> + attr->value = ptr_to_u64(val_get);
> +
> + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
> +
> + switch (n) {
Small nit (maybe personal preference), I'd rather make this check for
map_types.attr, as opposed to test number / some position in array.
> + case 0:
> + if (TST_RET != -1 || TST_ERR != ENOENT) {
> + tst_res(TFAIL | TTERRNO,
> + "Empty hash map lookup should fail with ENOENT");
> + } else {
> + tst_res(TPASS | TTERRNO, "Empty hash map lookup");
> + }
> + break;
> + case 1:
> + if (TST_RET != -1) {
> + for (i = 0;;) {
> + if (val_get[i] != 0) {
> + tst_res(TFAIL,
> + "Preallocated array map val not zero");
If we hit this TFAIL, will the loop terminate?
> + } else if (++i >= VAL_SZ) {
> + tst_res(TPASS,
> + "Preallocated array map lookup");
> + break;
> + }
> + }
> + } else {
> + tst_res(TFAIL | TERRNO, "Prellocated array map lookup");
> + }
> + break;
> + }
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->map_fd = fd;
> + attr->key = ptr_to_u64(key);
> + attr->value = ptr_to_u64(val_set);
> + attr->flags = BPF_ANY;
> +
> + TEST(bpf(BPF_MAP_UPDATE_ELEM, attr, sizeof(*attr)));
> + if (TST_RET == -1) {
> + tst_brk(TFAIL | TTERRNO,
> + "Update %s map element",
> + map_types[n].name);
> + } else {
> + tst_res(TPASS,
> + "Update %s map element",
> + map_types[n].name);
> + }
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->map_fd = fd;
> + attr->key = ptr_to_u64(key);
> + attr->value = ptr_to_u64(val_get);
> +
> + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
> + if (TST_RET == -1) {
> + tst_res(TFAIL | TTERRNO,
> + "%s map lookup missing",
> + map_types[n].name);
> + } else if (memcmp(val_set, val_get, (size_t) VAL_SZ)) {
> + tst_res(TFAIL,
> + "%s map lookup returned different value",
> + map_types[n].name);
> + } else {
> + tst_res(TPASS, "%s map lookup", map_types[n].name);
> + }
> +
> + SAFE_CLOSE(fd);
> +}
> +
> +static void setup(void)
> +{
> + unsigned int i;
> +
> + memcpy(key8, "12345678", 8);
> + memset(key4, 0, 4);
> +
> + for (i = 0; i < VAL_SZ; i++)
> + val_set[i] = i % 256;
> +}
> +
> +static struct tst_test test = {
> + .tcnt = 2,
Nit, ARRAY_SIZE(map_types) ?
> + .test = run,
> + .setup = setup,
> + .min_kver = "3.18",
> + .bufs = (struct tst_buffers []) {
> + {&key4, .size = 4},
> + {&key8, .size = 8},
> + {&val_set, .size = VAL_SZ},
> + {&val_get, .size = VAL_SZ},
> + {&attr, .size = sizeof(*attr)},
> + {},
> + },
> +};
> --
> 2.21.0
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-08-26 11:10 [LTP] [PATCH v4 0/4] Basic eBPF tests Cyril Hrubis
` (3 preceding siblings ...)
2019-08-26 11:10 ` [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program Cyril Hrubis
@ 2019-08-26 14:29 ` Jan Stancek
2019-08-28 7:26 ` Clemens Famulla-Conrad
2019-09-02 14:55 ` Cyril Hrubis
4 siblings, 2 replies; 17+ messages in thread
From: Jan Stancek @ 2019-08-26 14:29 UTC (permalink / raw)
To: ltp
----- Original Message -----
> I've ended up playing with the patchset and fixed a few loose ends on
> the map test and as I had the code at hand I decided to send v4 instead
> of pointing out the mistakes in a review.
>
> There were numerous small changes for the map test:
>
> * Make sure the key buffer is sized exactly for the content
>
> * Initialized the array/hash element value in test setup
>
> * Made the code flow a bit more obvious, it was hard to tell which
> part was run for n == 0 and which for n == 1
>
> Also it looks that for me the test that loads the eBPF program ends up
> with EPERM randomly at about 10th iteration both as unpriviledged and
> priviledged user, which is really strange.
There's one EPERM I can reproduce reliably with bpf_map test, which appears
to originate from "bpf_charge_memlock".
There's a deferred component to map freeing, and unchange appears to be part of it:
bpf_map_release
bpf_map_put
INIT_WORK(&map->work, bpf_map_free_deferred);
(deferred) bpf_uncharge_memlock
When I lower max locked memory, it's easy to hit:
# ulimit -l 128; ./bpf_map01 -i 100
...
bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
Can you try bumping max locked memory to some high value and check
if that helps your case?
Regards,
Jan
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program
2019-08-26 11:10 ` [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program Cyril Hrubis
@ 2019-08-26 16:05 ` Jan Stancek
2019-08-28 7:41 ` Clemens Famulla-Conrad
1 sibling, 0 replies; 17+ messages in thread
From: Jan Stancek @ 2019-08-26 16:05 UTC (permalink / raw)
To: ltp
----- Original Message -----
> From: Richard Palethorpe <rpalethorpe@suse.com>
>
> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
> Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
> +
> +static struct tst_test test = {
> + .setup = setup,
> + .test_all = run,
> + .min_kver = "3.18",
Small nit, per http://man7.org/linux/man-pages/man2/bpf.2.html it's since 3.19.
Some comments in 2/4, but overall looks good to me.
Acked-by: Jan Stancek <jstancek@redhat.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-08-26 14:29 ` [LTP] [PATCH v4 0/4] Basic eBPF tests Jan Stancek
@ 2019-08-28 7:26 ` Clemens Famulla-Conrad
2019-08-28 7:46 ` Jan Stancek
2019-09-02 14:55 ` Cyril Hrubis
1 sibling, 1 reply; 17+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-28 7:26 UTC (permalink / raw)
To: ltp
On Mon, 2019-08-26 at 10:29 -0400, Jan Stancek wrote:
>
> ----- Original Message -----
> > I've ended up playing with the patchset and fixed a few loose ends
> > on
> > the map test and as I had the code at hand I decided to send v4
> > instead
> > of pointing out the mistakes in a review.
> >
> > There were numerous small changes for the map test:
> >
> > * Make sure the key buffer is sized exactly for the content
> >
> > * Initialized the array/hash element value in test setup
> >
> > * Made the code flow a bit more obvious, it was hard to tell which
> > part was run for n == 0 and which for n == 1
> >
> > Also it looks that for me the test that loads the eBPF program ends
> > up
> > with EPERM randomly at about 10th iteration both as unpriviledged
> > and
> > priviledged user, which is really strange.
>
> There's one EPERM I can reproduce reliably with bpf_map test, which
> appears
> to originate from "bpf_charge_memlock".
>
> There's a deferred component to map freeing, and unchange appears to
> be part of it:
> bpf_map_release
> bpf_map_put
> INIT_WORK(&map->work, bpf_map_free_deferred);
> (deferred) bpf_uncharge_memlock
>
> When I lower max locked memory, it's easy to hit:
> # ulimit -l 128; ./bpf_map01 -i 100
> ...
> bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system:
> EPERM
>
> Can you try bumping max locked memory to some high value and check
> if that helps your case?
# for i in 64 128 256 1024; do
echo $i;
ulimit -l $i;
./bpf_prog01 -i 100 |& grep -P 'passed|CONF';
done
64
CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 16
128
CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 16
256
CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 32
1024
CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 192
Which produce almost the same results.
Same approach with `bpf_map01` differs a lot. Sometimes all pass,
sometimes none.
/Clemens
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program
2019-08-26 11:10 ` [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program Cyril Hrubis
2019-08-26 16:05 ` Jan Stancek
@ 2019-08-28 7:41 ` Clemens Famulla-Conrad
1 sibling, 0 replies; 17+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-28 7:41 UTC (permalink / raw)
To: ltp
Acked-by: Clemens Famulla-Conrad <cfamullaconrad@suse.de>
On Mon, 2019-08-26 at 13:10 +0200, Cyril Hrubis wrote:
> From: Richard Palethorpe <rpalethorpe@suse.com>
>
> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
> Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
> ---
> runtest/syscalls | 1 +
> testcases/kernel/syscalls/bpf/.gitignore | 1 +
> testcases/kernel/syscalls/bpf/bpf_prog01.c | 162
> +++++++++++++++++++++
> 3 files changed, 164 insertions(+)
> create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c
>
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 6ddfc2178..ec9f5ef6d 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -33,6 +33,7 @@ bind02 bind02
> bind03 bind03
>
> bpf_map01 bpf_map01
> +bpf_prog01 bpf_prog01
>
> brk01 brk01
>
> diff --git a/testcases/kernel/syscalls/bpf/.gitignore
> b/testcases/kernel/syscalls/bpf/.gitignore
> index f33532484..7eb5f7c92 100644
> --- a/testcases/kernel/syscalls/bpf/.gitignore
> +++ b/testcases/kernel/syscalls/bpf/.gitignore
> @@ -1 +1,2 @@
> bpf_map01
> +bpf_prog01
> diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c
> b/testcases/kernel/syscalls/bpf/bpf_prog01.c
> new file mode 100644
> index 000000000..135324efb
> --- /dev/null
> +++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c
> @@ -0,0 +1,162 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
> + *
> + * Trivial Extended Berkeley Packet Filter (eBPF) test.
> + *
> + * Sanity check loading and running bytecode.
> + *
> + * Test flow:
> + * 1. Create array map
> + * 2. Load eBPF program
> + * 3. Attach program to socket
> + * 4. Send packet on socket
> + * 5. This should trigger eBPF program which writes to array map
> + * 6. Verify array map was written to
> + */
> +
> +#include <limits.h>
> +#include <string.h>
> +#include <stdio.h>
> +
> +#include "config.h"
> +#include "tst_test.h"
> +#include "lapi/socket.h"
> +#include "lapi/bpf.h"
> +
> +const char MSG[] = "Ahoj!";
> +static char *msg;
> +
> +/*
> + * The following is a byte code template. We copy it to a guarded
> buffer and
> + * substitute the runtime value of our map file descriptor.
> + *
> + * r0 - r10 = registers 0 to 10
> + * r0 = return code
> + * r1 - r5 = scratch registers, used for function arguments
> + * r6 - r9 = registers preserved across function calls
> + * fp/r10 = stack frame pointer
> + */
> +const struct bpf_insn PROG[] = {
> + /* Load the map FD into r1 (place holder) */
> + BPF_LD_MAP_FD(BPF_REG_1, 0),
> + /* Put (key = 0) on stack and key ptr into r2 */
> + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */
> + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = r2 - 8 */
> + BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), /* *r2 = 0 */
/* *(u64 * r2) = 0 */
Is it possible to can call `BPF_FUNC_map_lookup_elem` with u32, like
here[1]? Maybe that hint helps to see that BPF_DW more quickly then I
did :)
[1] https://github.com/torvalds/linux/blob/v4.20/samples/bpf/sock_examp
le.c#L52
> + /* r0 = bpf_map_lookup_elem(r1, r2) */
> + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
> + /* if r0 == 0 goto exit */
> + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
> + /* Set map[0] = 1 */
> + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* r1 = r0 */
> + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 1), /* *r1 = 1 */
> + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */
> + BPF_EXIT_INSN(), /* return r0 */
> +};
> +
> +static struct bpf_insn *prog;
> +static char *log;
> +static union bpf_attr *attr;
> +
> +int load_prog(int fd)
> +{
> + prog[0] = BPF_LD_MAP_FD(BPF_REG_1, fd);
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
> + attr->insns = ptr_to_u64(prog);
> + attr->insn_cnt = ARRAY_SIZE(PROG);
> + attr->license = ptr_to_u64("GPL");
> + attr->log_buf = ptr_to_u64(log);
> + attr->log_size = BUFSIZ;
> + attr->log_level = 1;
> +
> + TEST(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)));
> + if (TST_RET == -1) {
> + if (log[0] != 0) {
> + tst_brk(TFAIL | TTERRNO,
> + "Failed verification: %s",
> + log);
> + } else {
> + tst_brk(TFAIL | TTERRNO, "Failed to load
> program");
> + }
> + } else {
> + tst_res(TPASS, "Loaded program");
> + }
> +
> + return TST_RET;
> +}
> +
> +void setup(void)
> +{
> + memcpy(prog, PROG, sizeof(PROG));
> + memcpy(msg, MSG, sizeof(MSG));
> +}
> +
> +void run(void)
> +{
> + int map_fd, prog_fd;
> + int sk[2];
> + uint32_t key = 0;
> + uint64_t val;
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->map_type = BPF_MAP_TYPE_ARRAY;
> + attr->key_size = 4;
> + attr->value_size = 8;
> + attr->max_entries = 1;
> +
> + TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)));
> + if (TST_RET == -1) {
> + if (TST_ERR == EPERM) {
> + tst_brk(TCONF | TTERRNO,
> + "bpf() requires CAP_SYS_ADMIN on
> this system");
> + } else {
> + tst_brk(TBROK | TTERRNO, "Failed to create
> array map");
> + }
> + }
> + map_fd = TST_RET;
> +
> + prog_fd = load_prog(map_fd);
> +
> + SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
> + SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF,
> + &prog_fd, sizeof(prog_fd));
> +
> + SAFE_WRITE(1, sk[0], msg, sizeof(MSG));
> +
> + memset(attr, 0, sizeof(*attr));
> + attr->map_fd = map_fd;
> + attr->key = ptr_to_u64(&key);
> + attr->value = ptr_to_u64(&val);
> +
> + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
> + if (TST_RET == -1) {
> + tst_res(TFAIL | TTERRNO, "array map lookup");
> + } else if (val != 1) {
> + tst_res(TFAIL,
> + "val = %lu, but should be val = 1",
> + val);
> + } else {
> + tst_res(TPASS, "val = 1");
> + }
> +
> + SAFE_CLOSE(prog_fd);
> + SAFE_CLOSE(map_fd);
> + SAFE_CLOSE(sk[0]);
> + SAFE_CLOSE(sk[1]);
> +}
> +
> +static struct tst_test test = {
> + .setup = setup,
> + .test_all = run,
> + .min_kver = "3.18",
> + .bufs = (struct tst_buffers []) {
> + {&log, .size = BUFSIZ},
> + {&prog, .size = sizeof(PROG)},
> + {&attr, .size = sizeof(*attr)},
> + {&msg, .size = sizeof(MSG)},
> + {},
> + }
> +};
> --
> 2.21.0
>
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-08-28 7:26 ` Clemens Famulla-Conrad
@ 2019-08-28 7:46 ` Jan Stancek
2019-08-28 10:15 ` Clemens Famulla-Conrad
0 siblings, 1 reply; 17+ messages in thread
From: Jan Stancek @ 2019-08-28 7:46 UTC (permalink / raw)
To: ltp
----- Original Message -----
> On Mon, 2019-08-26 at 10:29 -0400, Jan Stancek wrote:
> >
> > ----- Original Message -----
> > > I've ended up playing with the patchset and fixed a few loose ends
> > > on
> > > the map test and as I had the code at hand I decided to send v4
> > > instead
> > > of pointing out the mistakes in a review.
> > >
> > > There were numerous small changes for the map test:
> > >
> > > * Make sure the key buffer is sized exactly for the content
> > >
> > > * Initialized the array/hash element value in test setup
> > >
> > > * Made the code flow a bit more obvious, it was hard to tell which
> > > part was run for n == 0 and which for n == 1
> > >
> > > Also it looks that for me the test that loads the eBPF program ends
> > > up
> > > with EPERM randomly at about 10th iteration both as unpriviledged
> > > and
> > > priviledged user, which is really strange.
> >
> > There's one EPERM I can reproduce reliably with bpf_map test, which
> > appears
> > to originate from "bpf_charge_memlock".
> >
> > There's a deferred component to map freeing, and unchange appears to
> > be part of it:
> > bpf_map_release
> > bpf_map_put
> > INIT_WORK(&map->work, bpf_map_free_deferred);
> > (deferred) bpf_uncharge_memlock
> >
> > When I lower max locked memory, it's easy to hit:
> > # ulimit -l 128; ./bpf_map01 -i 100
> > ...
> > bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system:
> > EPERM
> >
> > Can you try bumping max locked memory to some high value and check
> > if that helps your case?
>
> # for i in 64 128 256 1024; do
> echo $i;
> ulimit -l $i;
> ./bpf_prog01 -i 100 |& grep -P 'passed|CONF';
> done
>
> 64
> CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> passed 16
>
> 128
> CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> passed 16
>
> 256
> CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> passed 32
>
> 1024
> CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> passed 192
>
>
> Which produce almost the same results.
> Same approach with `bpf_map01` differs a lot. Sometimes all pass,
> sometimes none.
Seems to make difference for me on 5.2:
# cat bench.sh; sh bench.sh
for i in 128 256 512 1024 4096 65536; do
echo $i;
ulimit -l $i;
./bpf_prog01 -i 100 |& grep -P 'passed|CONF';
sleep 4;
done
128
bpf_prog01.c:114: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 32
256
bpf_prog01.c:114: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 64
512
bpf_prog01.c:114: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
passed 128
1024
passed 200
4096
passed 200
65536
passed 200
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-08-28 7:46 ` Jan Stancek
@ 2019-08-28 10:15 ` Clemens Famulla-Conrad
0 siblings, 0 replies; 17+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-28 10:15 UTC (permalink / raw)
To: ltp
On Wed, 2019-08-28 at 03:46 -0400, Jan Stancek wrote:
> ----- Original Message -----
> > On Mon, 2019-08-26 at 10:29 -0400, Jan Stancek wrote:
> > >
> > > ----- Original Message -----
> > > > I've ended up playing with the patchset and fixed a few loose
> > > > ends
> > > > on
> > > > the map test and as I had the code at hand I decided to send v4
> > > > instead
> > > > of pointing out the mistakes in a review.
> > > >
> > > > There were numerous small changes for the map test:
> > > >
> > > > * Make sure the key buffer is sized exactly for the content
> > > >
> > > > * Initialized the array/hash element value in test setup
> > > >
> > > > * Made the code flow a bit more obvious, it was hard to tell
> > > > which
> > > > part was run for n == 0 and which for n == 1
> > > >
> > > > Also it looks that for me the test that loads the eBPF program
> > > > ends
> > > > up
> > > > with EPERM randomly at about 10th iteration both as
> > > > unpriviledged
> > > > and
> > > > priviledged user, which is really strange.
> > >
> > > There's one EPERM I can reproduce reliably with bpf_map test,
> > > which
> > > appears
> > > to originate from "bpf_charge_memlock".
> > >
> > > There's a deferred component to map freeing, and unchange appears
> > > to
> > > be part of it:
> > > bpf_map_release
> > > bpf_map_put
> > > INIT_WORK(&map->work, bpf_map_free_deferred);
> > > (deferred) bpf_uncharge_memlock
> > >
> > > When I lower max locked memory, it's easy to hit:
> > > # ulimit -l 128; ./bpf_map01 -i 100
> > > ...
> > > bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this
> > > system:
> > > EPERM
> > >
> > > Can you try bumping max locked memory to some high value and
> > > check
> > > if that helps your case?
> >
> > # for i in 64 128 256 1024; do
> > echo $i;
> > ulimit -l $i;
> > ./bpf_prog01 -i 100 |& grep -P 'passed|CONF';
> > done
> >
> > 64
> > CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> > passed 16
> >
> > 128
> > CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> > passed 16
> >
> > 256
> > CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> > passed 32
> >
> > 1024
> > CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> > passed 192
> >
> >
> > Which produce almost the same results.
> > Same approach with `bpf_map01` differs a lot. Sometimes all pass,
> > sometimes none.
>
> Seems to make difference for me on 5.2:
>
> # cat bench.sh; sh bench.sh
> for i in 128 256 512 1024 4096 65536; do
> echo $i;
> ulimit -l $i;
> ./bpf_prog01 -i 100 |& grep -P 'passed|CONF';
> sleep 4;
> done
>
> 128
> bpf_prog01.c:114: CONF: bpf() requires CAP_SYS_ADMIN on this system:
> EPERM
> passed 32
> 256
> bpf_prog01.c:114: CONF: bpf() requires CAP_SYS_ADMIN on this system:
> EPERM
> passed 64
> 512
> bpf_prog01.c:114: CONF: bpf() requires CAP_SYS_ADMIN on this system:
> EPERM
> passed 128
> 1024
> passed 200
> 4096
> passed 200
> 65536
> passed 200
>
I ran it again and now my results looks like yours...
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps
2019-08-26 12:52 ` Jan Stancek
@ 2019-09-02 14:05 ` Cyril Hrubis
0 siblings, 0 replies; 17+ messages in thread
From: Cyril Hrubis @ 2019-09-02 14:05 UTC (permalink / raw)
To: ltp
Hi!
> Small nit (maybe personal preference), I'd rather make this check for
> map_types.attr, as opposed to test number / some position in array.
Sounds good.
> > + case 0:
> > + if (TST_RET != -1 || TST_ERR != ENOENT) {
> > + tst_res(TFAIL | TTERRNO,
> > + "Empty hash map lookup should fail with ENOENT");
> > + } else {
> > + tst_res(TPASS | TTERRNO, "Empty hash map lookup");
> > + }
> > + break;
> > + case 1:
> > + if (TST_RET != -1) {
> > + for (i = 0;;) {
> > + if (val_get[i] != 0) {
> > + tst_res(TFAIL,
> > + "Preallocated array map val not zero");
>
> If we hit this TFAIL, will the loop terminate?
My bad, I will change this to use proper for() loop.
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-08-26 14:29 ` [LTP] [PATCH v4 0/4] Basic eBPF tests Jan Stancek
2019-08-28 7:26 ` Clemens Famulla-Conrad
@ 2019-09-02 14:55 ` Cyril Hrubis
2019-09-03 5:50 ` Jan Stancek
1 sibling, 1 reply; 17+ messages in thread
From: Cyril Hrubis @ 2019-09-02 14:55 UTC (permalink / raw)
To: ltp
Hi!
> There's one EPERM I can reproduce reliably with bpf_map test, which appears
> to originate from "bpf_charge_memlock".
>
> There's a deferred component to map freeing, and unchange appears to be part of it:
> bpf_map_release
> bpf_map_put
> INIT_WORK(&map->work, bpf_map_free_deferred);
> (deferred) bpf_uncharge_memlock
>
> When I lower max locked memory, it's easy to hit:
> # ulimit -l 128; ./bpf_map01 -i 100
> ...
> bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
>
> Can you try bumping max locked memory to some high value and check
> if that helps your case?
Looks like this was the case, with high enough value the tests works
without a problem. The question is if and/or what should be done about
this...
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-09-02 14:55 ` Cyril Hrubis
@ 2019-09-03 5:50 ` Jan Stancek
2019-09-03 8:58 ` Cyril Hrubis
0 siblings, 1 reply; 17+ messages in thread
From: Jan Stancek @ 2019-09-03 5:50 UTC (permalink / raw)
To: ltp
----- Original Message -----
> Hi!
> > There's one EPERM I can reproduce reliably with bpf_map test, which appears
> > to originate from "bpf_charge_memlock".
> >
> > There's a deferred component to map freeing, and unchange appears to be
> > part of it:
> > bpf_map_release
> > bpf_map_put
> > INIT_WORK(&map->work, bpf_map_free_deferred);
> > (deferred) bpf_uncharge_memlock
> >
> > When I lower max locked memory, it's easy to hit:
> > # ulimit -l 128; ./bpf_map01 -i 100
> > ...
> > bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> >
> > Can you try bumping max locked memory to some high value and check
> > if that helps your case?
>
> Looks like this was the case, with high enough value the tests works
> without a problem. The question is if and/or what should be done about
> this...
We can try asking on bpf@vger.kernel.org, if they see it as bug.
I'd push tests with a comment. Or setup() that bumps the limit: whatever
current limit is, add 2MB to it, so single/few iteration(s) should always work.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-09-03 5:50 ` Jan Stancek
@ 2019-09-03 8:58 ` Cyril Hrubis
2019-09-03 9:51 ` Jan Stancek
0 siblings, 1 reply; 17+ messages in thread
From: Cyril Hrubis @ 2019-09-03 8:58 UTC (permalink / raw)
To: ltp
Hi!
> > > There's one EPERM I can reproduce reliably with bpf_map test, which appears
> > > to originate from "bpf_charge_memlock".
> > >
> > > There's a deferred component to map freeing, and unchange appears to be
> > > part of it:
> > > bpf_map_release
> > > bpf_map_put
> > > INIT_WORK(&map->work, bpf_map_free_deferred);
> > > (deferred) bpf_uncharge_memlock
> > >
> > > When I lower max locked memory, it's easy to hit:
> > > # ulimit -l 128; ./bpf_map01 -i 100
> > > ...
> > > bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system: EPERM
> > >
> > > Can you try bumping max locked memory to some high value and check
> > > if that helps your case?
> >
> > Looks like this was the case, with high enough value the tests works
> > without a problem. The question is if and/or what should be done about
> > this...
>
> We can try asking on bpf@vger.kernel.org, if they see it as bug.
Let's start with this, it would be a bit nicer if it returned EAGAIN
instead of EPERM at least. Will you send the email or should I?
> I'd push tests with a comment. Or setup() that bumps the limit: whatever
> current limit is, add 2MB to it, so single/few iteration(s) should always work.
Let's go with a comment for now, we can add code later on once we are
clear on what is the expected outcome.
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH v4 0/4] Basic eBPF tests
2019-09-03 8:58 ` Cyril Hrubis
@ 2019-09-03 9:51 ` Jan Stancek
0 siblings, 0 replies; 17+ messages in thread
From: Jan Stancek @ 2019-09-03 9:51 UTC (permalink / raw)
To: ltp
----- Original Message -----
> Hi!
> > > > There's one EPERM I can reproduce reliably with bpf_map test, which
> > > > appears
> > > > to originate from "bpf_charge_memlock".
> > > >
> > > > There's a deferred component to map freeing, and unchange appears to be
> > > > part of it:
> > > > bpf_map_release
> > > > bpf_map_put
> > > > INIT_WORK(&map->work, bpf_map_free_deferred);
> > > > (deferred) bpf_uncharge_memlock
> > > >
> > > > When I lower max locked memory, it's easy to hit:
> > > > # ulimit -l 128; ./bpf_map01 -i 100
> > > > ...
> > > > bpf_map01.c:52: CONF: bpf() requires CAP_SYS_ADMIN on this system:
> > > > EPERM
> > > >
> > > > Can you try bumping max locked memory to some high value and check
> > > > if that helps your case?
> > >
> > > Looks like this was the case, with high enough value the tests works
> > > without a problem. The question is if and/or what should be done about
> > > this...
> >
> > We can try asking on bpf@vger.kernel.org, if they see it as bug.
>
> Let's start with this, it would be a bit nicer if it returned EAGAIN
> instead of EPERM at least. Will you send the email or should I?
If you don't mind please send the email. You know those tests better,
and your environment seems to have lower (/lowest) default value.
>
> > I'd push tests with a comment. Or setup() that bumps the limit: whatever
> > current limit is, add 2MB to it, so single/few iteration(s) should always
> > work.
>
> Let's go with a comment for now, we can add code later on once we are
> clear on what is the expected outcome.
Sounds good.
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2019-09-03 9:51 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-26 11:10 [LTP] [PATCH v4 0/4] Basic eBPF tests Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 1/4] BPF: Essential headers for map creation Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 2/4] BPF: Sanity check creating and updating maps Cyril Hrubis
2019-08-26 12:52 ` Jan Stancek
2019-09-02 14:05 ` Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 3/4] BPF: Essential headers for a basic program Cyril Hrubis
2019-08-26 11:10 ` [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program Cyril Hrubis
2019-08-26 16:05 ` Jan Stancek
2019-08-28 7:41 ` Clemens Famulla-Conrad
2019-08-26 14:29 ` [LTP] [PATCH v4 0/4] Basic eBPF tests Jan Stancek
2019-08-28 7:26 ` Clemens Famulla-Conrad
2019-08-28 7:46 ` Jan Stancek
2019-08-28 10:15 ` Clemens Famulla-Conrad
2019-09-02 14:55 ` Cyril Hrubis
2019-09-03 5:50 ` Jan Stancek
2019-09-03 8:58 ` Cyril Hrubis
2019-09-03 9:51 ` Jan Stancek
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.