1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | /* Create 3 namespaces with 3 veth peers, and forward packets in-between using |
4 | * native XDP |
5 | * |
6 | * Network topology: |
7 | * ---------- ---------- ---------- |
8 | * | NS1 | | NS2 | | NS3 | |
9 | * | veth11 | | veth22 | | veth33 | |
10 | * ----|----- -----|---- -----|---- |
11 | * | | | |
12 | * ----|------------------|----------------|---- |
13 | * | veth1 veth2 veth3 | |
14 | * | | |
15 | * | NSO | |
16 | * --------------------------------------------- |
17 | * |
18 | * Test cases: |
19 | * - [test_xdp_veth_redirect] : ping veth33 from veth11 |
20 | * |
21 | * veth11 veth22 veth33 |
22 | * (XDP_PASS) (XDP_TX) (XDP_PASS) |
23 | * | | | |
24 | * | | | |
25 | * veth1 veth2 veth3 |
26 | * (XDP_REDIRECT) (XDP_REDIRECT) (XDP_REDIRECT) |
27 | * ^ | ^ | ^ | |
28 | * | | | | | | |
29 | * | ------------------ ------------------ | |
30 | * ----------------------------------------- |
31 | * |
32 | * - [test_xdp_veth_broadcast_redirect]: broadcast from veth11 |
33 | * - IPv4 ping : BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS |
34 | * -> echo request received by all except veth11 |
35 | * - IPv4 ping : BPF_F_BROADCAST |
36 | * -> echo request received by all veth |
37 | * - [test_xdp_veth_egress]: |
38 | * - all src mac should be the magic mac |
39 | * |
40 | * veth11 veth22 veth33 |
41 | * (XDP_PASS) (XDP_PASS) (XDP_PASS) |
42 | * | | | |
43 | * | | | |
44 | * veth1 veth2 veth3 |
45 | * (XDP_REDIRECT) (XDP_REDIRECT) (XDP_REDIRECT) |
46 | * | ^ ^ |
47 | * | | | |
48 | * ---------------------------------------- |
49 | * |
50 | */ |
51 | |
52 | #define _GNU_SOURCE |
53 | #include <net/if.h> |
54 | #include "test_progs.h" |
55 | #include "network_helpers.h" |
56 | #include "xdp_dummy.skel.h" |
57 | #include "xdp_redirect_map.skel.h" |
58 | #include "xdp_redirect_multi_kern.skel.h" |
59 | #include "xdp_tx.skel.h" |
60 | #include <uapi/linux/if_link.h> |
61 | |
62 | #define VETH_PAIRS_COUNT 3 |
63 | #define VETH_NAME_MAX_LEN 32 |
64 | #define IP_MAX_LEN 16 |
65 | #define IP_SRC "10.1.1.11" |
66 | #define IP_DST "10.1.1.33" |
67 | #define IP_NEIGH "10.1.1.253" |
68 | #define PROG_NAME_MAX_LEN 128 |
69 | #define NS_NAME_MAX_LEN 32 |
70 | |
71 | struct veth_configuration { |
72 | char local_veth[VETH_NAME_MAX_LEN]; /* Interface in main namespace */ |
73 | char remote_veth[VETH_NAME_MAX_LEN]; /* Peer interface in dedicated namespace*/ |
74 | char namespace[NS_NAME_MAX_LEN]; /* Namespace for the remote veth */ |
75 | int next_veth; /* Local interface to redirect traffic to */ |
76 | char remote_addr[IP_MAX_LEN]; /* IP address of the remote veth */ |
77 | }; |
78 | |
79 | struct net_configuration { |
80 | char ns0_name[NS_NAME_MAX_LEN]; |
81 | struct veth_configuration veth_cfg[VETH_PAIRS_COUNT]; |
82 | }; |
83 | |
84 | static const struct net_configuration default_config = { |
85 | .ns0_name = "ns0-" , |
86 | { |
87 | { |
88 | .local_veth = "veth1-" , |
89 | .remote_veth = "veth11" , |
90 | .next_veth = 1, |
91 | .remote_addr = IP_SRC, |
92 | .namespace = "ns-veth11-" |
93 | }, |
94 | { |
95 | .local_veth = "veth2-" , |
96 | .remote_veth = "veth22" , |
97 | .next_veth = 2, |
98 | .remote_addr = "" , |
99 | .namespace = "ns-veth22-" |
100 | }, |
101 | { |
102 | .local_veth = "veth3-" , |
103 | .remote_veth = "veth33" , |
104 | .next_veth = 0, |
105 | .remote_addr = IP_DST, |
106 | .namespace = "ns-veth33-" |
107 | } |
108 | } |
109 | }; |
110 | |
111 | struct prog_configuration { |
112 | char local_name[PROG_NAME_MAX_LEN]; /* BPF prog to attach to local_veth */ |
113 | char remote_name[PROG_NAME_MAX_LEN]; /* BPF prog to attach to remote_veth */ |
114 | u32 local_flags; /* XDP flags to use on local_veth */ |
115 | u32 remote_flags; /* XDP flags to use on remote_veth */ |
116 | }; |
117 | |
118 | static int attach_programs_to_veth_pair(struct bpf_object **objs, size_t nb_obj, |
119 | struct net_configuration *net_config, |
120 | struct prog_configuration *prog, int index) |
121 | { |
122 | struct bpf_program *local_prog, *remote_prog; |
123 | struct nstoken *nstoken; |
124 | int interface, ret, i; |
125 | |
126 | for (i = 0; i < nb_obj; i++) { |
127 | local_prog = bpf_object__find_program_by_name(objs[i], prog[index].local_name); |
128 | if (local_prog) |
129 | break; |
130 | } |
131 | if (!ASSERT_OK_PTR(local_prog, "find local program" )) |
132 | return -1; |
133 | |
134 | for (i = 0; i < nb_obj; i++) { |
135 | remote_prog = bpf_object__find_program_by_name(objs[i], prog[index].remote_name); |
136 | if (remote_prog) |
137 | break; |
138 | } |
139 | if (!ASSERT_OK_PTR(remote_prog, "find remote program" )) |
140 | return -1; |
141 | |
142 | interface = if_nametoindex(net_config->veth_cfg[index].local_veth); |
143 | if (!ASSERT_NEQ(interface, 0, "non zero interface index" )) |
144 | return -1; |
145 | |
146 | ret = bpf_xdp_attach(interface, bpf_program__fd(local_prog), |
147 | prog[index].local_flags, NULL); |
148 | if (!ASSERT_OK(ret, "attach xdp program to local veth" )) |
149 | return -1; |
150 | |
151 | nstoken = open_netns(net_config->veth_cfg[index].namespace); |
152 | if (!ASSERT_OK_PTR(nstoken, "switch to remote veth namespace" )) |
153 | return -1; |
154 | |
155 | interface = if_nametoindex(net_config->veth_cfg[index].remote_veth); |
156 | if (!ASSERT_NEQ(interface, 0, "non zero interface index" )) { |
157 | close_netns(nstoken); |
158 | return -1; |
159 | } |
160 | |
161 | ret = bpf_xdp_attach(interface, bpf_program__fd(remote_prog), |
162 | prog[index].remote_flags, NULL); |
163 | if (!ASSERT_OK(ret, "attach xdp program to remote veth" )) { |
164 | close_netns(nstoken); |
165 | return -1; |
166 | } |
167 | |
168 | close_netns(nstoken); |
169 | return 0; |
170 | } |
171 | |
172 | static int create_network(struct net_configuration *net_config) |
173 | { |
174 | struct nstoken *nstoken = NULL; |
175 | int i, err; |
176 | |
177 | memcpy(net_config, &default_config, sizeof(struct net_configuration)); |
178 | |
179 | /* Create unique namespaces */ |
180 | err = append_tid(net_config->ns0_name, NS_NAME_MAX_LEN); |
181 | if (!ASSERT_OK(err, "append TID to ns0 name" )) |
182 | goto fail; |
183 | SYS(fail, "ip netns add %s" , net_config->ns0_name); |
184 | |
185 | for (i = 0; i < VETH_PAIRS_COUNT; i++) { |
186 | err = append_tid(net_config->veth_cfg[i].namespace, NS_NAME_MAX_LEN); |
187 | if (!ASSERT_OK(err, "append TID to ns name" )) |
188 | goto fail; |
189 | SYS(fail, "ip netns add %s" , net_config->veth_cfg[i].namespace); |
190 | } |
191 | |
192 | /* Create interfaces */ |
193 | nstoken = open_netns(net_config->ns0_name); |
194 | if (!nstoken) |
195 | goto fail; |
196 | |
197 | for (i = 0; i < VETH_PAIRS_COUNT; i++) { |
198 | SYS(fail, "ip link add %s type veth peer name %s netns %s" , |
199 | net_config->veth_cfg[i].local_veth, net_config->veth_cfg[i].remote_veth, |
200 | net_config->veth_cfg[i].namespace); |
201 | SYS(fail, "ip link set dev %s up" , net_config->veth_cfg[i].local_veth); |
202 | if (net_config->veth_cfg[i].remote_addr[0]) |
203 | SYS(fail, "ip -n %s addr add %s/24 dev %s" , |
204 | net_config->veth_cfg[i].namespace, |
205 | net_config->veth_cfg[i].remote_addr, |
206 | net_config->veth_cfg[i].remote_veth); |
207 | SYS(fail, "ip -n %s link set dev %s up" , net_config->veth_cfg[i].namespace, |
208 | net_config->veth_cfg[i].remote_veth); |
209 | } |
210 | |
211 | close_netns(nstoken); |
212 | return 0; |
213 | |
214 | fail: |
215 | close_netns(nstoken); |
216 | return -1; |
217 | } |
218 | |
219 | static void cleanup_network(struct net_configuration *net_config) |
220 | { |
221 | int i; |
222 | |
223 | SYS_NOFAIL("ip netns del %s" , net_config->ns0_name); |
224 | for (i = 0; i < VETH_PAIRS_COUNT; i++) |
225 | SYS_NOFAIL("ip netns del %s" , net_config->veth_cfg[i].namespace); |
226 | } |
227 | |
228 | #define VETH_REDIRECT_SKEL_NB 3 |
229 | static void xdp_veth_redirect(u32 flags) |
230 | { |
231 | struct prog_configuration ping_config[VETH_PAIRS_COUNT] = { |
232 | { |
233 | .local_name = "xdp_redirect_map_0" , |
234 | .remote_name = "xdp_dummy_prog" , |
235 | .local_flags = flags, |
236 | .remote_flags = flags, |
237 | }, |
238 | { |
239 | .local_name = "xdp_redirect_map_1" , |
240 | .remote_name = "xdp_tx" , |
241 | .local_flags = flags, |
242 | .remote_flags = flags, |
243 | }, |
244 | { |
245 | .local_name = "xdp_redirect_map_2" , |
246 | .remote_name = "xdp_dummy_prog" , |
247 | .local_flags = flags, |
248 | .remote_flags = flags, |
249 | } |
250 | }; |
251 | struct bpf_object *bpf_objs[VETH_REDIRECT_SKEL_NB]; |
252 | struct xdp_redirect_map *xdp_redirect_map; |
253 | struct net_configuration net_config; |
254 | struct nstoken *nstoken = NULL; |
255 | struct xdp_dummy *xdp_dummy; |
256 | struct xdp_tx *xdp_tx; |
257 | int map_fd; |
258 | int i; |
259 | |
260 | xdp_dummy = xdp_dummy__open_and_load(); |
261 | if (!ASSERT_OK_PTR(xdp_dummy, "xdp_dummy__open_and_load" )) |
262 | return; |
263 | |
264 | xdp_tx = xdp_tx__open_and_load(); |
265 | if (!ASSERT_OK_PTR(xdp_tx, "xdp_tx__open_and_load" )) |
266 | goto destroy_xdp_dummy; |
267 | |
268 | xdp_redirect_map = xdp_redirect_map__open_and_load(); |
269 | if (!ASSERT_OK_PTR(xdp_redirect_map, "xdp_redirect_map__open_and_load" )) |
270 | goto destroy_xdp_tx; |
271 | |
272 | if (!ASSERT_OK(create_network(net_config: &net_config), "create network" )) |
273 | goto destroy_xdp_redirect_map; |
274 | |
275 | /* Then configure the redirect map and attach programs to interfaces */ |
276 | map_fd = bpf_map__fd(xdp_redirect_map->maps.tx_port); |
277 | if (!ASSERT_OK_FD(map_fd, "open redirect map" )) |
278 | goto destroy_xdp_redirect_map; |
279 | |
280 | bpf_objs[0] = xdp_dummy->obj; |
281 | bpf_objs[1] = xdp_tx->obj; |
282 | bpf_objs[2] = xdp_redirect_map->obj; |
283 | |
284 | nstoken = open_netns(net_config.ns0_name); |
285 | if (!ASSERT_OK_PTR(nstoken, "open NS0" )) |
286 | goto destroy_xdp_redirect_map; |
287 | |
288 | for (i = 0; i < VETH_PAIRS_COUNT; i++) { |
289 | int next_veth = net_config.veth_cfg[i].next_veth; |
290 | int interface_id; |
291 | int err; |
292 | |
293 | interface_id = if_nametoindex(net_config.veth_cfg[next_veth].local_veth); |
294 | if (!ASSERT_NEQ(interface_id, 0, "non zero interface index" )) |
295 | goto destroy_xdp_redirect_map; |
296 | err = bpf_map_update_elem(map_fd, &i, &interface_id, BPF_ANY); |
297 | if (!ASSERT_OK(err, "configure interface redirection through map" )) |
298 | goto destroy_xdp_redirect_map; |
299 | if (attach_programs_to_veth_pair(objs: bpf_objs, VETH_REDIRECT_SKEL_NB, |
300 | net_config: &net_config, prog: ping_config, index: i)) |
301 | goto destroy_xdp_redirect_map; |
302 | } |
303 | |
304 | /* Test: if all interfaces are properly configured, we must be able to ping |
305 | * veth33 from veth11 |
306 | */ |
307 | ASSERT_OK(SYS_NOFAIL("ip netns exec %s ping -c 1 -W 1 %s > /dev/null" , |
308 | net_config.veth_cfg[0].namespace, IP_DST), "ping" ); |
309 | |
310 | destroy_xdp_redirect_map: |
311 | close_netns(nstoken); |
312 | xdp_redirect_map__destroy(xdp_redirect_map); |
313 | destroy_xdp_tx: |
314 | xdp_tx__destroy(xdp_tx); |
315 | destroy_xdp_dummy: |
316 | xdp_dummy__destroy(xdp_dummy); |
317 | |
318 | cleanup_network(net_config: &net_config); |
319 | } |
320 | |
321 | #define BROADCAST_REDIRECT_SKEL_NB 2 |
322 | static void xdp_veth_broadcast_redirect(u32 attach_flags, u64 redirect_flags) |
323 | { |
324 | struct prog_configuration prog_cfg[VETH_PAIRS_COUNT] = { |
325 | { |
326 | .local_name = "xdp_redirect_map_multi_prog" , |
327 | .remote_name = "xdp_count_0" , |
328 | .local_flags = attach_flags, |
329 | .remote_flags = attach_flags, |
330 | }, |
331 | { |
332 | .local_name = "xdp_redirect_map_multi_prog" , |
333 | .remote_name = "xdp_count_1" , |
334 | .local_flags = attach_flags, |
335 | .remote_flags = attach_flags, |
336 | }, |
337 | { |
338 | .local_name = "xdp_redirect_map_multi_prog" , |
339 | .remote_name = "xdp_count_2" , |
340 | .local_flags = attach_flags, |
341 | .remote_flags = attach_flags, |
342 | } |
343 | }; |
344 | struct bpf_object *bpf_objs[BROADCAST_REDIRECT_SKEL_NB]; |
345 | struct xdp_redirect_multi_kern *xdp_redirect_multi_kern; |
346 | struct xdp_redirect_map *xdp_redirect_map; |
347 | struct bpf_devmap_val devmap_val = {}; |
348 | struct net_configuration net_config; |
349 | struct nstoken *nstoken = NULL; |
350 | u16 protocol = ETH_P_IP; |
351 | int group_map; |
352 | int flags_map; |
353 | int cnt_map; |
354 | u64 cnt = 0; |
355 | int i, err; |
356 | |
357 | xdp_redirect_multi_kern = xdp_redirect_multi_kern__open_and_load(); |
358 | if (!ASSERT_OK_PTR(xdp_redirect_multi_kern, "xdp_redirect_multi_kern__open_and_load" )) |
359 | return; |
360 | |
361 | xdp_redirect_map = xdp_redirect_map__open_and_load(); |
362 | if (!ASSERT_OK_PTR(xdp_redirect_map, "xdp_redirect_map__open_and_load" )) |
363 | goto destroy_xdp_redirect_multi_kern; |
364 | |
365 | if (!ASSERT_OK(create_network(net_config: &net_config), "create network" )) |
366 | goto destroy_xdp_redirect_map; |
367 | |
368 | group_map = bpf_map__fd(xdp_redirect_multi_kern->maps.map_all); |
369 | if (!ASSERT_OK_FD(group_map, "open map_all" )) |
370 | goto destroy_xdp_redirect_map; |
371 | |
372 | flags_map = bpf_map__fd(xdp_redirect_multi_kern->maps.redirect_flags); |
373 | if (!ASSERT_OK_FD(group_map, "open map_all" )) |
374 | goto destroy_xdp_redirect_map; |
375 | |
376 | err = bpf_map_update_elem(flags_map, &protocol, &redirect_flags, BPF_NOEXIST); |
377 | if (!ASSERT_OK(err, "init IP count" )) |
378 | goto destroy_xdp_redirect_map; |
379 | |
380 | cnt_map = bpf_map__fd(xdp_redirect_map->maps.rxcnt); |
381 | if (!ASSERT_OK_FD(cnt_map, "open rxcnt map" )) |
382 | goto destroy_xdp_redirect_map; |
383 | |
384 | bpf_objs[0] = xdp_redirect_multi_kern->obj; |
385 | bpf_objs[1] = xdp_redirect_map->obj; |
386 | |
387 | nstoken = open_netns(net_config.ns0_name); |
388 | if (!ASSERT_OK_PTR(nstoken, "open NS0" )) |
389 | goto destroy_xdp_redirect_map; |
390 | |
391 | for (i = 0; i < VETH_PAIRS_COUNT; i++) { |
392 | int ifindex = if_nametoindex(net_config.veth_cfg[i].local_veth); |
393 | |
394 | if (attach_programs_to_veth_pair(objs: bpf_objs, BROADCAST_REDIRECT_SKEL_NB, |
395 | net_config: &net_config, prog: prog_cfg, index: i)) |
396 | goto destroy_xdp_redirect_map; |
397 | |
398 | SYS(destroy_xdp_redirect_map, |
399 | "ip -n %s neigh add %s lladdr 00:00:00:00:00:01 dev %s" , |
400 | net_config.veth_cfg[i].namespace, IP_NEIGH, net_config.veth_cfg[i].remote_veth); |
401 | |
402 | devmap_val.ifindex = ifindex; |
403 | err = bpf_map_update_elem(group_map, &ifindex, &devmap_val, 0); |
404 | if (!ASSERT_OK(err, "bpf_map_update_elem" )) |
405 | goto destroy_xdp_redirect_map; |
406 | |
407 | } |
408 | |
409 | SYS_NOFAIL("ip netns exec %s ping %s -i 0.1 -c 4 -W1 > /dev/null " , |
410 | net_config.veth_cfg[0].namespace, IP_NEIGH); |
411 | |
412 | for (i = 0; i < VETH_PAIRS_COUNT; i++) { |
413 | err = bpf_map_lookup_elem(cnt_map, &i, &cnt); |
414 | if (!ASSERT_OK(err, "get IP cnt" )) |
415 | goto destroy_xdp_redirect_map; |
416 | |
417 | if (redirect_flags & BPF_F_EXCLUDE_INGRESS) |
418 | /* veth11 shouldn't receive the ICMP requests; |
419 | * others should |
420 | */ |
421 | ASSERT_EQ(cnt, i ? 4 : 0, "compare IP cnt" ); |
422 | else |
423 | /* All remote veth should receive the ICMP requests */ |
424 | ASSERT_EQ(cnt, 4, "compare IP cnt" ); |
425 | } |
426 | |
427 | destroy_xdp_redirect_map: |
428 | close_netns(nstoken); |
429 | xdp_redirect_map__destroy(xdp_redirect_map); |
430 | destroy_xdp_redirect_multi_kern: |
431 | xdp_redirect_multi_kern__destroy(xdp_redirect_multi_kern); |
432 | |
433 | cleanup_network(net_config: &net_config); |
434 | } |
435 | |
436 | #define VETH_EGRESS_SKEL_NB 3 |
437 | static void xdp_veth_egress(u32 flags) |
438 | { |
439 | struct prog_configuration prog_cfg[VETH_PAIRS_COUNT] = { |
440 | { |
441 | .local_name = "xdp_redirect_map_all_prog" , |
442 | .remote_name = "xdp_dummy_prog" , |
443 | .local_flags = flags, |
444 | .remote_flags = flags, |
445 | }, |
446 | { |
447 | .local_name = "xdp_redirect_map_all_prog" , |
448 | .remote_name = "store_mac_1" , |
449 | .local_flags = flags, |
450 | .remote_flags = flags, |
451 | }, |
452 | { |
453 | .local_name = "xdp_redirect_map_all_prog" , |
454 | .remote_name = "store_mac_2" , |
455 | .local_flags = flags, |
456 | .remote_flags = flags, |
457 | } |
458 | }; |
459 | const char magic_mac[6] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; |
460 | struct xdp_redirect_multi_kern *xdp_redirect_multi_kern; |
461 | struct bpf_object *bpf_objs[VETH_EGRESS_SKEL_NB]; |
462 | struct xdp_redirect_map *xdp_redirect_map; |
463 | struct bpf_devmap_val devmap_val = {}; |
464 | struct net_configuration net_config; |
465 | int mac_map, egress_map, res_map; |
466 | struct nstoken *nstoken = NULL; |
467 | struct xdp_dummy *xdp_dummy; |
468 | int err; |
469 | int i; |
470 | |
471 | xdp_dummy = xdp_dummy__open_and_load(); |
472 | if (!ASSERT_OK_PTR(xdp_dummy, "xdp_dummy__open_and_load" )) |
473 | return; |
474 | |
475 | xdp_redirect_multi_kern = xdp_redirect_multi_kern__open_and_load(); |
476 | if (!ASSERT_OK_PTR(xdp_redirect_multi_kern, "xdp_redirect_multi_kern__open_and_load" )) |
477 | goto destroy_xdp_dummy; |
478 | |
479 | xdp_redirect_map = xdp_redirect_map__open_and_load(); |
480 | if (!ASSERT_OK_PTR(xdp_redirect_map, "xdp_redirect_map__open_and_load" )) |
481 | goto destroy_xdp_redirect_multi_kern; |
482 | |
483 | if (!ASSERT_OK(create_network(net_config: &net_config), "create network" )) |
484 | goto destroy_xdp_redirect_map; |
485 | |
486 | mac_map = bpf_map__fd(xdp_redirect_multi_kern->maps.mac_map); |
487 | if (!ASSERT_OK_FD(mac_map, "open mac_map" )) |
488 | goto destroy_xdp_redirect_map; |
489 | |
490 | egress_map = bpf_map__fd(xdp_redirect_multi_kern->maps.map_egress); |
491 | if (!ASSERT_OK_FD(egress_map, "open map_egress" )) |
492 | goto destroy_xdp_redirect_map; |
493 | |
494 | devmap_val.bpf_prog.fd = bpf_program__fd(xdp_redirect_multi_kern->progs.xdp_devmap_prog); |
495 | |
496 | bpf_objs[0] = xdp_dummy->obj; |
497 | bpf_objs[1] = xdp_redirect_multi_kern->obj; |
498 | bpf_objs[2] = xdp_redirect_map->obj; |
499 | |
500 | nstoken = open_netns(net_config.ns0_name); |
501 | if (!ASSERT_OK_PTR(nstoken, "open NS0" )) |
502 | goto destroy_xdp_redirect_map; |
503 | |
504 | for (i = 0; i < VETH_PAIRS_COUNT; i++) { |
505 | int ifindex = if_nametoindex(net_config.veth_cfg[i].local_veth); |
506 | |
507 | SYS(destroy_xdp_redirect_map, |
508 | "ip -n %s neigh add %s lladdr 00:00:00:00:00:01 dev %s" , |
509 | net_config.veth_cfg[i].namespace, IP_NEIGH, net_config.veth_cfg[i].remote_veth); |
510 | |
511 | if (attach_programs_to_veth_pair(objs: bpf_objs, VETH_REDIRECT_SKEL_NB, |
512 | net_config: &net_config, prog: prog_cfg, index: i)) |
513 | goto destroy_xdp_redirect_map; |
514 | |
515 | err = bpf_map_update_elem(mac_map, &ifindex, magic_mac, 0); |
516 | if (!ASSERT_OK(err, "bpf_map_update_elem" )) |
517 | goto destroy_xdp_redirect_map; |
518 | |
519 | devmap_val.ifindex = ifindex; |
520 | err = bpf_map_update_elem(egress_map, &ifindex, &devmap_val, 0); |
521 | if (!ASSERT_OK(err, "bpf_map_update_elem" )) |
522 | goto destroy_xdp_redirect_map; |
523 | } |
524 | |
525 | SYS_NOFAIL("ip netns exec %s ping %s -i 0.1 -c 4 -W1 > /dev/null " , |
526 | net_config.veth_cfg[0].namespace, IP_NEIGH); |
527 | |
528 | res_map = bpf_map__fd(xdp_redirect_map->maps.rx_mac); |
529 | if (!ASSERT_OK_FD(res_map, "open rx_map" )) |
530 | goto destroy_xdp_redirect_map; |
531 | |
532 | for (i = 0; i < 2; i++) { |
533 | u32 key = i; |
534 | u64 res; |
535 | |
536 | err = bpf_map_lookup_elem(res_map, &key, &res); |
537 | if (!ASSERT_OK(err, "get MAC res" )) |
538 | goto destroy_xdp_redirect_map; |
539 | |
540 | ASSERT_STRNEQ((const char *)&res, magic_mac, ETH_ALEN, "compare mac" ); |
541 | } |
542 | |
543 | destroy_xdp_redirect_map: |
544 | close_netns(nstoken); |
545 | xdp_redirect_map__destroy(xdp_redirect_map); |
546 | destroy_xdp_redirect_multi_kern: |
547 | xdp_redirect_multi_kern__destroy(xdp_redirect_multi_kern); |
548 | destroy_xdp_dummy: |
549 | xdp_dummy__destroy(xdp_dummy); |
550 | |
551 | cleanup_network(net_config: &net_config); |
552 | } |
553 | |
554 | void test_xdp_veth_redirect(void) |
555 | { |
556 | if (test__start_subtest("0" )) |
557 | xdp_veth_redirect(flags: 0); |
558 | |
559 | if (test__start_subtest("DRV_MODE" )) |
560 | xdp_veth_redirect(XDP_FLAGS_DRV_MODE); |
561 | |
562 | if (test__start_subtest("SKB_MODE" )) |
563 | xdp_veth_redirect(XDP_FLAGS_SKB_MODE); |
564 | } |
565 | |
566 | void test_xdp_veth_broadcast_redirect(void) |
567 | { |
568 | if (test__start_subtest("0/BROADCAST" )) |
569 | xdp_veth_broadcast_redirect(attach_flags: 0, redirect_flags: BPF_F_BROADCAST); |
570 | |
571 | if (test__start_subtest("0/(BROADCAST | EXCLUDE_INGRESS)" )) |
572 | xdp_veth_broadcast_redirect(attach_flags: 0, redirect_flags: BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS); |
573 | |
574 | if (test__start_subtest("DRV_MODE/BROADCAST" )) |
575 | xdp_veth_broadcast_redirect(XDP_FLAGS_DRV_MODE, redirect_flags: BPF_F_BROADCAST); |
576 | |
577 | if (test__start_subtest("DRV_MODE/(BROADCAST | EXCLUDE_INGRESS)" )) |
578 | xdp_veth_broadcast_redirect(XDP_FLAGS_DRV_MODE, |
579 | redirect_flags: BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS); |
580 | |
581 | if (test__start_subtest("SKB_MODE/BROADCAST" )) |
582 | xdp_veth_broadcast_redirect(XDP_FLAGS_SKB_MODE, redirect_flags: BPF_F_BROADCAST); |
583 | |
584 | if (test__start_subtest("SKB_MODE/(BROADCAST | EXCLUDE_INGRESS)" )) |
585 | xdp_veth_broadcast_redirect(XDP_FLAGS_SKB_MODE, |
586 | redirect_flags: BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS); |
587 | } |
588 | |
589 | void test_xdp_veth_egress(void) |
590 | { |
591 | if (test__start_subtest("0/egress" )) |
592 | xdp_veth_egress(flags: 0); |
593 | |
594 | if (test__start_subtest("DRV_MODE/egress" )) |
595 | xdp_veth_egress(XDP_FLAGS_DRV_MODE); |
596 | |
597 | if (test__start_subtest("SKB_MODE/egress" )) |
598 | xdp_veth_egress(XDP_FLAGS_SKB_MODE); |
599 | } |
600 | |