Commit 08f71a1e authored by Martynas Pumputis's avatar Martynas Pumputis Committed by Andrii Nakryiko
Browse files

selftests/bpf: Check inner map deletion



Add a test case to check whether an unsuccessful creation of an outer
map of a BTF-defined map-in-map destroys the inner map.

As bpf_object__create_map() is a static function, we cannot just call it
from the test case and then check whether a map accessible via
map->inner_map_fd has been closed. Instead, we iterate over all maps and
check whether the map "$MAP_NAME.inner" does not exist.

Signed-off-by: default avatarMartynas Pumputis <m@lambda.lt>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20210719173838.423148-3-m@lambda.lt
parent a21ab4c5
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021 Isovalent, Inc. */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct inner {
	__uint(type, BPF_MAP_TYPE_ARRAY);
	__type(key, __u32);
	__type(value, int);
	__uint(max_entries, 4);
};

struct {
	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
	__uint(max_entries, 0); /* This will make map creation to fail */
	__uint(key_size, sizeof(__u32));
	__array(values, struct inner);
} mim SEC(".maps");

SEC("xdp")
int xdp_noop0(struct xdp_md *ctx)
{
	return XDP_PASS;
}

char _license[] SEC("license") = "GPL";
+62 −1
Original line number Diff line number Diff line
@@ -1153,12 +1153,16 @@ static void test_sockmap(unsigned int tasks, void *data)
}

#define MAPINMAP_PROG "./test_map_in_map.o"
#define MAPINMAP_INVALID_PROG "./test_map_in_map_invalid.o"
static void test_map_in_map(void)
{
	struct bpf_object *obj;
	struct bpf_map *map;
	int mim_fd, fd, err;
	int pos = 0;
	struct bpf_map_info info = {};
	__u32 len = sizeof(info);
	__u32 id = 0;

	obj = bpf_object__open(MAPINMAP_PROG);

@@ -1228,10 +1232,67 @@ static void test_map_in_map(void)
	}

	close(fd);
	fd = -1;
	bpf_object__close(obj);

	/* Test that failing bpf_object__create_map() destroys the inner map */
	obj = bpf_object__open(MAPINMAP_INVALID_PROG);
	err = libbpf_get_error(obj);
	if (err) {
		printf("Failed to load %s program: %d %d",
		       MAPINMAP_INVALID_PROG, err, errno);
		goto out_map_in_map;
	}

	map = bpf_object__find_map_by_name(obj, "mim");
	if (!map) {
		printf("Failed to load array of maps from test prog\n");
		goto out_map_in_map;
	}

	err = bpf_object__load(obj);
	if (!err) {
		printf("Loading obj supposed to fail\n");
		goto out_map_in_map;
	}

	/* Iterate over all maps to check whether the internal map
	 * ("mim.internal") has been destroyed.
	 */
	while (true) {
		err = bpf_map_get_next_id(id, &id);
		if (err) {
			if (errno == ENOENT)
				break;
			printf("Failed to get next map: %d", errno);
			goto out_map_in_map;
		}

		fd = bpf_map_get_fd_by_id(id);
		if (fd < 0) {
			if (errno == ENOENT)
				continue;
			printf("Failed to get map by id %u: %d", id, errno);
			goto out_map_in_map;
		}

		err = bpf_obj_get_info_by_fd(fd, &info, &len);
		if (err) {
			printf("Failed to get map info by fd %d: %d", fd,
			       errno);
			goto out_map_in_map;
		}

		if (!strcmp(info.name, "mim.inner")) {
			printf("Inner map mim.inner was not destroyed\n");
			goto out_map_in_map;
		}
	}

	return;

out_map_in_map:
	if (fd >= 0)
		close(fd);
	exit(1);
}