1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include "test_xdp_attach_fail.skel.h" 4 5 #define IFINDEX_LO 1 6 #define XDP_FLAGS_REPLACE (1U << 4) 7 8 static void test_xdp_attach(const char *file) 9 { 10 __u32 duration = 0, id1, id2, id0 = 0, len; 11 struct bpf_object *obj1, *obj2, *obj3; 12 struct bpf_prog_info info = {}; 13 int err, fd1, fd2, fd3; 14 LIBBPF_OPTS(bpf_xdp_attach_opts, opts); 15 16 len = sizeof(info); 17 18 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj1, &fd1); 19 if (CHECK_FAIL(err)) 20 return; 21 err = bpf_prog_get_info_by_fd(fd1, &info, &len); 22 if (CHECK_FAIL(err)) 23 goto out_1; 24 id1 = info.id; 25 26 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj2, &fd2); 27 if (CHECK_FAIL(err)) 28 goto out_1; 29 30 memset(&info, 0, sizeof(info)); 31 err = bpf_prog_get_info_by_fd(fd2, &info, &len); 32 if (CHECK_FAIL(err)) 33 goto out_2; 34 id2 = info.id; 35 36 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj3, &fd3); 37 if (CHECK_FAIL(err)) 38 goto out_2; 39 40 err = bpf_xdp_attach(IFINDEX_LO, fd1, XDP_FLAGS_REPLACE, &opts); 41 if (CHECK(err, "load_ok", "initial load failed")) 42 goto out_close; 43 44 err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0); 45 if (CHECK(err || id0 != id1, "id1_check", 46 "loaded prog id %u != id1 %u, err %d", id0, id1, err)) 47 goto out_close; 48 49 err = bpf_xdp_attach(IFINDEX_LO, fd2, XDP_FLAGS_REPLACE, &opts); 50 if (CHECK(!err, "load_fail", "load with expected id didn't fail")) 51 goto out; 52 53 opts.old_prog_fd = fd1; 54 err = bpf_xdp_attach(IFINDEX_LO, fd2, 0, &opts); 55 if (CHECK(err, "replace_ok", "replace valid old_fd failed")) 56 goto out; 57 err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0); 58 if (CHECK(err || id0 != id2, "id2_check", 59 "loaded prog id %u != id2 %u, err %d", id0, id2, err)) 60 goto out_close; 61 62 err = bpf_xdp_attach(IFINDEX_LO, fd3, 0, &opts); 63 if (CHECK(!err, "replace_fail", "replace invalid old_fd didn't fail")) 64 goto out; 65 66 err = bpf_xdp_detach(IFINDEX_LO, 0, &opts); 67 if (CHECK(!err, "remove_fail", "remove invalid old_fd didn't fail")) 68 goto out; 69 70 opts.old_prog_fd = fd2; 71 err = bpf_xdp_detach(IFINDEX_LO, 0, &opts); 72 if (CHECK(err, "remove_ok", "remove valid old_fd failed")) 73 goto out; 74 75 err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0); 76 if (CHECK(err || id0 != 0, "unload_check", 77 "loaded prog id %u != 0, err %d", id0, err)) 78 goto out_close; 79 out: 80 bpf_xdp_detach(IFINDEX_LO, 0, NULL); 81 out_close: 82 bpf_object__close(obj3); 83 out_2: 84 bpf_object__close(obj2); 85 out_1: 86 bpf_object__close(obj1); 87 } 88 89 #define ERRMSG_LEN 64 90 91 struct xdp_errmsg { 92 char msg[ERRMSG_LEN]; 93 }; 94 95 static void on_xdp_errmsg(void *ctx, int cpu, void *data, __u32 size) 96 { 97 struct xdp_errmsg *ctx_errmg = ctx, *tp_errmsg = data; 98 99 memcpy(&ctx_errmg->msg, &tp_errmsg->msg, ERRMSG_LEN); 100 } 101 102 static const char tgt_errmsg[] = "Invalid XDP flags for BPF link attachment"; 103 104 static void test_xdp_attach_fail(const char *file) 105 { 106 struct test_xdp_attach_fail *skel = NULL; 107 struct xdp_errmsg errmsg = {}; 108 struct perf_buffer *pb = NULL; 109 struct bpf_object *obj = NULL; 110 int err, fd_xdp; 111 112 LIBBPF_OPTS(bpf_link_create_opts, opts); 113 114 skel = test_xdp_attach_fail__open_and_load(); 115 if (!ASSERT_OK_PTR(skel, "test_xdp_attach_fail__open_and_load")) 116 goto out_close; 117 118 err = test_xdp_attach_fail__attach(skel); 119 if (!ASSERT_EQ(err, 0, "test_xdp_attach_fail__attach")) 120 goto out_close; 121 122 /* set up perf buffer */ 123 pb = perf_buffer__new(bpf_map__fd(skel->maps.xdp_errmsg_pb), 1, 124 on_xdp_errmsg, NULL, &errmsg, NULL); 125 if (!ASSERT_OK_PTR(pb, "perf_buffer__new")) 126 goto out_close; 127 128 err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &fd_xdp); 129 if (!ASSERT_EQ(err, 0, "bpf_prog_test_load")) 130 goto out_close; 131 132 opts.flags = 0xFF; // invalid flags to fail to attach XDP prog 133 err = bpf_link_create(fd_xdp, IFINDEX_LO, BPF_XDP, &opts); 134 if (!ASSERT_EQ(err, -EINVAL, "bpf_link_create")) 135 goto out_close; 136 137 /* read perf buffer */ 138 err = perf_buffer__poll(pb, 100); 139 if (!ASSERT_GT(err, -1, "perf_buffer__poll")) 140 goto out_close; 141 142 ASSERT_STRNEQ((const char *) errmsg.msg, tgt_errmsg, 143 42 /* strlen(tgt_errmsg) */, "check error message"); 144 145 out_close: 146 perf_buffer__free(pb); 147 bpf_object__close(obj); 148 test_xdp_attach_fail__destroy(skel); 149 } 150 151 void serial_test_xdp_attach(void) 152 { 153 if (test__start_subtest("xdp_attach")) 154 test_xdp_attach("./test_xdp.bpf.o"); 155 if (test__start_subtest("xdp_attach_dynptr")) 156 test_xdp_attach("./test_xdp_dynptr.bpf.o"); 157 if (test__start_subtest("xdp_attach_failed")) 158 test_xdp_attach_fail("./xdp_dummy.bpf.o"); 159 } 160