All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.