Skip to content

Commit

Permalink
selftests/bpf: Check inner map deletion
Browse files Browse the repository at this point in the history
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: Martynas Pumputis <m@lambda.lt>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20210719173838.423148-3-m@lambda.lt
  • Loading branch information
Martynas Pumputis authored and Andrii Nakryiko committed Jul 19, 2021
1 parent a21ab4c commit 08f71a1
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
26 changes: 26 additions & 0 deletions tools/testing/selftests/bpf/progs/test_map_in_map_invalid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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";
63 changes: 62 additions & 1 deletion tools/testing/selftests/bpf/test_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -1228,11 +1232,68 @@ 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:
close(fd);
if (fd >= 0)
close(fd);
exit(1);
}

Expand Down

0 comments on commit 08f71a1

Please sign in to comment.