1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright 2020 Google LLC.
5 */
6
7#include <test_progs.h>
8#include <cgroup_helpers.h>
9#include <network_helpers.h>
10
11#include "metadata_unused.skel.h"
12#include "metadata_used.skel.h"
13
14static int duration;
15
16static int prog_holds_map(int prog_fd, int map_fd)
17{
18	struct bpf_prog_info prog_info = {};
19	struct bpf_map_info map_info = {};
20	__u32 prog_info_len;
21	__u32 map_info_len;
22	__u32 *map_ids;
23	int nr_maps;
24	int ret;
25	int i;
26
27	map_info_len = sizeof(map_info);
28	ret = bpf_map_get_info_by_fd(map_fd, &map_info, &map_info_len);
29	if (ret)
30		return -errno;
31
32	prog_info_len = sizeof(prog_info);
33	ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
34	if (ret)
35		return -errno;
36
37	map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32));
38	if (!map_ids)
39		return -ENOMEM;
40
41	nr_maps = prog_info.nr_map_ids;
42	memset(&prog_info, 0, sizeof(prog_info));
43	prog_info.nr_map_ids = nr_maps;
44	prog_info.map_ids = ptr_to_u64(map_ids);
45	prog_info_len = sizeof(prog_info);
46
47	ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
48	if (ret) {
49		ret = -errno;
50		goto free_map_ids;
51	}
52
53	ret = -ENOENT;
54	for (i = 0; i < prog_info.nr_map_ids; i++) {
55		if (map_ids[i] == map_info.id) {
56			ret = 0;
57			break;
58		}
59	}
60
61free_map_ids:
62	free(map_ids);
63	return ret;
64}
65
66static void test_metadata_unused(void)
67{
68	struct metadata_unused *obj;
69	int err;
70
71	obj = metadata_unused__open_and_load();
72	if (CHECK(!obj, "skel-load", "errno %d", errno))
73		return;
74
75	err = prog_holds_map(bpf_program__fd(obj->progs.prog),
76			     bpf_map__fd(obj->maps.rodata));
77	if (CHECK(err, "prog-holds-rodata", "errno: %d", err))
78		return;
79
80	/* Assert that we can access the metadata in skel and the values are
81	 * what we expect.
82	 */
83	if (CHECK(strncmp(obj->rodata->bpf_metadata_a, "foo",
84			  sizeof(obj->rodata->bpf_metadata_a)),
85		  "bpf_metadata_a", "expected \"foo\", value differ"))
86		goto close_bpf_object;
87	if (CHECK(obj->rodata->bpf_metadata_b != 1, "bpf_metadata_b",
88		  "expected 1, got %d", obj->rodata->bpf_metadata_b))
89		goto close_bpf_object;
90
91	/* Assert that binding metadata map to prog again succeeds. */
92	err = bpf_prog_bind_map(bpf_program__fd(obj->progs.prog),
93				bpf_map__fd(obj->maps.rodata), NULL);
94	CHECK(err, "rebind_map", "errno %d, expected 0", errno);
95
96close_bpf_object:
97	metadata_unused__destroy(obj);
98}
99
100static void test_metadata_used(void)
101{
102	struct metadata_used *obj;
103	int err;
104
105	obj = metadata_used__open_and_load();
106	if (CHECK(!obj, "skel-load", "errno %d", errno))
107		return;
108
109	err = prog_holds_map(bpf_program__fd(obj->progs.prog),
110			     bpf_map__fd(obj->maps.rodata));
111	if (CHECK(err, "prog-holds-rodata", "errno: %d", err))
112		return;
113
114	/* Assert that we can access the metadata in skel and the values are
115	 * what we expect.
116	 */
117	if (CHECK(strncmp(obj->rodata->bpf_metadata_a, "bar",
118			  sizeof(obj->rodata->bpf_metadata_a)),
119		  "metadata_a", "expected \"bar\", value differ"))
120		goto close_bpf_object;
121	if (CHECK(obj->rodata->bpf_metadata_b != 2, "metadata_b",
122		  "expected 2, got %d", obj->rodata->bpf_metadata_b))
123		goto close_bpf_object;
124
125	/* Assert that binding metadata map to prog again succeeds. */
126	err = bpf_prog_bind_map(bpf_program__fd(obj->progs.prog),
127				bpf_map__fd(obj->maps.rodata), NULL);
128	CHECK(err, "rebind_map", "errno %d, expected 0", errno);
129
130close_bpf_object:
131	metadata_used__destroy(obj);
132}
133
134void test_metadata(void)
135{
136	if (test__start_subtest("unused"))
137		test_metadata_unused();
138
139	if (test__start_subtest("used"))
140		test_metadata_used();
141}
142