1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include <network_helpers.h> 4 #include <net/if.h> 5 #include <linux/if_ether.h> 6 #include <linux/if_packet.h> 7 #include <linux/ipv6.h> 8 #include <linux/in6.h> 9 #include <linux/udp.h> 10 #include <bpf/bpf_endian.h> 11 #include "test_xdp_do_redirect.skel.h" 12 13 #define SYS(fmt, ...) \ 14 ({ \ 15 char cmd[1024]; \ 16 snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ 17 if (!ASSERT_OK(system(cmd), cmd)) \ 18 goto out; \ 19 }) 20 21 struct udp_packet { 22 struct ethhdr eth; 23 struct ipv6hdr iph; 24 struct udphdr udp; 25 __u8 payload[64 - sizeof(struct udphdr) 26 - sizeof(struct ethhdr) - sizeof(struct ipv6hdr)]; 27 } __packed; 28 29 static struct udp_packet pkt_udp = { 30 .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), 31 .eth.h_dest = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}, 32 .eth.h_source = {0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb}, 33 .iph.version = 6, 34 .iph.nexthdr = IPPROTO_UDP, 35 .iph.payload_len = bpf_htons(sizeof(struct udp_packet) 36 - offsetof(struct udp_packet, udp)), 37 .iph.hop_limit = 2, 38 .iph.saddr.s6_addr16 = {bpf_htons(0xfc00), 0, 0, 0, 0, 0, 0, bpf_htons(1)}, 39 .iph.daddr.s6_addr16 = {bpf_htons(0xfc00), 0, 0, 0, 0, 0, 0, bpf_htons(2)}, 40 .udp.source = bpf_htons(1), 41 .udp.dest = bpf_htons(1), 42 .udp.len = bpf_htons(sizeof(struct udp_packet) 43 - offsetof(struct udp_packet, udp)), 44 .payload = {0x42}, /* receiver XDP program matches on this */ 45 }; 46 47 static int attach_tc_prog(struct bpf_tc_hook *hook, int fd) 48 { 49 DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts, .handle = 1, .priority = 1, .prog_fd = fd); 50 int ret; 51 52 ret = bpf_tc_hook_create(hook); 53 if (!ASSERT_OK(ret, "create tc hook")) 54 return ret; 55 56 ret = bpf_tc_attach(hook, &opts); 57 if (!ASSERT_OK(ret, "bpf_tc_attach")) { 58 bpf_tc_hook_destroy(hook); 59 return ret; 60 } 61 62 return 0; 63 } 64 65 /* The maximum permissible size is: PAGE_SIZE - sizeof(struct xdp_page_head) - 66 * sizeof(struct skb_shared_info) - XDP_PACKET_HEADROOM = 3368 bytes 67 */ 68 #define MAX_PKT_SIZE 3368 69 static void test_max_pkt_size(int fd) 70 { 71 char data[MAX_PKT_SIZE + 1] = {}; 72 int err; 73 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, 74 .data_in = &data, 75 .data_size_in = MAX_PKT_SIZE, 76 .flags = BPF_F_TEST_XDP_LIVE_FRAMES, 77 .repeat = 1, 78 ); 79 err = bpf_prog_test_run_opts(fd, &opts); 80 ASSERT_OK(err, "prog_run_max_size"); 81 82 opts.data_size_in += 1; 83 err = bpf_prog_test_run_opts(fd, &opts); 84 ASSERT_EQ(err, -EINVAL, "prog_run_too_big"); 85 } 86 87 #define NUM_PKTS 10000 88 void test_xdp_do_redirect(void) 89 { 90 int err, xdp_prog_fd, tc_prog_fd, ifindex_src, ifindex_dst; 91 char data[sizeof(pkt_udp) + sizeof(__u32)]; 92 struct test_xdp_do_redirect *skel = NULL; 93 struct nstoken *nstoken = NULL; 94 struct bpf_link *link; 95 96 struct xdp_md ctx_in = { .data = sizeof(__u32), 97 .data_end = sizeof(data) }; 98 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, 99 .data_in = &data, 100 .data_size_in = sizeof(data), 101 .ctx_in = &ctx_in, 102 .ctx_size_in = sizeof(ctx_in), 103 .flags = BPF_F_TEST_XDP_LIVE_FRAMES, 104 .repeat = NUM_PKTS, 105 .batch_size = 64, 106 ); 107 DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook, 108 .attach_point = BPF_TC_INGRESS); 109 110 memcpy(&data[sizeof(__u32)], &pkt_udp, sizeof(pkt_udp)); 111 *((__u32 *)data) = 0x42; /* metadata test value */ 112 113 skel = test_xdp_do_redirect__open(); 114 if (!ASSERT_OK_PTR(skel, "skel")) 115 return; 116 117 /* The XDP program we run with bpf_prog_run() will cycle through all 118 * three xmit (PASS/TX/REDIRECT) return codes starting from above, and 119 * ending up with PASS, so we should end up with two packets on the dst 120 * iface and NUM_PKTS-2 in the TC hook. We match the packets on the UDP 121 * payload. 122 */ 123 SYS("ip netns add testns"); 124 nstoken = open_netns("testns"); 125 if (!ASSERT_OK_PTR(nstoken, "setns")) 126 goto out; 127 128 SYS("ip link add veth_src type veth peer name veth_dst"); 129 SYS("ip link set dev veth_src address 00:11:22:33:44:55"); 130 SYS("ip link set dev veth_dst address 66:77:88:99:aa:bb"); 131 SYS("ip link set dev veth_src up"); 132 SYS("ip link set dev veth_dst up"); 133 SYS("ip addr add dev veth_src fc00::1/64"); 134 SYS("ip addr add dev veth_dst fc00::2/64"); 135 SYS("ip neigh add fc00::2 dev veth_src lladdr 66:77:88:99:aa:bb"); 136 137 /* We enable forwarding in the test namespace because that will cause 138 * the packets that go through the kernel stack (with XDP_PASS) to be 139 * forwarded back out the same interface (because of the packet dst 140 * combined with the interface addresses). When this happens, the 141 * regular forwarding path will end up going through the same 142 * veth_xdp_xmit() call as the XDP_REDIRECT code, which can cause a 143 * deadlock if it happens on the same CPU. There's a local_bh_disable() 144 * in the test_run code to prevent this, but an earlier version of the 145 * code didn't have this, so we keep the test behaviour to make sure the 146 * bug doesn't resurface. 147 */ 148 SYS("sysctl -qw net.ipv6.conf.all.forwarding=1"); 149 150 ifindex_src = if_nametoindex("veth_src"); 151 ifindex_dst = if_nametoindex("veth_dst"); 152 if (!ASSERT_NEQ(ifindex_src, 0, "ifindex_src") || 153 !ASSERT_NEQ(ifindex_dst, 0, "ifindex_dst")) 154 goto out; 155 156 memcpy(skel->rodata->expect_dst, &pkt_udp.eth.h_dest, ETH_ALEN); 157 skel->rodata->ifindex_out = ifindex_src; /* redirect back to the same iface */ 158 skel->rodata->ifindex_in = ifindex_src; 159 ctx_in.ingress_ifindex = ifindex_src; 160 tc_hook.ifindex = ifindex_src; 161 162 if (!ASSERT_OK(test_xdp_do_redirect__load(skel), "load")) 163 goto out; 164 165 link = bpf_program__attach_xdp(skel->progs.xdp_count_pkts, ifindex_dst); 166 if (!ASSERT_OK_PTR(link, "prog_attach")) 167 goto out; 168 skel->links.xdp_count_pkts = link; 169 170 tc_prog_fd = bpf_program__fd(skel->progs.tc_count_pkts); 171 if (attach_tc_prog(&tc_hook, tc_prog_fd)) 172 goto out; 173 174 xdp_prog_fd = bpf_program__fd(skel->progs.xdp_redirect); 175 err = bpf_prog_test_run_opts(xdp_prog_fd, &opts); 176 if (!ASSERT_OK(err, "prog_run")) 177 goto out_tc; 178 179 /* wait for the packets to be flushed */ 180 kern_sync_rcu(); 181 182 /* There will be one packet sent through XDP_REDIRECT and one through 183 * XDP_TX; these will show up on the XDP counting program, while the 184 * rest will be counted at the TC ingress hook (and the counting program 185 * resets the packet payload so they don't get counted twice even though 186 * they are re-xmited out the veth device 187 */ 188 ASSERT_EQ(skel->bss->pkts_seen_xdp, 2, "pkt_count_xdp"); 189 ASSERT_EQ(skel->bss->pkts_seen_zero, 2, "pkt_count_zero"); 190 ASSERT_EQ(skel->bss->pkts_seen_tc, NUM_PKTS - 2, "pkt_count_tc"); 191 192 test_max_pkt_size(bpf_program__fd(skel->progs.xdp_count_pkts)); 193 194 out_tc: 195 bpf_tc_hook_destroy(&tc_hook); 196 out: 197 if (nstoken) 198 close_netns(nstoken); 199 system("ip netns del testns"); 200 test_xdp_do_redirect__destroy(skel); 201 } 202