bpf.c 6.4 KB
Newer Older
W
Wang Nan 已提交
1 2
#include <stdio.h>
#include <sys/epoll.h>
3
#include <util/util.h>
W
Wang Nan 已提交
4 5
#include <util/bpf-loader.h>
#include <util/evlist.h>
6 7 8
#include <linux/bpf.h>
#include <linux/filter.h>
#include <bpf/bpf.h>
W
Wang Nan 已提交
9 10 11 12 13 14 15
#include "tests.h"
#include "llvm.h"
#include "debug.h"
#define NR_ITERS       111

#ifdef HAVE_LIBBPF_SUPPORT

16
static int epoll_wait_loop(void)
W
Wang Nan 已提交
17 18 19 20 21
{
	int i;

	/* Should fail NR_ITERS times */
	for (i = 0; i < NR_ITERS; i++)
22
		epoll_wait(-(i + 1), NULL, 0, 0);
W
Wang Nan 已提交
23 24 25
	return 0;
}

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#ifdef HAVE_BPF_PROLOGUE

static int llseek_loop(void)
{
	int fds[2], i;

	fds[0] = open("/dev/null", O_RDONLY);
	fds[1] = open("/dev/null", O_RDWR);

	if (fds[0] < 0 || fds[1] < 0)
		return -1;

	for (i = 0; i < NR_ITERS; i++) {
		lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
		lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
	}
	close(fds[0]);
	close(fds[1]);
	return 0;
}

#endif

W
Wang Nan 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
static struct {
	enum test_llvm__testcase prog_id;
	const char *desc;
	const char *name;
	const char *msg_compile_fail;
	const char *msg_load_fail;
	int (*target_func)(void);
	int expect_result;
} bpf_testcase_table[] = {
	{
		LLVM_TESTCASE_BASE,
		"Test basic BPF filtering",
		"[basic_bpf_test]",
		"fix 'perf test LLVM' first",
		"load bpf object failed",
64
		&epoll_wait_loop,
W
Wang Nan 已提交
65 66
		(NR_ITERS + 1) / 2,
	},
67 68 69 70 71 72 73 74 75 76 77
#ifdef HAVE_BPF_PROLOGUE
	{
		LLVM_TESTCASE_BPF_PROLOGUE,
		"Test BPF prologue generation",
		"[bpf_prologue_test]",
		"fix kbuild first",
		"check your vmlinux setting?",
		&llseek_loop,
		(NR_ITERS + 1) / 4,
	},
#endif
78 79 80 81 82 83 84 85 86
	{
		LLVM_TESTCASE_BPF_RELOCATION,
		"Test BPF relocation checker",
		"[bpf_relocation_test]",
		"fix 'perf test LLVM' first",
		"libbpf error when dealing with relocation",
		NULL,
		0,
	},
W
Wang Nan 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
};

static int do_test(struct bpf_object *obj, int (*func)(void),
		   int expect)
{
	struct record_opts opts = {
		.target = {
			.uid = UINT_MAX,
			.uses_mmap = true,
		},
		.freq	      = 0,
		.mmap_pages   = 256,
		.default_interval = 1,
	};

	char pid[16];
	char sbuf[STRERR_BUFSIZE];
	struct perf_evlist *evlist;
	int i, ret = TEST_FAIL, err = 0, count = 0;

	struct parse_events_evlist parse_evlist;
	struct parse_events_error parse_error;

	bzero(&parse_error, sizeof(parse_error));
	bzero(&parse_evlist, sizeof(parse_evlist));
	parse_evlist.error = &parse_error;
	INIT_LIST_HEAD(&parse_evlist.list);

115
	err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj, NULL);
W
Wang Nan 已提交
116 117
	if (err || list_empty(&parse_evlist.list)) {
		pr_debug("Failed to add events selected by BPF\n");
118
		return TEST_FAIL;
W
Wang Nan 已提交
119 120 121 122 123 124 125 126 127
	}

	snprintf(pid, sizeof(pid), "%d", getpid());
	pid[sizeof(pid) - 1] = '\0';
	opts.target.tid = opts.target.pid = pid;

	/* Instead of perf_evlist__new_default, don't add default events */
	evlist = perf_evlist__new();
	if (!evlist) {
128
		pr_debug("Not enough memory to create evlist\n");
W
Wang Nan 已提交
129 130 131 132 133 134 135 136 137 138 139 140
		return TEST_FAIL;
	}

	err = perf_evlist__create_maps(evlist, &opts.target);
	if (err < 0) {
		pr_debug("Not enough memory to create thread/cpu maps\n");
		goto out_delete_evlist;
	}

	perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
	evlist->nr_groups = parse_evlist.nr_groups;

141
	perf_evlist__config(evlist, &opts, NULL);
W
Wang Nan 已提交
142 143 144 145

	err = perf_evlist__open(evlist);
	if (err < 0) {
		pr_debug("perf_evlist__open: %s\n",
146
			 str_error_r(errno, sbuf, sizeof(sbuf)));
W
Wang Nan 已提交
147 148 149 150 151 152
		goto out_delete_evlist;
	}

	err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
	if (err < 0) {
		pr_debug("perf_evlist__mmap: %s\n",
153
			 str_error_r(errno, sbuf, sizeof(sbuf)));
W
Wang Nan 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
		goto out_delete_evlist;
	}

	perf_evlist__enable(evlist);
	(*func)();
	perf_evlist__disable(evlist);

	for (i = 0; i < evlist->nr_mmaps; i++) {
		union perf_event *event;

		while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
			const u32 type = event->header.type;

			if (type == PERF_RECORD_SAMPLE)
				count ++;
		}
	}

172
	if (count != expect) {
W
Wang Nan 已提交
173
		pr_debug("BPF filter result incorrect\n");
174 175
		goto out_delete_evlist;
	}
W
Wang Nan 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

	ret = TEST_OK;

out_delete_evlist:
	perf_evlist__delete(evlist);
	return ret;
}

static struct bpf_object *
prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
{
	struct bpf_object *obj;

	obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
	if (IS_ERR(obj)) {
		pr_debug("Compile BPF program failed.\n");
		return NULL;
	}
	return obj;
}

197
static int __test__bpf(int idx)
W
Wang Nan 已提交
198 199 200 201 202 203 204
{
	int ret;
	void *obj_buf;
	size_t obj_buf_sz;
	struct bpf_object *obj;

	ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
205
				       bpf_testcase_table[idx].prog_id,
206
				       true, NULL);
W
Wang Nan 已提交
207 208
	if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
		pr_debug("Unable to get BPF object, %s\n",
209 210
			 bpf_testcase_table[idx].msg_compile_fail);
		if (idx == 0)
W
Wang Nan 已提交
211 212 213 214 215 216
			return TEST_SKIP;
		else
			return TEST_FAIL;
	}

	obj = prepare_bpf(obj_buf, obj_buf_sz,
217
			  bpf_testcase_table[idx].name);
218 219 220 221 222 223 224
	if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
		if (!obj)
			pr_debug("Fail to load BPF object: %s\n",
				 bpf_testcase_table[idx].msg_load_fail);
		else
			pr_debug("Success unexpectedly: %s\n",
				 bpf_testcase_table[idx].msg_load_fail);
W
Wang Nan 已提交
225 226 227 228
		ret = TEST_FAIL;
		goto out;
	}

229 230 231 232
	if (obj)
		ret = do_test(obj,
			      bpf_testcase_table[idx].target_func,
			      bpf_testcase_table[idx].expect_result);
W
Wang Nan 已提交
233 234 235 236 237
out:
	bpf__clear();
	return ret;
}

238 239 240 241 242 243 244 245 246 247 248 249
int test__bpf_subtest_get_nr(void)
{
	return (int)ARRAY_SIZE(bpf_testcase_table);
}

const char *test__bpf_subtest_get_desc(int i)
{
	if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
		return NULL;
	return bpf_testcase_table[i].desc;
}

250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
static int check_env(void)
{
	int err;
	unsigned int kver_int;
	char license[] = "GPL";

	struct bpf_insn insns[] = {
		BPF_MOV64_IMM(BPF_REG_0, 1),
		BPF_EXIT_INSN(),
	};

	err = fetch_kernel_version(&kver_int, NULL, 0);
	if (err) {
		pr_debug("Unable to get kernel version\n");
		return err;
	}

	err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
			       sizeof(insns) / sizeof(insns[0]),
			       license, kver_int, NULL, 0);
	if (err < 0) {
		pr_err("Missing basic BPF support, skip this test: %s\n",
		       strerror(errno));
		return err;
	}
	close(err);

	return 0;
}

280
int test__bpf(int i)
W
Wang Nan 已提交
281 282 283
{
	int err;

284 285 286
	if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
		return TEST_FAIL;

W
Wang Nan 已提交
287 288 289 290 291
	if (geteuid() != 0) {
		pr_debug("Only root can run BPF test\n");
		return TEST_SKIP;
	}

292 293 294
	if (check_env())
		return TEST_SKIP;

295 296 297
	err = __test__bpf(i);
	return err;
}
W
Wang Nan 已提交
298

299 300 301 302 303
#else
int test__bpf_subtest_get_nr(void)
{
	return 0;
}
W
Wang Nan 已提交
304

305 306 307
const char *test__bpf_subtest_get_desc(int i __maybe_unused)
{
	return NULL;
W
Wang Nan 已提交
308 309
}

310
int test__bpf(int i __maybe_unused)
W
Wang Nan 已提交
311 312 313 314 315
{
	pr_debug("Skip BPF test because BPF support is not compiled\n");
	return TEST_SKIP;
}
#endif