Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 43b987d2 authored by Mauricio Vasquez B's avatar Mauricio Vasquez B Committed by Alexei Starovoitov
Browse files

selftests/bpf: add test cases for queue and stack maps



test_maps:
Tests that queue/stack maps are behaving correctly even in corner cases

test_progs:
Tests new ebpf helpers

Signed-off-by: default avatarMauricio Vasquez B <mauricio.vasquez@polito.it>
Acked-by: default avatarSong Liu <songliubraving@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent da4e1b15
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -278,6 +278,18 @@ int bpf_map_lookup_elem(int fd, const void *key, void *value)
	return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}

int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
{
	union bpf_attr attr;

	bzero(&attr, sizeof(attr));
	attr.map_fd = fd;
	attr.key = ptr_to_u64(key);
	attr.value = ptr_to_u64(value);

	return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
}

int bpf_map_delete_elem(int fd, const void *key)
{
	union bpf_attr attr;
+2 −0
Original line number Diff line number Diff line
@@ -99,6 +99,8 @@ LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
				   __u64 flags);

LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value);
LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
					      void *value);
LIBBPF_API int bpf_map_delete_elem(int fd, const void *key);
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
+4 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
	test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
	get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
	test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \
	test_sk_lookup_kern.o test_xdp_vlan.o
	test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o

# Order correspond to 'make run_tests' order
TEST_PROGS := test_kmod.sh \
@@ -118,6 +118,9 @@ CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \
$(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline
$(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline

$(OUTPUT)/test_queue_map.o: test_queue_stack_map.h
$(OUTPUT)/test_stack_map.o: test_queue_stack_map.h

BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris)
BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF)
BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm')
+7 −0
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@ static int (*bpf_map_update_elem)(void *map, void *key, void *value,
	(void *) BPF_FUNC_map_update_elem;
static int (*bpf_map_delete_elem)(void *map, void *key) =
	(void *) BPF_FUNC_map_delete_elem;
static int (*bpf_map_push_elem)(void *map, void *value,
				unsigned long long flags) =
	(void *) BPF_FUNC_map_push_elem;
static int (*bpf_map_pop_elem)(void *map, void *value) =
	(void *) BPF_FUNC_map_pop_elem;
static int (*bpf_map_peek_elem)(void *map, void *value) =
	(void *) BPF_FUNC_map_peek_elem;
static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
	(void *) BPF_FUNC_probe_read;
static unsigned long long (*bpf_ktime_get_ns)(void) =
+122 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>

#include <sys/wait.h>
#include <sys/socket.h>
@@ -471,6 +472,122 @@ static void test_devmap(int task, void *data)
	close(fd);
}

static void test_queuemap(int task, void *data)
{
	const int MAP_SIZE = 32;
	__u32 vals[MAP_SIZE + MAP_SIZE/2], val;
	int fd, i;

	/* Fill test values to be used */
	for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
		vals[i] = rand();

	/* Invalid key size */
	fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 4, sizeof(val), MAP_SIZE,
			    map_flags);
	assert(fd < 0 && errno == EINVAL);

	fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 0, sizeof(val), MAP_SIZE,
			    map_flags);
	/* Queue map does not support BPF_F_NO_PREALLOC */
	if (map_flags & BPF_F_NO_PREALLOC) {
		assert(fd < 0 && errno == EINVAL);
		return;
	}
	if (fd < 0) {
		printf("Failed to create queuemap '%s'!\n", strerror(errno));
		exit(1);
	}

	/* Push MAP_SIZE elements */
	for (i = 0; i < MAP_SIZE; i++)
		assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);

	/* Check that element cannot be pushed due to max_entries limit */
	assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 &&
	       errno == E2BIG);

	/* Peek element */
	assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]);

	/* Replace half elements */
	for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
		assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);

	/* Pop all elements */
	for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++)
		assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
		       val == vals[i]);

	/* Check that there are not elements left */
	assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 &&
	       errno == ENOENT);

	/* Check that non supported functions set errno to EINVAL */
	assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL);
	assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL);

	close(fd);
}

static void test_stackmap(int task, void *data)
{
	const int MAP_SIZE = 32;
	__u32 vals[MAP_SIZE + MAP_SIZE/2], val;
	int fd, i;

	/* Fill test values to be used */
	for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
		vals[i] = rand();

	/* Invalid key size */
	fd = bpf_create_map(BPF_MAP_TYPE_STACK, 4, sizeof(val), MAP_SIZE,
			    map_flags);
	assert(fd < 0 && errno == EINVAL);

	fd = bpf_create_map(BPF_MAP_TYPE_STACK, 0, sizeof(val), MAP_SIZE,
			    map_flags);
	/* Stack map does not support BPF_F_NO_PREALLOC */
	if (map_flags & BPF_F_NO_PREALLOC) {
		assert(fd < 0 && errno == EINVAL);
		return;
	}
	if (fd < 0) {
		printf("Failed to create stackmap '%s'!\n", strerror(errno));
		exit(1);
	}

	/* Push MAP_SIZE elements */
	for (i = 0; i < MAP_SIZE; i++)
		assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);

	/* Check that element cannot be pushed due to max_entries limit */
	assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 &&
	       errno == E2BIG);

	/* Peek element */
	assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]);

	/* Replace half elements */
	for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
		assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);

	/* Pop all elements */
	for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--)
		assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
		       val == vals[i]);

	/* Check that there are not elements left */
	assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 &&
	       errno == ENOENT);

	/* Check that non supported functions set errno to EINVAL */
	assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL);
	assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL);

	close(fd);
}

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
@@ -1434,10 +1551,15 @@ static void run_all_tests(void)
	test_map_wronly();

	test_reuseport_array();

	test_queuemap(0, NULL);
	test_stackmap(0, NULL);
}

int main(void)
{
	srand(time(NULL));

	map_flags = 0;
	run_all_tests();

Loading