1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 3 /* 4 * End-to-end eBPF tunnel test suite 5 * The file tests BPF network tunnel implementation. 6 * 7 * Topology: 8 * --------- 9 * root namespace | at_ns0 namespace 10 * | 11 * ----------- | ----------- 12 * | tnl dev | | | tnl dev | (overlay network) 13 * ----------- | ----------- 14 * metadata-mode | metadata-mode 15 * with bpf | with bpf 16 * | 17 * ---------- | ---------- 18 * | veth1 | --------- | veth0 | (underlay network) 19 * ---------- peer ---------- 20 * 21 * 22 * Device Configuration 23 * -------------------- 24 * root namespace with metadata-mode tunnel + BPF 25 * Device names and addresses: 26 * veth1 IP 1: 172.16.1.200, IPv6: 00::22 (underlay) 27 * IP 2: 172.16.1.20, IPv6: 00::bb (underlay) 28 * tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay) 29 * 30 * Namespace at_ns0 with native tunnel 31 * Device names and addresses: 32 * veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay) 33 * tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay) 34 * 35 * 36 * End-to-end ping packet flow 37 * --------------------------- 38 * Most of the tests start by namespace creation, device configuration, 39 * then ping the underlay and overlay network. When doing 'ping 10.1.1.100' 40 * from root namespace, the following operations happen: 41 * 1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev. 42 * 2) Tnl device's egress BPF program is triggered and set the tunnel metadata, 43 * with local_ip=172.16.1.200, remote_ip=172.16.1.100. BPF program choose 44 * the primary or secondary ip of veth1 as the local ip of tunnel. The 45 * choice is made based on the value of bpf map local_ip_map. 46 * 3) Outer tunnel header is prepended and route the packet to veth1's egress. 47 * 4) veth0's ingress queue receive the tunneled packet at namespace at_ns0. 48 * 5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet. 49 * 6) Forward the packet to the overlay tnl dev. 50 */ 51 52 #include <arpa/inet.h> 53 #include <linux/if_tun.h> 54 #include <linux/limits.h> 55 #include <linux/sysctl.h> 56 #include <linux/time_types.h> 57 #include <linux/net_tstamp.h> 58 #include <net/if.h> 59 #include <stdbool.h> 60 #include <stdio.h> 61 #include <sys/stat.h> 62 #include <unistd.h> 63 64 #include "test_progs.h" 65 #include "network_helpers.h" 66 #include "test_tunnel_kern.skel.h" 67 68 #define IP4_ADDR_VETH0 "172.16.1.100" 69 #define IP4_ADDR1_VETH1 "172.16.1.200" 70 #define IP4_ADDR2_VETH1 "172.16.1.20" 71 #define IP4_ADDR_TUNL_DEV0 "10.1.1.100" 72 #define IP4_ADDR_TUNL_DEV1 "10.1.1.200" 73 74 #define IP6_ADDR_VETH0 "::11" 75 #define IP6_ADDR1_VETH1 "::22" 76 #define IP6_ADDR2_VETH1 "::bb" 77 78 #define IP4_ADDR1_HEX_VETH1 0xac1001c8 79 #define IP4_ADDR2_HEX_VETH1 0xac100114 80 #define IP6_ADDR1_HEX_VETH1 0x22 81 #define IP6_ADDR2_HEX_VETH1 0xbb 82 83 #define MAC_TUNL_DEV0 "52:54:00:d9:01:00" 84 #define MAC_TUNL_DEV1 "52:54:00:d9:02:00" 85 #define MAC_VETH1 "52:54:00:d9:03:00" 86 87 #define VXLAN_TUNL_DEV0 "vxlan00" 88 #define VXLAN_TUNL_DEV1 "vxlan11" 89 #define IP6VXLAN_TUNL_DEV0 "ip6vxlan00" 90 #define IP6VXLAN_TUNL_DEV1 "ip6vxlan11" 91 92 #define PING_ARGS "-i 0.01 -c 3 -w 10 -q" 93 94 static int config_device(void) 95 { 96 SYS(fail, "ip netns add at_ns0"); 97 SYS(fail, "ip link add veth0 address " MAC_VETH1 " type veth peer name veth1"); 98 SYS(fail, "ip link set veth0 netns at_ns0"); 99 SYS(fail, "ip addr add " IP4_ADDR1_VETH1 "/24 dev veth1"); 100 SYS(fail, "ip link set dev veth1 up mtu 1500"); 101 SYS(fail, "ip netns exec at_ns0 ip addr add " IP4_ADDR_VETH0 "/24 dev veth0"); 102 SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up mtu 1500"); 103 104 return 0; 105 fail: 106 return -1; 107 } 108 109 static void cleanup(void) 110 { 111 SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0"); 112 SYS_NOFAIL("ip link del veth1 2> /dev/null"); 113 SYS_NOFAIL("ip link del %s 2> /dev/null", VXLAN_TUNL_DEV1); 114 SYS_NOFAIL("ip link del %s 2> /dev/null", IP6VXLAN_TUNL_DEV1); 115 } 116 117 static int add_vxlan_tunnel(void) 118 { 119 /* at_ns0 namespace */ 120 SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external gbp dstport 4789", 121 VXLAN_TUNL_DEV0); 122 SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up", 123 VXLAN_TUNL_DEV0, MAC_TUNL_DEV0); 124 SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24", 125 VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0); 126 SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev %s", 127 IP4_ADDR_TUNL_DEV1, MAC_TUNL_DEV1, VXLAN_TUNL_DEV0); 128 SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev veth0", 129 IP4_ADDR2_VETH1, MAC_VETH1); 130 131 /* root namespace */ 132 SYS(fail, "ip link add dev %s type vxlan external gbp dstport 4789", 133 VXLAN_TUNL_DEV1); 134 SYS(fail, "ip link set dev %s address %s up", VXLAN_TUNL_DEV1, MAC_TUNL_DEV1); 135 SYS(fail, "ip addr add dev %s %s/24", VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1); 136 SYS(fail, "ip neigh add %s lladdr %s dev %s", 137 IP4_ADDR_TUNL_DEV0, MAC_TUNL_DEV0, VXLAN_TUNL_DEV1); 138 139 return 0; 140 fail: 141 return -1; 142 } 143 144 static void delete_vxlan_tunnel(void) 145 { 146 SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s", 147 VXLAN_TUNL_DEV0); 148 SYS_NOFAIL("ip link delete dev %s", VXLAN_TUNL_DEV1); 149 } 150 151 static int add_ip6vxlan_tunnel(void) 152 { 153 SYS(fail, "ip netns exec at_ns0 ip -6 addr add %s/96 dev veth0", 154 IP6_ADDR_VETH0); 155 SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up"); 156 SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR1_VETH1); 157 SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR2_VETH1); 158 SYS(fail, "ip link set dev veth1 up"); 159 160 /* at_ns0 namespace */ 161 SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external dstport 4789", 162 IP6VXLAN_TUNL_DEV0); 163 SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24", 164 IP6VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0); 165 SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up", 166 IP6VXLAN_TUNL_DEV0, MAC_TUNL_DEV0); 167 168 /* root namespace */ 169 SYS(fail, "ip link add dev %s type vxlan external dstport 4789", 170 IP6VXLAN_TUNL_DEV1); 171 SYS(fail, "ip addr add dev %s %s/24", IP6VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1); 172 SYS(fail, "ip link set dev %s address %s up", 173 IP6VXLAN_TUNL_DEV1, MAC_TUNL_DEV1); 174 175 return 0; 176 fail: 177 return -1; 178 } 179 180 static void delete_ip6vxlan_tunnel(void) 181 { 182 SYS_NOFAIL("ip netns exec at_ns0 ip -6 addr delete %s/96 dev veth0", 183 IP6_ADDR_VETH0); 184 SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR1_VETH1); 185 SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR2_VETH1); 186 SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s", 187 IP6VXLAN_TUNL_DEV0); 188 SYS_NOFAIL("ip link delete dev %s", IP6VXLAN_TUNL_DEV1); 189 } 190 191 static int test_ping(int family, const char *addr) 192 { 193 SYS(fail, "%s %s %s > /dev/null", ping_command(family), PING_ARGS, addr); 194 return 0; 195 fail: 196 return -1; 197 } 198 199 static int attach_tc_prog(struct bpf_tc_hook *hook, int igr_fd, int egr_fd) 200 { 201 DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1, 202 .priority = 1, .prog_fd = igr_fd); 203 DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1, 204 .priority = 1, .prog_fd = egr_fd); 205 int ret; 206 207 ret = bpf_tc_hook_create(hook); 208 if (!ASSERT_OK(ret, "create tc hook")) 209 return ret; 210 211 if (igr_fd >= 0) { 212 hook->attach_point = BPF_TC_INGRESS; 213 ret = bpf_tc_attach(hook, &opts1); 214 if (!ASSERT_OK(ret, "bpf_tc_attach")) { 215 bpf_tc_hook_destroy(hook); 216 return ret; 217 } 218 } 219 220 if (egr_fd >= 0) { 221 hook->attach_point = BPF_TC_EGRESS; 222 ret = bpf_tc_attach(hook, &opts2); 223 if (!ASSERT_OK(ret, "bpf_tc_attach")) { 224 bpf_tc_hook_destroy(hook); 225 return ret; 226 } 227 } 228 229 return 0; 230 } 231 232 static void test_vxlan_tunnel(void) 233 { 234 struct test_tunnel_kern *skel = NULL; 235 struct nstoken *nstoken; 236 int local_ip_map_fd = -1; 237 int set_src_prog_fd, get_src_prog_fd; 238 int set_dst_prog_fd; 239 int key = 0, ifindex = -1; 240 uint local_ip; 241 int err; 242 DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook, 243 .attach_point = BPF_TC_INGRESS); 244 245 /* add vxlan tunnel */ 246 err = add_vxlan_tunnel(); 247 if (!ASSERT_OK(err, "add vxlan tunnel")) 248 goto done; 249 250 /* load and attach bpf prog to tunnel dev tc hook point */ 251 skel = test_tunnel_kern__open_and_load(); 252 if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) 253 goto done; 254 ifindex = if_nametoindex(VXLAN_TUNL_DEV1); 255 if (!ASSERT_NEQ(ifindex, 0, "vxlan11 ifindex")) 256 goto done; 257 tc_hook.ifindex = ifindex; 258 get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src); 259 set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src); 260 if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd")) 261 goto done; 262 if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd")) 263 goto done; 264 if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd)) 265 goto done; 266 267 /* load and attach bpf prog to veth dev tc hook point */ 268 ifindex = if_nametoindex("veth1"); 269 if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex")) 270 goto done; 271 tc_hook.ifindex = ifindex; 272 set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst); 273 if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd")) 274 goto done; 275 if (attach_tc_prog(&tc_hook, set_dst_prog_fd, -1)) 276 goto done; 277 278 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ 279 nstoken = open_netns("at_ns0"); 280 if (!ASSERT_OK_PTR(nstoken, "setns src")) 281 goto done; 282 ifindex = if_nametoindex(VXLAN_TUNL_DEV0); 283 if (!ASSERT_NEQ(ifindex, 0, "vxlan00 ifindex")) 284 goto done; 285 tc_hook.ifindex = ifindex; 286 set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst); 287 if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd")) 288 goto done; 289 if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd)) 290 goto done; 291 close_netns(nstoken); 292 293 /* use veth1 ip 2 as tunnel source ip */ 294 local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map); 295 if (!ASSERT_GE(local_ip_map_fd, 0, "bpf_map__fd")) 296 goto done; 297 local_ip = IP4_ADDR2_HEX_VETH1; 298 err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY); 299 if (!ASSERT_OK(err, "update bpf local_ip_map")) 300 goto done; 301 302 /* ping test */ 303 err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0); 304 if (!ASSERT_OK(err, "test_ping")) 305 goto done; 306 307 done: 308 /* delete vxlan tunnel */ 309 delete_vxlan_tunnel(); 310 if (local_ip_map_fd >= 0) 311 close(local_ip_map_fd); 312 if (skel) 313 test_tunnel_kern__destroy(skel); 314 } 315 316 static void test_ip6vxlan_tunnel(void) 317 { 318 struct test_tunnel_kern *skel = NULL; 319 struct nstoken *nstoken; 320 int local_ip_map_fd = -1; 321 int set_src_prog_fd, get_src_prog_fd; 322 int set_dst_prog_fd; 323 int key = 0, ifindex = -1; 324 uint local_ip; 325 int err; 326 DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook, 327 .attach_point = BPF_TC_INGRESS); 328 329 /* add vxlan tunnel */ 330 err = add_ip6vxlan_tunnel(); 331 if (!ASSERT_OK(err, "add_ip6vxlan_tunnel")) 332 goto done; 333 334 /* load and attach bpf prog to tunnel dev tc hook point */ 335 skel = test_tunnel_kern__open_and_load(); 336 if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) 337 goto done; 338 ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV1); 339 if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan11 ifindex")) 340 goto done; 341 tc_hook.ifindex = ifindex; 342 get_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src); 343 set_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src); 344 if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd")) 345 goto done; 346 if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd")) 347 goto done; 348 if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd)) 349 goto done; 350 351 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ 352 nstoken = open_netns("at_ns0"); 353 if (!ASSERT_OK_PTR(nstoken, "setns src")) 354 goto done; 355 ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV0); 356 if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan00 ifindex")) 357 goto done; 358 tc_hook.ifindex = ifindex; 359 set_dst_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst); 360 if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd")) 361 goto done; 362 if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd)) 363 goto done; 364 close_netns(nstoken); 365 366 /* use veth1 ip 2 as tunnel source ip */ 367 local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map); 368 if (!ASSERT_GE(local_ip_map_fd, 0, "get local_ip_map fd")) 369 goto done; 370 local_ip = IP6_ADDR2_HEX_VETH1; 371 err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY); 372 if (!ASSERT_OK(err, "update bpf local_ip_map")) 373 goto done; 374 375 /* ping test */ 376 err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0); 377 if (!ASSERT_OK(err, "test_ping")) 378 goto done; 379 380 done: 381 /* delete ipv6 vxlan tunnel */ 382 delete_ip6vxlan_tunnel(); 383 if (local_ip_map_fd >= 0) 384 close(local_ip_map_fd); 385 if (skel) 386 test_tunnel_kern__destroy(skel); 387 } 388 389 #define RUN_TEST(name) \ 390 ({ \ 391 if (test__start_subtest(#name)) { \ 392 test_ ## name(); \ 393 } \ 394 }) 395 396 static void *test_tunnel_run_tests(void *arg) 397 { 398 cleanup(); 399 config_device(); 400 401 RUN_TEST(vxlan_tunnel); 402 RUN_TEST(ip6vxlan_tunnel); 403 404 cleanup(); 405 406 return NULL; 407 } 408 409 void test_tunnel(void) 410 { 411 pthread_t test_thread; 412 int err; 413 414 /* Run the tests in their own thread to isolate the namespace changes 415 * so they do not affect the environment of other tests. 416 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns()) 417 */ 418 err = pthread_create(&test_thread, NULL, &test_tunnel_run_tests, NULL); 419 if (ASSERT_OK(err, "pthread_create")) 420 ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join"); 421 } 422