1 // SPDX-License-Identifier: GPL-2.0 2 #include <arpa/inet.h> 3 #include <uapi/linux/bpf.h> 4 #include <linux/if_link.h> 5 #include <network_helpers.h> 6 #include <net/if.h> 7 #include <test_progs.h> 8 9 #include "test_xdp_devmap_helpers.skel.h" 10 #include "test_xdp_devmap_tailcall.skel.h" 11 #include "test_xdp_with_devmap_frags_helpers.skel.h" 12 #include "test_xdp_with_devmap_helpers.skel.h" 13 14 #define IFINDEX_LO 1 15 #define TEST_NS "devmap_attach_ns" 16 17 static void test_xdp_with_devmap_helpers(void) 18 { 19 struct test_xdp_with_devmap_helpers *skel = NULL; 20 struct bpf_prog_info info = {}; 21 struct bpf_devmap_val val = { 22 .ifindex = IFINDEX_LO, 23 }; 24 __u32 len = sizeof(info); 25 int err, dm_fd, dm_fd_redir, map_fd; 26 struct nstoken *nstoken = NULL; 27 char data[ETH_HLEN] = {}; 28 __u32 idx = 0; 29 30 SYS(out_close, "ip netns add %s", TEST_NS); 31 nstoken = open_netns(TEST_NS); 32 if (!ASSERT_OK_PTR(nstoken, "open_netns")) 33 goto out_close; 34 SYS(out_close, "ip link set dev lo up"); 35 36 skel = test_xdp_with_devmap_helpers__open_and_load(); 37 if (!ASSERT_OK_PTR(skel, "test_xdp_with_devmap_helpers__open_and_load")) 38 goto out_close; 39 40 dm_fd_redir = bpf_program__fd(skel->progs.xdp_redir_prog); 41 err = bpf_xdp_attach(IFINDEX_LO, dm_fd_redir, XDP_FLAGS_SKB_MODE, NULL); 42 if (!ASSERT_OK(err, "Generic attach of program with 8-byte devmap")) 43 goto out_close; 44 45 dm_fd = bpf_program__fd(skel->progs.xdp_dummy_dm); 46 map_fd = bpf_map__fd(skel->maps.dm_ports); 47 err = bpf_prog_get_info_by_fd(dm_fd, &info, &len); 48 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd")) 49 goto out_close; 50 51 val.bpf_prog.fd = dm_fd; 52 err = bpf_map_update_elem(map_fd, &idx, &val, 0); 53 ASSERT_OK(err, "Add program to devmap entry"); 54 55 err = bpf_map_lookup_elem(map_fd, &idx, &val); 56 ASSERT_OK(err, "Read devmap entry"); 57 ASSERT_EQ(info.id, val.bpf_prog.id, "Match program id to devmap entry prog_id"); 58 59 /* send a packet to trigger any potential bugs in there */ 60 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, 61 .data_in = &data, 62 .data_size_in = sizeof(data), 63 .flags = BPF_F_TEST_XDP_LIVE_FRAMES, 64 .repeat = 1, 65 ); 66 err = bpf_prog_test_run_opts(dm_fd_redir, &opts); 67 ASSERT_OK(err, "XDP test run"); 68 69 /* wait for the packets to be flushed */ 70 kern_sync_rcu(); 71 72 err = bpf_xdp_detach(IFINDEX_LO, XDP_FLAGS_SKB_MODE, NULL); 73 ASSERT_OK(err, "XDP program detach"); 74 75 /* can not attach BPF_XDP_DEVMAP program to a device */ 76 err = bpf_xdp_attach(IFINDEX_LO, dm_fd, XDP_FLAGS_SKB_MODE, NULL); 77 if (!ASSERT_NEQ(err, 0, "Attach of BPF_XDP_DEVMAP program")) 78 bpf_xdp_detach(IFINDEX_LO, XDP_FLAGS_SKB_MODE, NULL); 79 80 val.ifindex = 1; 81 val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_dummy_prog); 82 err = bpf_map_update_elem(map_fd, &idx, &val, 0); 83 ASSERT_NEQ(err, 0, "Add non-BPF_XDP_DEVMAP program to devmap entry"); 84 85 /* Try to attach BPF_XDP program with frags to devmap when we have 86 * already loaded a BPF_XDP program on the map 87 */ 88 idx = 1; 89 val.ifindex = 1; 90 val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_dummy_dm_frags); 91 err = bpf_map_update_elem(map_fd, &idx, &val, 0); 92 ASSERT_NEQ(err, 0, "Add BPF_XDP program with frags to devmap entry"); 93 94 out_close: 95 close_netns(nstoken); 96 SYS_NOFAIL("ip netns del %s", TEST_NS); 97 test_xdp_with_devmap_helpers__destroy(skel); 98 } 99 100 static void test_neg_xdp_devmap_helpers(void) 101 { 102 struct test_xdp_devmap_helpers *skel; 103 104 skel = test_xdp_devmap_helpers__open_and_load(); 105 if (!ASSERT_EQ(skel, NULL, 106 "Load of XDP program accessing egress ifindex without attach type")) { 107 test_xdp_devmap_helpers__destroy(skel); 108 } 109 } 110 111 static void test_xdp_devmap_tailcall(enum bpf_attach_type prog_dev, 112 enum bpf_attach_type prog_tail, 113 bool expect_reject) 114 { 115 struct test_xdp_devmap_tailcall *skel; 116 int err; 117 118 skel = test_xdp_devmap_tailcall__open(); 119 if (!ASSERT_OK_PTR(skel, "test_xdp_devmap_tailcall__open")) 120 return; 121 122 bpf_program__set_expected_attach_type(skel->progs.xdp_devmap, prog_dev); 123 bpf_program__set_expected_attach_type(skel->progs.xdp_entry, prog_tail); 124 125 err = test_xdp_devmap_tailcall__load(skel); 126 if (expect_reject) 127 ASSERT_ERR(err, "test_xdp_devmap_tailcall__load"); 128 else 129 ASSERT_OK(err, "test_xdp_devmap_tailcall__load"); 130 131 test_xdp_devmap_tailcall__destroy(skel); 132 } 133 134 static void test_xdp_with_devmap_frags_helpers(void) 135 { 136 struct test_xdp_with_devmap_frags_helpers *skel; 137 struct bpf_prog_info info = {}; 138 struct bpf_devmap_val val = { 139 .ifindex = IFINDEX_LO, 140 }; 141 __u32 len = sizeof(info); 142 int err, dm_fd_frags, map_fd; 143 __u32 idx = 0; 144 145 skel = test_xdp_with_devmap_frags_helpers__open_and_load(); 146 if (!ASSERT_OK_PTR(skel, "test_xdp_with_devmap_helpers__open_and_load")) 147 return; 148 149 dm_fd_frags = bpf_program__fd(skel->progs.xdp_dummy_dm_frags); 150 map_fd = bpf_map__fd(skel->maps.dm_ports); 151 err = bpf_prog_get_info_by_fd(dm_fd_frags, &info, &len); 152 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd")) 153 goto out_close; 154 155 val.bpf_prog.fd = dm_fd_frags; 156 err = bpf_map_update_elem(map_fd, &idx, &val, 0); 157 ASSERT_OK(err, "Add frags program to devmap entry"); 158 159 err = bpf_map_lookup_elem(map_fd, &idx, &val); 160 ASSERT_OK(err, "Read devmap entry"); 161 ASSERT_EQ(info.id, val.bpf_prog.id, 162 "Match program id to devmap entry prog_id"); 163 164 /* Try to attach BPF_XDP program to devmap when we have 165 * already loaded a BPF_XDP program with frags on the map 166 */ 167 idx = 1; 168 val.ifindex = 1; 169 val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_dummy_dm); 170 err = bpf_map_update_elem(map_fd, &idx, &val, 0); 171 ASSERT_NEQ(err, 0, "Add BPF_XDP program to devmap entry"); 172 173 out_close: 174 test_xdp_with_devmap_frags_helpers__destroy(skel); 175 } 176 177 static void test_xdp_with_devmap_helpers_veth(void) 178 { 179 struct test_xdp_with_devmap_helpers *skel = NULL; 180 struct bpf_prog_info info = {}; 181 struct bpf_devmap_val val = {}; 182 struct nstoken *nstoken = NULL; 183 __u32 len = sizeof(info); 184 int err, dm_fd, dm_fd_redir, map_fd, ifindex_dst; 185 char data[ETH_HLEN] = {}; 186 __u32 idx = 0; 187 188 SYS(out_close, "ip netns add %s", TEST_NS); 189 nstoken = open_netns(TEST_NS); 190 if (!ASSERT_OK_PTR(nstoken, "open_netns")) 191 goto out_close; 192 193 SYS(out_close, "ip link add veth_src type veth peer name veth_dst"); 194 SYS(out_close, "ip link set dev veth_src up"); 195 SYS(out_close, "ip link set dev veth_dst up"); 196 197 val.ifindex = if_nametoindex("veth_src"); 198 ifindex_dst = if_nametoindex("veth_dst"); 199 if (!ASSERT_NEQ(val.ifindex, 0, "val.ifindex") || 200 !ASSERT_NEQ(ifindex_dst, 0, "ifindex_dst")) 201 goto out_close; 202 203 skel = test_xdp_with_devmap_helpers__open_and_load(); 204 if (!ASSERT_OK_PTR(skel, "test_xdp_with_devmap_helpers__open_and_load")) 205 goto out_close; 206 207 dm_fd_redir = bpf_program__fd(skel->progs.xdp_redir_prog); 208 err = bpf_xdp_attach(val.ifindex, dm_fd_redir, XDP_FLAGS_DRV_MODE, NULL); 209 if (!ASSERT_OK(err, "Attach of program with 8-byte devmap")) 210 goto out_close; 211 212 dm_fd = bpf_program__fd(skel->progs.xdp_dummy_dm); 213 map_fd = bpf_map__fd(skel->maps.dm_ports); 214 err = bpf_prog_get_info_by_fd(dm_fd, &info, &len); 215 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd")) 216 goto out_close; 217 218 val.bpf_prog.fd = dm_fd; 219 err = bpf_map_update_elem(map_fd, &idx, &val, 0); 220 ASSERT_OK(err, "Add program to devmap entry"); 221 222 err = bpf_map_lookup_elem(map_fd, &idx, &val); 223 ASSERT_OK(err, "Read devmap entry"); 224 ASSERT_EQ(info.id, val.bpf_prog.id, "Match program id to devmap entry prog_id"); 225 226 /* attach dummy to other side to enable reception */ 227 dm_fd = bpf_program__fd(skel->progs.xdp_dummy_prog); 228 err = bpf_xdp_attach(ifindex_dst, dm_fd, XDP_FLAGS_DRV_MODE, NULL); 229 if (!ASSERT_OK(err, "Attach of dummy XDP")) 230 goto out_close; 231 232 /* send a packet to trigger any potential bugs in there */ 233 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, 234 .data_in = &data, 235 .data_size_in = sizeof(data), 236 .flags = BPF_F_TEST_XDP_LIVE_FRAMES, 237 .repeat = 1, 238 ); 239 err = bpf_prog_test_run_opts(dm_fd_redir, &opts); 240 ASSERT_OK(err, "XDP test run"); 241 242 /* wait for the packets to be flushed */ 243 kern_sync_rcu(); 244 245 err = bpf_xdp_detach(val.ifindex, XDP_FLAGS_DRV_MODE, NULL); 246 ASSERT_OK(err, "XDP program detach"); 247 248 err = bpf_xdp_detach(ifindex_dst, XDP_FLAGS_DRV_MODE, NULL); 249 ASSERT_OK(err, "XDP program detach"); 250 251 out_close: 252 close_netns(nstoken); 253 SYS_NOFAIL("ip netns del %s", TEST_NS); 254 test_xdp_with_devmap_helpers__destroy(skel); 255 } 256 257 void serial_test_xdp_devmap_attach(void) 258 { 259 if (test__start_subtest("DEVMAP with programs in entries")) 260 test_xdp_with_devmap_helpers(); 261 262 if (test__start_subtest("DEVMAP with frags programs in entries")) 263 test_xdp_with_devmap_frags_helpers(); 264 265 if (test__start_subtest("Verifier check of DEVMAP programs")) { 266 test_neg_xdp_devmap_helpers(); 267 test_xdp_devmap_tailcall(BPF_XDP_DEVMAP, BPF_XDP_DEVMAP, false); 268 test_xdp_devmap_tailcall(0, 0, true); 269 test_xdp_devmap_tailcall(BPF_XDP_DEVMAP, 0, true); 270 test_xdp_devmap_tailcall(0, BPF_XDP_DEVMAP, true); 271 } 272 273 if (test__start_subtest("DEVMAP with programs in entries on veth")) 274 test_xdp_with_devmap_helpers_veth(); 275 } 276