187854a0bSToke Høiland-Jørgensen // SPDX-License-Identifier: GPL-2.0
287854a0bSToke Høiland-Jørgensen #include <test_progs.h>
3*7fedbf32SLeon Hwang #include "test_xdp_attach_fail.skel.h"
487854a0bSToke Høiland-Jørgensen 
587854a0bSToke Høiland-Jørgensen #define IFINDEX_LO 1
687854a0bSToke Høiland-Jørgensen #define XDP_FLAGS_REPLACE		(1U << 4)
787854a0bSToke Høiland-Jørgensen 
test_xdp_attach(const char * file)8cfa7b011SJoanne Koong static void test_xdp_attach(const char *file)
987854a0bSToke Høiland-Jørgensen {
10c6c11152SToke Høiland-Jørgensen 	__u32 duration = 0, id1, id2, id0 = 0, len;
1187854a0bSToke Høiland-Jørgensen 	struct bpf_object *obj1, *obj2, *obj3;
12c6c11152SToke Høiland-Jørgensen 	struct bpf_prog_info info = {};
1387854a0bSToke Høiland-Jørgensen 	int err, fd1, fd2, fd3;
14e4e284a8SAndrii Nakryiko 	LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
1587854a0bSToke Høiland-Jørgensen 
16c6c11152SToke Høiland-Jørgensen 	len = sizeof(info);
17c6c11152SToke Høiland-Jørgensen 
18cbdb1461SAndrii Nakryiko 	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj1, &fd1);
1987854a0bSToke Høiland-Jørgensen 	if (CHECK_FAIL(err))
2087854a0bSToke Høiland-Jørgensen 		return;
21c5a237a4SIlya Leoshkevich 	err = bpf_prog_get_info_by_fd(fd1, &info, &len);
22c6c11152SToke Høiland-Jørgensen 	if (CHECK_FAIL(err))
23c6c11152SToke Høiland-Jørgensen 		goto out_1;
24c6c11152SToke Høiland-Jørgensen 	id1 = info.id;
25c6c11152SToke Høiland-Jørgensen 
26cbdb1461SAndrii Nakryiko 	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj2, &fd2);
2787854a0bSToke Høiland-Jørgensen 	if (CHECK_FAIL(err))
2887854a0bSToke Høiland-Jørgensen 		goto out_1;
29c6c11152SToke Høiland-Jørgensen 
30c6c11152SToke Høiland-Jørgensen 	memset(&info, 0, sizeof(info));
31c5a237a4SIlya Leoshkevich 	err = bpf_prog_get_info_by_fd(fd2, &info, &len);
32c6c11152SToke Høiland-Jørgensen 	if (CHECK_FAIL(err))
33c6c11152SToke Høiland-Jørgensen 		goto out_2;
34c6c11152SToke Høiland-Jørgensen 	id2 = info.id;
35c6c11152SToke Høiland-Jørgensen 
36cbdb1461SAndrii Nakryiko 	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj3, &fd3);
3787854a0bSToke Høiland-Jørgensen 	if (CHECK_FAIL(err))
3887854a0bSToke Høiland-Jørgensen 		goto out_2;
3987854a0bSToke Høiland-Jørgensen 
40e4e284a8SAndrii Nakryiko 	err = bpf_xdp_attach(IFINDEX_LO, fd1, XDP_FLAGS_REPLACE, &opts);
4187854a0bSToke Høiland-Jørgensen 	if (CHECK(err, "load_ok", "initial load failed"))
4287854a0bSToke Høiland-Jørgensen 		goto out_close;
4387854a0bSToke Høiland-Jørgensen 
44e4e284a8SAndrii Nakryiko 	err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0);
45c6c11152SToke Høiland-Jørgensen 	if (CHECK(err || id0 != id1, "id1_check",
46c6c11152SToke Høiland-Jørgensen 		  "loaded prog id %u != id1 %u, err %d", id0, id1, err))
47c6c11152SToke Høiland-Jørgensen 		goto out_close;
48c6c11152SToke Høiland-Jørgensen 
49e4e284a8SAndrii Nakryiko 	err = bpf_xdp_attach(IFINDEX_LO, fd2, XDP_FLAGS_REPLACE, &opts);
5087854a0bSToke Høiland-Jørgensen 	if (CHECK(!err, "load_fail", "load with expected id didn't fail"))
5187854a0bSToke Høiland-Jørgensen 		goto out;
5287854a0bSToke Høiland-Jørgensen 
53e4e284a8SAndrii Nakryiko 	opts.old_prog_fd = fd1;
54e4e284a8SAndrii Nakryiko 	err = bpf_xdp_attach(IFINDEX_LO, fd2, 0, &opts);
5587854a0bSToke Høiland-Jørgensen 	if (CHECK(err, "replace_ok", "replace valid old_fd failed"))
5687854a0bSToke Høiland-Jørgensen 		goto out;
57e4e284a8SAndrii Nakryiko 	err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0);
58c6c11152SToke Høiland-Jørgensen 	if (CHECK(err || id0 != id2, "id2_check",
59c6c11152SToke Høiland-Jørgensen 		  "loaded prog id %u != id2 %u, err %d", id0, id2, err))
60c6c11152SToke Høiland-Jørgensen 		goto out_close;
6187854a0bSToke Høiland-Jørgensen 
62e4e284a8SAndrii Nakryiko 	err = bpf_xdp_attach(IFINDEX_LO, fd3, 0, &opts);
6387854a0bSToke Høiland-Jørgensen 	if (CHECK(!err, "replace_fail", "replace invalid old_fd didn't fail"))
6487854a0bSToke Høiland-Jørgensen 		goto out;
6587854a0bSToke Høiland-Jørgensen 
66e4e284a8SAndrii Nakryiko 	err = bpf_xdp_detach(IFINDEX_LO, 0, &opts);
6787854a0bSToke Høiland-Jørgensen 	if (CHECK(!err, "remove_fail", "remove invalid old_fd didn't fail"))
6887854a0bSToke Høiland-Jørgensen 		goto out;
6987854a0bSToke Høiland-Jørgensen 
70e4e284a8SAndrii Nakryiko 	opts.old_prog_fd = fd2;
71e4e284a8SAndrii Nakryiko 	err = bpf_xdp_detach(IFINDEX_LO, 0, &opts);
7287854a0bSToke Høiland-Jørgensen 	if (CHECK(err, "remove_ok", "remove valid old_fd failed"))
7387854a0bSToke Høiland-Jørgensen 		goto out;
7487854a0bSToke Høiland-Jørgensen 
75e4e284a8SAndrii Nakryiko 	err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0);
76c6c11152SToke Høiland-Jørgensen 	if (CHECK(err || id0 != 0, "unload_check",
77c6c11152SToke Høiland-Jørgensen 		  "loaded prog id %u != 0, err %d", id0, err))
78c6c11152SToke Høiland-Jørgensen 		goto out_close;
7987854a0bSToke Høiland-Jørgensen out:
80e4e284a8SAndrii Nakryiko 	bpf_xdp_detach(IFINDEX_LO, 0, NULL);
8187854a0bSToke Høiland-Jørgensen out_close:
8287854a0bSToke Høiland-Jørgensen 	bpf_object__close(obj3);
8387854a0bSToke Høiland-Jørgensen out_2:
8487854a0bSToke Høiland-Jørgensen 	bpf_object__close(obj2);
8587854a0bSToke Høiland-Jørgensen out_1:
8687854a0bSToke Høiland-Jørgensen 	bpf_object__close(obj1);
8787854a0bSToke Høiland-Jørgensen }
88cfa7b011SJoanne Koong 
89*7fedbf32SLeon Hwang #define ERRMSG_LEN 64
90*7fedbf32SLeon Hwang 
91*7fedbf32SLeon Hwang struct xdp_errmsg {
92*7fedbf32SLeon Hwang 	char msg[ERRMSG_LEN];
93*7fedbf32SLeon Hwang };
94*7fedbf32SLeon Hwang 
on_xdp_errmsg(void * ctx,int cpu,void * data,__u32 size)95*7fedbf32SLeon Hwang static void on_xdp_errmsg(void *ctx, int cpu, void *data, __u32 size)
96*7fedbf32SLeon Hwang {
97*7fedbf32SLeon Hwang 	struct xdp_errmsg *ctx_errmg = ctx, *tp_errmsg = data;
98*7fedbf32SLeon Hwang 
99*7fedbf32SLeon Hwang 	memcpy(&ctx_errmg->msg, &tp_errmsg->msg, ERRMSG_LEN);
100*7fedbf32SLeon Hwang }
101*7fedbf32SLeon Hwang 
102*7fedbf32SLeon Hwang static const char tgt_errmsg[] = "Invalid XDP flags for BPF link attachment";
103*7fedbf32SLeon Hwang 
test_xdp_attach_fail(const char * file)104*7fedbf32SLeon Hwang static void test_xdp_attach_fail(const char *file)
105*7fedbf32SLeon Hwang {
106*7fedbf32SLeon Hwang 	struct test_xdp_attach_fail *skel = NULL;
107*7fedbf32SLeon Hwang 	struct xdp_errmsg errmsg = {};
108*7fedbf32SLeon Hwang 	struct perf_buffer *pb = NULL;
109*7fedbf32SLeon Hwang 	struct bpf_object *obj = NULL;
110*7fedbf32SLeon Hwang 	int err, fd_xdp;
111*7fedbf32SLeon Hwang 
112*7fedbf32SLeon Hwang 	LIBBPF_OPTS(bpf_link_create_opts, opts);
113*7fedbf32SLeon Hwang 
114*7fedbf32SLeon Hwang 	skel = test_xdp_attach_fail__open_and_load();
115*7fedbf32SLeon Hwang 	if (!ASSERT_OK_PTR(skel, "test_xdp_attach_fail__open_and_load"))
116*7fedbf32SLeon Hwang 		goto out_close;
117*7fedbf32SLeon Hwang 
118*7fedbf32SLeon Hwang 	err = test_xdp_attach_fail__attach(skel);
119*7fedbf32SLeon Hwang 	if (!ASSERT_EQ(err, 0, "test_xdp_attach_fail__attach"))
120*7fedbf32SLeon Hwang 		goto out_close;
121*7fedbf32SLeon Hwang 
122*7fedbf32SLeon Hwang 	/* set up perf buffer */
123*7fedbf32SLeon Hwang 	pb = perf_buffer__new(bpf_map__fd(skel->maps.xdp_errmsg_pb), 1,
124*7fedbf32SLeon Hwang 			      on_xdp_errmsg, NULL, &errmsg, NULL);
125*7fedbf32SLeon Hwang 	if (!ASSERT_OK_PTR(pb, "perf_buffer__new"))
126*7fedbf32SLeon Hwang 		goto out_close;
127*7fedbf32SLeon Hwang 
128*7fedbf32SLeon Hwang 	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &fd_xdp);
129*7fedbf32SLeon Hwang 	if (!ASSERT_EQ(err, 0, "bpf_prog_test_load"))
130*7fedbf32SLeon Hwang 		goto out_close;
131*7fedbf32SLeon Hwang 
132*7fedbf32SLeon Hwang 	opts.flags = 0xFF; // invalid flags to fail to attach XDP prog
133*7fedbf32SLeon Hwang 	err = bpf_link_create(fd_xdp, IFINDEX_LO, BPF_XDP, &opts);
134*7fedbf32SLeon Hwang 	if (!ASSERT_EQ(err, -EINVAL, "bpf_link_create"))
135*7fedbf32SLeon Hwang 		goto out_close;
136*7fedbf32SLeon Hwang 
137*7fedbf32SLeon Hwang 	/* read perf buffer */
138*7fedbf32SLeon Hwang 	err = perf_buffer__poll(pb, 100);
139*7fedbf32SLeon Hwang 	if (!ASSERT_GT(err, -1, "perf_buffer__poll"))
140*7fedbf32SLeon Hwang 		goto out_close;
141*7fedbf32SLeon Hwang 
142*7fedbf32SLeon Hwang 	ASSERT_STRNEQ((const char *) errmsg.msg, tgt_errmsg,
143*7fedbf32SLeon Hwang 		      42 /* strlen(tgt_errmsg) */, "check error message");
144*7fedbf32SLeon Hwang 
145*7fedbf32SLeon Hwang out_close:
146*7fedbf32SLeon Hwang 	perf_buffer__free(pb);
147*7fedbf32SLeon Hwang 	bpf_object__close(obj);
148*7fedbf32SLeon Hwang 	test_xdp_attach_fail__destroy(skel);
149*7fedbf32SLeon Hwang }
150*7fedbf32SLeon Hwang 
serial_test_xdp_attach(void)151cfa7b011SJoanne Koong void serial_test_xdp_attach(void)
152cfa7b011SJoanne Koong {
153cfa7b011SJoanne Koong 	if (test__start_subtest("xdp_attach"))
154cfa7b011SJoanne Koong 		test_xdp_attach("./test_xdp.bpf.o");
155cfa7b011SJoanne Koong 	if (test__start_subtest("xdp_attach_dynptr"))
156cfa7b011SJoanne Koong 		test_xdp_attach("./test_xdp_dynptr.bpf.o");
157*7fedbf32SLeon Hwang 	if (test__start_subtest("xdp_attach_failed"))
158*7fedbf32SLeon Hwang 		test_xdp_attach_fail("./xdp_dummy.bpf.o");
159cfa7b011SJoanne Koong }
160