xref: /linux/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c (revision 2ed2e359dea752e7758d29a423033031a0b96584)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <network_helpers.h>
4 #include <linux/ipv6.h>
5 #include <arpa/inet.h>
6 #include "test_xdp_context_test_run.skel.h"
7 #include "test_xdp_meta.skel.h"
8 
9 #define RX_NAME "veth0"
10 #define TX_NAME "veth1"
11 #define TX_NETNS "xdp_context_tx"
12 #define RX_NETNS "xdp_context_rx"
13 #define RX_MAC "02:00:00:00:00:01"
14 #define TX_MAC "02:00:00:00:00:02"
15 #define TAP_NAME "tap0"
16 #define DUMMY_NAME "dum0"
17 #define TAP_NETNS "xdp_context_tuntap"
18 #define LWT_NETNS "xdp_context_lwt"
19 
20 #define TEST_PAYLOAD_LEN 32
21 static const __u8 test_payload[TEST_PAYLOAD_LEN] = {
22 	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
23 	0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
24 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
25 	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
26 };
27 
test_xdp_context_error(int prog_fd,struct bpf_test_run_opts opts,__u32 data_meta,__u32 data,__u32 data_end,__u32 ingress_ifindex,__u32 rx_queue_index,__u32 egress_ifindex)28 void test_xdp_context_error(int prog_fd, struct bpf_test_run_opts opts,
29 			    __u32 data_meta, __u32 data, __u32 data_end,
30 			    __u32 ingress_ifindex, __u32 rx_queue_index,
31 			    __u32 egress_ifindex)
32 {
33 	struct xdp_md ctx = {
34 		.data = data,
35 		.data_end = data_end,
36 		.data_meta = data_meta,
37 		.ingress_ifindex = ingress_ifindex,
38 		.rx_queue_index = rx_queue_index,
39 		.egress_ifindex = egress_ifindex,
40 	};
41 	int err;
42 
43 	opts.ctx_in = &ctx;
44 	opts.ctx_size_in = sizeof(ctx);
45 	err = bpf_prog_test_run_opts(prog_fd, &opts);
46 	ASSERT_EQ(errno, EINVAL, "errno-EINVAL");
47 	ASSERT_ERR(err, "bpf_prog_test_run");
48 }
49 
test_xdp_context_test_run(void)50 void test_xdp_context_test_run(void)
51 {
52 	struct test_xdp_context_test_run *skel = NULL;
53 	char data[sizeof(pkt_v4) + sizeof(__u32)];
54 	char bad_ctx[sizeof(struct xdp_md) + 1];
55 	char large_data[256];
56 	struct xdp_md ctx_in, ctx_out;
57 	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
58 			    .data_in = &data,
59 			    .data_size_in = sizeof(data),
60 			    .ctx_out = &ctx_out,
61 			    .ctx_size_out = sizeof(ctx_out),
62 			    .repeat = 1,
63 		);
64 	int err, prog_fd;
65 
66 	skel = test_xdp_context_test_run__open_and_load();
67 	if (!ASSERT_OK_PTR(skel, "skel"))
68 		return;
69 	prog_fd = bpf_program__fd(skel->progs.xdp_context);
70 
71 	/* Data past the end of the kernel's struct xdp_md must be 0 */
72 	bad_ctx[sizeof(bad_ctx) - 1] = 1;
73 	opts.ctx_in = bad_ctx;
74 	opts.ctx_size_in = sizeof(bad_ctx);
75 	err = bpf_prog_test_run_opts(prog_fd, &opts);
76 	ASSERT_EQ(errno, E2BIG, "extradata-errno");
77 	ASSERT_ERR(err, "bpf_prog_test_run(extradata)");
78 
79 	*(__u32 *)data = XDP_PASS;
80 	*(struct ipv4_packet *)(data + sizeof(__u32)) = pkt_v4;
81 	opts.ctx_in = &ctx_in;
82 	opts.ctx_size_in = sizeof(ctx_in);
83 	memset(&ctx_in, 0, sizeof(ctx_in));
84 	ctx_in.data_meta = 0;
85 	ctx_in.data = sizeof(__u32);
86 	ctx_in.data_end = ctx_in.data + sizeof(pkt_v4);
87 	err = bpf_prog_test_run_opts(prog_fd, &opts);
88 	ASSERT_OK(err, "bpf_prog_test_run(valid)");
89 	ASSERT_EQ(opts.retval, XDP_PASS, "valid-retval");
90 	ASSERT_EQ(opts.data_size_out, sizeof(pkt_v4), "valid-datasize");
91 	ASSERT_EQ(opts.ctx_size_out, opts.ctx_size_in, "valid-ctxsize");
92 	ASSERT_EQ(ctx_out.data_meta, 0, "valid-datameta");
93 	ASSERT_EQ(ctx_out.data, 0, "valid-data");
94 	ASSERT_EQ(ctx_out.data_end, sizeof(pkt_v4), "valid-dataend");
95 
96 	/* Meta data's size must be a multiple of 4 */
97 	test_xdp_context_error(prog_fd, opts, 0, 1, sizeof(data), 0, 0, 0);
98 
99 	/* data_meta must reference the start of data */
100 	test_xdp_context_error(prog_fd, opts, 4, sizeof(__u32), sizeof(data),
101 			       0, 0, 0);
102 
103 	/* Total size of data must be data_end - data_meta or larger */
104 	test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32),
105 			       sizeof(data) + 1, 0, 0, 0);
106 
107 	/* RX queue cannot be specified without specifying an ingress */
108 	test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), sizeof(data),
109 			       0, 1, 0);
110 
111 	/* Interface 1 is always the loopback interface which always has only
112 	 * one RX queue (index 0). This makes index 1 an invalid rx queue index
113 	 * for interface 1.
114 	 */
115 	test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), sizeof(data),
116 			       1, 1, 0);
117 
118 	/* The egress cannot be specified */
119 	test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), sizeof(data),
120 			       0, 0, 1);
121 
122 	/* Meta data must be 216 bytes or smaller (256 - sizeof(struct
123 	 * xdp_frame)). Test both nearest invalid size and nearest invalid
124 	 * 4-byte-aligned size, and make sure data_in is large enough that we
125 	 * actually hit the check on metadata length
126 	 */
127 	opts.data_in = large_data;
128 	opts.data_size_in = sizeof(large_data);
129 	test_xdp_context_error(prog_fd, opts, 0, 217, sizeof(large_data), 0, 0, 0);
130 	test_xdp_context_error(prog_fd, opts, 0, 220, sizeof(large_data), 0, 0, 0);
131 
132 	test_xdp_context_test_run__destroy(skel);
133 }
134 
send_test_packet(int ifindex)135 static int send_test_packet(int ifindex)
136 {
137 	int n, sock = -1;
138 	__u8 packet[sizeof(struct ethhdr) + TEST_PAYLOAD_LEN];
139 
140 	/* We use the Ethernet header only to identify the test packet */
141 	struct ethhdr eth = {
142 		.h_source = { 0x12, 0x34, 0xDE, 0xAD, 0xBE, 0xEF },
143 	};
144 
145 	memcpy(packet, &eth, sizeof(eth));
146 	memcpy(packet + sizeof(eth), test_payload, TEST_PAYLOAD_LEN);
147 
148 	sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
149 	if (!ASSERT_GE(sock, 0, "socket"))
150 		goto err;
151 
152 	struct sockaddr_ll saddr = {
153 		.sll_family = PF_PACKET,
154 		.sll_ifindex = ifindex,
155 		.sll_halen = ETH_ALEN
156 	};
157 	n = sendto(sock, packet, sizeof(packet), 0, (struct sockaddr *)&saddr,
158 		   sizeof(saddr));
159 	if (!ASSERT_EQ(n, sizeof(packet), "sendto"))
160 		goto err;
161 
162 	close(sock);
163 	return 0;
164 
165 err:
166 	if (sock >= 0)
167 		close(sock);
168 	return -1;
169 }
170 
write_test_packet(int tap_fd)171 static int write_test_packet(int tap_fd)
172 {
173 	__u8 packet[sizeof(struct ethhdr) + TEST_PAYLOAD_LEN];
174 	int n;
175 
176 	/* The Ethernet header is mostly not relevant. We use it to identify the
177 	 * test packet and some BPF helpers we exercise expect to operate on
178 	 * Ethernet frames carrying IP packets. Pretend that's the case.
179 	 */
180 	struct ethhdr eth = {
181 		.h_source = { 0x12, 0x34, 0xDE, 0xAD, 0xBE, 0xEF },
182 		.h_proto = htons(ETH_P_IP),
183 	};
184 
185 	memcpy(packet, &eth, sizeof(eth));
186 	memcpy(packet + sizeof(struct ethhdr), test_payload, TEST_PAYLOAD_LEN);
187 
188 	n = write(tap_fd, packet, sizeof(packet));
189 	if (!ASSERT_EQ(n, sizeof(packet), "write packet"))
190 		return -1;
191 
192 	return 0;
193 }
194 
195 /* Inject Ethernet+IPv6+UDP frame into TAP */
write_test_packet_udp(int tap_fd)196 static int write_test_packet_udp(int tap_fd)
197 {
198 	__u8 pkt[sizeof(struct ethhdr) + sizeof(struct ipv6hdr) +
199 		 sizeof(struct udphdr) + TEST_PAYLOAD_LEN] = {};
200 	struct ethhdr *eth = (void *)pkt;
201 	struct ipv6hdr *ip6 = (void *)(eth + 1);
202 	struct udphdr *udp = (void *)(ip6 + 1);
203 	__u8 *payload = (void *)(udp + 1);
204 	const __u8 tap_mac[ETH_ALEN] = { 0x02, 0, 0, 0, 0, 0x01 };
205 	int n;
206 
207 	memcpy(eth->h_dest, tap_mac, ETH_ALEN);
208 	eth->h_proto = htons(ETH_P_IPV6);
209 
210 	ip6->version = 6;
211 	ip6->hop_limit = 64;
212 	ip6->nexthdr = IPPROTO_UDP;
213 	ip6->payload_len = htons(sizeof(*udp) + TEST_PAYLOAD_LEN);
214 	inet_pton(AF_INET6, "fd00::2", &ip6->saddr);
215 	inet_pton(AF_INET6, "fd00:1::1", &ip6->daddr);
216 
217 	udp->source = htons(42);
218 	udp->dest = htons(42);
219 	udp->len = htons(sizeof(*udp) + TEST_PAYLOAD_LEN);
220 	/* UDP checksum is not validated on the forwarding path. */
221 
222 	memcpy(payload, test_payload, TEST_PAYLOAD_LEN);
223 
224 	n = write(tap_fd, pkt, sizeof(pkt));
225 	if (!ASSERT_EQ(n, sizeof(pkt), "write frame"))
226 		return -1;
227 
228 	return 0;
229 }
230 
dump_err_stream(const struct bpf_program * prog)231 static void dump_err_stream(const struct bpf_program *prog)
232 {
233 	char buf[512];
234 	int ret;
235 
236 	ret = 0;
237 	do {
238 		ret = bpf_prog_stream_read(bpf_program__fd(prog),
239 					   BPF_STREAM_STDERR, buf, sizeof(buf),
240 					   NULL);
241 		if (ret > 0)
242 			fwrite(buf, sizeof(buf[0]), ret, stderr);
243 	} while (ret > 0);
244 }
245 
test_xdp_context_veth(void)246 void test_xdp_context_veth(void)
247 {
248 	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS);
249 	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
250 	struct netns_obj *rx_ns = NULL, *tx_ns = NULL;
251 	struct bpf_program *tc_prog, *xdp_prog;
252 	struct test_xdp_meta *skel = NULL;
253 	struct nstoken *nstoken = NULL;
254 	int rx_ifindex, tx_ifindex;
255 	int ret;
256 
257 	tx_ns = netns_new(TX_NETNS, false);
258 	if (!ASSERT_OK_PTR(tx_ns, "create tx_ns"))
259 		return;
260 
261 	rx_ns = netns_new(RX_NETNS, false);
262 	if (!ASSERT_OK_PTR(rx_ns, "create rx_ns"))
263 		goto close;
264 
265 	SYS(close, "ip link add " RX_NAME " netns " RX_NETNS
266 	    " type veth peer name " TX_NAME " netns " TX_NETNS);
267 
268 	nstoken = open_netns(RX_NETNS);
269 	if (!ASSERT_OK_PTR(nstoken, "setns rx_ns"))
270 		goto close;
271 
272 	SYS(close, "ip link set dev " RX_NAME " up");
273 
274 	skel = test_xdp_meta__open_and_load();
275 	if (!ASSERT_OK_PTR(skel, "open and load skeleton"))
276 		goto close;
277 
278 	rx_ifindex = if_nametoindex(RX_NAME);
279 	if (!ASSERT_GE(rx_ifindex, 0, "if_nametoindex rx"))
280 		goto close;
281 
282 	tc_hook.ifindex = rx_ifindex;
283 	ret = bpf_tc_hook_create(&tc_hook);
284 	if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
285 		goto close;
286 
287 	tc_prog = bpf_object__find_program_by_name(skel->obj, "ing_cls");
288 	if (!ASSERT_OK_PTR(tc_prog, "open ing_cls prog"))
289 		goto close;
290 
291 	tc_opts.prog_fd = bpf_program__fd(tc_prog);
292 	ret = bpf_tc_attach(&tc_hook, &tc_opts);
293 	if (!ASSERT_OK(ret, "bpf_tc_attach"))
294 		goto close;
295 
296 	xdp_prog = bpf_object__find_program_by_name(skel->obj, "ing_xdp");
297 	if (!ASSERT_OK_PTR(xdp_prog, "open ing_xdp prog"))
298 		goto close;
299 
300 	ret = bpf_xdp_attach(rx_ifindex,
301 			     bpf_program__fd(xdp_prog),
302 			     0, NULL);
303 	if (!ASSERT_GE(ret, 0, "bpf_xdp_attach"))
304 		goto close;
305 
306 	close_netns(nstoken);
307 
308 	nstoken = open_netns(TX_NETNS);
309 	if (!ASSERT_OK_PTR(nstoken, "setns tx_ns"))
310 		goto close;
311 
312 	SYS(close, "ip link set dev " TX_NAME " up");
313 
314 	tx_ifindex = if_nametoindex(TX_NAME);
315 	if (!ASSERT_GE(tx_ifindex, 0, "if_nametoindex tx"))
316 		goto close;
317 
318 	skel->bss->test_pass = false;
319 
320 	ret = send_test_packet(tx_ifindex);
321 	if (!ASSERT_OK(ret, "send_test_packet"))
322 		goto close;
323 
324 	if (!ASSERT_TRUE(skel->bss->test_pass, "test_pass"))
325 		dump_err_stream(tc_prog);
326 
327 close:
328 	close_netns(nstoken);
329 	test_xdp_meta__destroy(skel);
330 	netns_free(rx_ns);
331 	netns_free(tx_ns);
332 }
333 
test_tuntap(struct bpf_program * xdp_prog,struct bpf_program * tc_prio_1_prog,struct bpf_program * tc_prio_2_prog,bool * test_pass)334 static void test_tuntap(struct bpf_program *xdp_prog,
335 			struct bpf_program *tc_prio_1_prog,
336 			struct bpf_program *tc_prio_2_prog,
337 			bool *test_pass)
338 {
339 	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS);
340 	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
341 	struct netns_obj *ns = NULL;
342 	int tap_fd = -1;
343 	int tap_ifindex;
344 	int ret;
345 
346 	*test_pass = false;
347 
348 	ns = netns_new(TAP_NETNS, true);
349 	if (!ASSERT_OK_PTR(ns, "create and open ns"))
350 		return;
351 
352 	tap_fd = open_tuntap(TAP_NAME, true);
353 	if (!ASSERT_GE(tap_fd, 0, "open_tuntap"))
354 		goto close;
355 
356 	SYS(close, "ip link set dev " TAP_NAME " up");
357 
358 	tap_ifindex = if_nametoindex(TAP_NAME);
359 	if (!ASSERT_GE(tap_ifindex, 0, "if_nametoindex"))
360 		goto close;
361 
362 	tc_hook.ifindex = tap_ifindex;
363 	ret = bpf_tc_hook_create(&tc_hook);
364 	if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
365 		goto close;
366 
367 	tc_opts.prog_fd = bpf_program__fd(tc_prio_1_prog);
368 	ret = bpf_tc_attach(&tc_hook, &tc_opts);
369 	if (!ASSERT_OK(ret, "bpf_tc_attach"))
370 		goto close;
371 
372 	if (tc_prio_2_prog) {
373 		LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 2,
374 			    .prog_fd = bpf_program__fd(tc_prio_2_prog));
375 
376 		ret = bpf_tc_attach(&tc_hook, &tc_opts);
377 		if (!ASSERT_OK(ret, "bpf_tc_attach"))
378 			goto close;
379 	}
380 
381 	ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(xdp_prog),
382 			     0, NULL);
383 	if (!ASSERT_GE(ret, 0, "bpf_xdp_attach"))
384 		goto close;
385 
386 	ret = write_test_packet(tap_fd);
387 	if (!ASSERT_OK(ret, "write_test_packet"))
388 		goto close;
389 
390 	if (!ASSERT_TRUE(*test_pass, "test_pass"))
391 		dump_err_stream(tc_prio_2_prog ? : tc_prio_1_prog);
392 
393 close:
394 	if (tap_fd >= 0)
395 		close(tap_fd);
396 	netns_free(ns);
397 }
398 
399 /* Write a packet to a tap dev and copy it to ingress of a dummy dev */
test_tuntap_mirred(struct bpf_program * xdp_prog,struct bpf_program * tc_prog,bool * test_pass)400 static void test_tuntap_mirred(struct bpf_program *xdp_prog,
401 			       struct bpf_program *tc_prog,
402 			       bool *test_pass)
403 {
404 	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS);
405 	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
406 	struct netns_obj *ns = NULL;
407 	int dummy_ifindex;
408 	int tap_fd = -1;
409 	int tap_ifindex;
410 	int ret;
411 
412 	*test_pass = false;
413 
414 	ns = netns_new(TAP_NETNS, true);
415 	if (!ASSERT_OK_PTR(ns, "netns_new"))
416 		return;
417 
418 	/* Setup dummy interface */
419 	SYS(close, "ip link add name " DUMMY_NAME " type dummy");
420 	SYS(close, "ip link set dev " DUMMY_NAME " up");
421 
422 	dummy_ifindex = if_nametoindex(DUMMY_NAME);
423 	if (!ASSERT_GE(dummy_ifindex, 0, "if_nametoindex"))
424 		goto close;
425 
426 	tc_hook.ifindex = dummy_ifindex;
427 	ret = bpf_tc_hook_create(&tc_hook);
428 	if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
429 		goto close;
430 
431 	tc_opts.prog_fd = bpf_program__fd(tc_prog);
432 	ret = bpf_tc_attach(&tc_hook, &tc_opts);
433 	if (!ASSERT_OK(ret, "bpf_tc_attach"))
434 		goto close;
435 
436 	/* Setup TAP interface */
437 	tap_fd = open_tuntap(TAP_NAME, true);
438 	if (!ASSERT_GE(tap_fd, 0, "open_tuntap"))
439 		goto close;
440 
441 	SYS(close, "ip link set dev " TAP_NAME " up");
442 
443 	tap_ifindex = if_nametoindex(TAP_NAME);
444 	if (!ASSERT_GE(tap_ifindex, 0, "if_nametoindex"))
445 		goto close;
446 
447 	ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(xdp_prog), 0, NULL);
448 	if (!ASSERT_GE(ret, 0, "bpf_xdp_attach"))
449 		goto close;
450 
451 	/* Copy all packets received from TAP to dummy ingress */
452 	SYS(close, "tc qdisc add dev " TAP_NAME " clsact");
453 	SYS(close, "tc filter add dev " TAP_NAME " ingress "
454 		   "protocol all matchall "
455 		   "action mirred ingress mirror dev " DUMMY_NAME);
456 
457 	/* Receive a packet on TAP */
458 	ret = write_test_packet(tap_fd);
459 	if (!ASSERT_OK(ret, "write_test_packet"))
460 		goto close;
461 
462 	if (!ASSERT_TRUE(*test_pass, "test_pass"))
463 		dump_err_stream(tc_prog);
464 
465 close:
466 	if (tap_fd >= 0)
467 		close(tap_fd);
468 	netns_free(ns);
469 }
470 
test_xdp_context_tuntap(void)471 void test_xdp_context_tuntap(void)
472 {
473 	struct test_xdp_meta *skel = NULL;
474 
475 	skel = test_xdp_meta__open_and_load();
476 	if (!ASSERT_OK_PTR(skel, "open and load skeleton"))
477 		return;
478 
479 	if (test__start_subtest("data_meta"))
480 		test_tuntap(skel->progs.ing_xdp,
481 			    skel->progs.ing_cls,
482 			    NULL, /* tc prio 2 */
483 			    &skel->bss->test_pass);
484 	if (test__start_subtest("dynptr_read"))
485 		test_tuntap(skel->progs.ing_xdp,
486 			    skel->progs.ing_cls_dynptr_read,
487 			    NULL, /* tc prio 2 */
488 			    &skel->bss->test_pass);
489 	if (test__start_subtest("dynptr_slice"))
490 		test_tuntap(skel->progs.ing_xdp,
491 			    skel->progs.ing_cls_dynptr_slice,
492 			    NULL, /* tc prio 2 */
493 			    &skel->bss->test_pass);
494 	if (test__start_subtest("dynptr_write"))
495 		test_tuntap(skel->progs.ing_xdp_zalloc_meta,
496 			    skel->progs.ing_cls_dynptr_write,
497 			    skel->progs.ing_cls_dynptr_read,
498 			    &skel->bss->test_pass);
499 	if (test__start_subtest("dynptr_slice_rdwr"))
500 		test_tuntap(skel->progs.ing_xdp_zalloc_meta,
501 			    skel->progs.ing_cls_dynptr_slice_rdwr,
502 			    skel->progs.ing_cls_dynptr_slice,
503 			    &skel->bss->test_pass);
504 	if (test__start_subtest("dynptr_offset"))
505 		test_tuntap(skel->progs.ing_xdp_zalloc_meta,
506 			    skel->progs.ing_cls_dynptr_offset_wr,
507 			    skel->progs.ing_cls_dynptr_offset_rd,
508 			    &skel->bss->test_pass);
509 	if (test__start_subtest("dynptr_offset_oob"))
510 		test_tuntap(skel->progs.ing_xdp,
511 			    skel->progs.ing_cls_dynptr_offset_oob,
512 			    skel->progs.ing_cls,
513 			    &skel->bss->test_pass);
514 	if (test__start_subtest("clone_data_meta_survives_data_write"))
515 		test_tuntap_mirred(skel->progs.ing_xdp,
516 				   skel->progs.clone_data_meta_survives_data_write,
517 				   &skel->bss->test_pass);
518 	if (test__start_subtest("clone_data_meta_survives_meta_write"))
519 		test_tuntap_mirred(skel->progs.ing_xdp,
520 				   skel->progs.clone_data_meta_survives_meta_write,
521 				   &skel->bss->test_pass);
522 	if (test__start_subtest("clone_meta_dynptr_survives_data_slice_write"))
523 		test_tuntap_mirred(skel->progs.ing_xdp,
524 				   skel->progs.clone_meta_dynptr_survives_data_slice_write,
525 				   &skel->bss->test_pass);
526 	if (test__start_subtest("clone_meta_dynptr_survives_meta_slice_write"))
527 		test_tuntap_mirred(skel->progs.ing_xdp,
528 				   skel->progs.clone_meta_dynptr_survives_meta_slice_write,
529 				   &skel->bss->test_pass);
530 	if (test__start_subtest("clone_meta_dynptr_rw_before_data_dynptr_write"))
531 		test_tuntap_mirred(skel->progs.ing_xdp,
532 				   skel->progs.clone_meta_dynptr_rw_before_data_dynptr_write,
533 				   &skel->bss->test_pass);
534 	if (test__start_subtest("clone_meta_dynptr_rw_before_meta_dynptr_write"))
535 		test_tuntap_mirred(skel->progs.ing_xdp,
536 				   skel->progs.clone_meta_dynptr_rw_before_meta_dynptr_write,
537 				   &skel->bss->test_pass);
538 	/* Tests for BPF helpers which touch headroom */
539 	if (test__start_subtest("helper_skb_vlan_push_pop"))
540 		test_tuntap(skel->progs.ing_xdp,
541 			    skel->progs.helper_skb_vlan_push_pop,
542 			    NULL, /* tc prio 2 */
543 			    &skel->bss->test_pass);
544 	if (test__start_subtest("helper_skb_adjust_room"))
545 		test_tuntap(skel->progs.ing_xdp,
546 			    skel->progs.helper_skb_adjust_room,
547 			    NULL, /* tc prio 2 */
548 			    &skel->bss->test_pass);
549 	if (test__start_subtest("helper_skb_change_head_tail"))
550 		test_tuntap(skel->progs.ing_xdp,
551 			    skel->progs.helper_skb_change_head_tail,
552 			    NULL, /* tc prio 2 */
553 			    &skel->bss->test_pass);
554 	if (test__start_subtest("helper_skb_change_proto"))
555 		test_tuntap(skel->progs.ing_xdp,
556 			    skel->progs.helper_skb_change_proto,
557 			    NULL, /* tc prio 2 */
558 			    &skel->bss->test_pass);
559 
560 	test_xdp_meta__destroy(skel);
561 }
562 
563 /*
564  * Test topology:
565  *
566  *	tap0 fd00::1
567  *	  RX:  injected IPv6 UDP frame, XDP ingress sets metadata
568  *	  fwd: encap route prepends outer header(s)
569  *	  TX:  TC egress validates metadata
570  *
571  * A routable IPv6 UDP frame is written into the tap fd, so it enters the RX
572  * path where XDP stores metadata. Routing then forwards it back out the same
573  * tap through an encapsulating route that prepends outer header(s). The TC
574  * egress program checks that the pushed header did not silently corrupt
575  * metadata.
576  */
577 #define LWT_PIN_PATH "/sys/fs/bpf/xdp_context_lwt_xmit"
578 
579 enum lwt_encap_type {
580 	LWT_ENCAP_BPF,
581 	LWT_ENCAP_MPLS,
582 	LWT_ENCAP_SEG6,
583 	LWT_ENCAP_IOAM6,
584 };
585 
test_lwt_encap(struct test_xdp_meta * skel,enum lwt_encap_type type)586 static void test_lwt_encap(struct test_xdp_meta *skel,
587 			   enum lwt_encap_type type)
588 {
589 	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_EGRESS);
590 	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
591 	struct bpf_program *lwt_prog = NULL;
592 	struct netns_obj *ns = NULL;
593 	const char *encap;
594 	bool pinned = false;
595 	int tap_ifindex;
596 	int tap_fd = -1;
597 	int ret;
598 
599 	skel->bss->test_pass = false;
600 
601 	switch (type) {
602 	case LWT_ENCAP_BPF:
603 		encap = "encap bpf xmit pinned " LWT_PIN_PATH " via fd00::2";
604 		lwt_prog = skel->progs.dummy_lwt_xmit;
605 		break;
606 	case LWT_ENCAP_MPLS:
607 		encap = "encap mpls 100 via inet6 fd00::2";
608 		break;
609 	case LWT_ENCAP_SEG6:
610 		encap = "encap seg6 mode encap segs fd00::2";
611 		break;
612 	case LWT_ENCAP_IOAM6:
613 		encap = "encap ioam6 mode encap tundst fd00::2 "
614 			"trace prealloc type 0x800000 ns 0 size 4 via fd00::2";
615 		break;
616 	default:
617 		return;
618 	}
619 
620 	if (lwt_prog) {
621 		unlink(LWT_PIN_PATH);
622 		ret = bpf_program__pin(lwt_prog, LWT_PIN_PATH);
623 		if (!ASSERT_OK(ret, "pin lwt prog"))
624 			return;
625 		pinned = true;
626 	}
627 
628 	ns = netns_new(LWT_NETNS, true);
629 	if (!ASSERT_OK_PTR(ns, "netns_new"))
630 		goto close;
631 
632 	tap_fd = open_tuntap(TAP_NAME, true);
633 	if (!ASSERT_GE(tap_fd, 0, "open_tuntap"))
634 		goto close;
635 
636 	SYS(close, "ip link set dev " TAP_NAME " address " RX_MAC);
637 	SYS(close, "sysctl -wq net.ipv6.conf.all.forwarding=1");
638 	SYS(close, "ip addr add fd00::1/64 dev " TAP_NAME " nodad");
639 	SYS(close, "ip link set dev " TAP_NAME " up");
640 	SYS(close, "ip neigh add fd00::2 lladdr " TX_MAC " nud permanent dev " TAP_NAME);
641 	SYS(close, "ip -6 route add fd00:1::/64 %s dev %s", encap, TAP_NAME);
642 
643 	tap_ifindex = if_nametoindex(TAP_NAME);
644 	if (!ASSERT_GE(tap_ifindex, 0, "if_nametoindex"))
645 		goto close;
646 
647 	ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(skel->progs.ing_xdp),
648 			     0, NULL);
649 	if (!ASSERT_GE(ret, 0, "bpf_xdp_attach"))
650 		goto close;
651 
652 	tc_hook.ifindex = tap_ifindex;
653 	ret = bpf_tc_hook_create(&tc_hook);
654 	if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
655 		goto close;
656 
657 	tc_opts.prog_fd = bpf_program__fd(skel->progs.tc_is_meta_empty);
658 	ret = bpf_tc_attach(&tc_hook, &tc_opts);
659 	if (!ASSERT_OK(ret, "bpf_tc_attach"))
660 		goto close;
661 
662 	ret = write_test_packet_udp(tap_fd);
663 	if (!ASSERT_OK(ret, "write_test_packet_udp"))
664 		goto close;
665 
666 	if (!ASSERT_TRUE(skel->bss->test_pass, "test_pass"))
667 		dump_err_stream(skel->progs.tc_is_meta_empty);
668 
669 close:
670 	if (tap_fd >= 0)
671 		close(tap_fd);
672 	netns_free(ns);
673 	if (pinned)
674 		unlink(LWT_PIN_PATH);
675 }
676 
test_xdp_context_lwt_encap(void)677 void test_xdp_context_lwt_encap(void)
678 {
679 	struct test_xdp_meta *skel;
680 
681 	skel = test_xdp_meta__open_and_load();
682 	if (!ASSERT_OK_PTR(skel, "open and load skeleton"))
683 		return;
684 
685 	if (test__start_subtest("bpf_encap"))
686 		test_lwt_encap(skel, LWT_ENCAP_BPF);
687 	if (test__start_subtest("mpls_encap"))
688 		test_lwt_encap(skel, LWT_ENCAP_MPLS);
689 	if (test__start_subtest("seg6_encap"))
690 		test_lwt_encap(skel, LWT_ENCAP_SEG6);
691 	if (test__start_subtest("ioam6_encap"))
692 		test_lwt_encap(skel, LWT_ENCAP_IOAM6);
693 
694 	test_xdp_meta__destroy(skel);
695 }
696