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 #define SYS(fmt, ...) \ 95 ({ \ 96 char cmd[1024]; \ 97 snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ 98 if (!ASSERT_OK(system(cmd), cmd)) \ 99 goto fail; \ 100 }) 101 102 #define SYS_NOFAIL(fmt, ...) \ 103 ({ \ 104 char cmd[1024]; \ 105 snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ 106 system(cmd); \ 107 }) 108 109 static int config_device(void) 110 { 111 SYS("ip netns add at_ns0"); 112 SYS("ip link add veth0 address " MAC_VETH1 " type veth peer name veth1"); 113 SYS("ip link set veth0 netns at_ns0"); 114 SYS("ip addr add " IP4_ADDR1_VETH1 "/24 dev veth1"); 115 SYS("ip link set dev veth1 up mtu 1500"); 116 SYS("ip netns exec at_ns0 ip addr add " IP4_ADDR_VETH0 "/24 dev veth0"); 117 SYS("ip netns exec at_ns0 ip link set dev veth0 up mtu 1500"); 118 119 return 0; 120 fail: 121 return -1; 122 } 123 124 static void cleanup(void) 125 { 126 SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0"); 127 SYS_NOFAIL("ip link del veth1 2> /dev/null"); 128 SYS_NOFAIL("ip link del %s 2> /dev/null", VXLAN_TUNL_DEV1); 129 SYS_NOFAIL("ip link del %s 2> /dev/null", IP6VXLAN_TUNL_DEV1); 130 } 131 132 static int add_vxlan_tunnel(void) 133 { 134 /* at_ns0 namespace */ 135 SYS("ip netns exec at_ns0 ip link add dev %s type vxlan external gbp dstport 4789", 136 VXLAN_TUNL_DEV0); 137 SYS("ip netns exec at_ns0 ip link set dev %s address %s up", 138 VXLAN_TUNL_DEV0, MAC_TUNL_DEV0); 139 SYS("ip netns exec at_ns0 ip addr add dev %s %s/24", 140 VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0); 141 SYS("ip netns exec at_ns0 ip neigh add %s lladdr %s dev %s", 142 IP4_ADDR_TUNL_DEV1, MAC_TUNL_DEV1, VXLAN_TUNL_DEV0); 143 SYS("ip netns exec at_ns0 ip neigh add %s lladdr %s dev veth0", 144 IP4_ADDR2_VETH1, MAC_VETH1); 145 146 /* root namespace */ 147 SYS("ip link add dev %s type vxlan external gbp dstport 4789", 148 VXLAN_TUNL_DEV1); 149 SYS("ip link set dev %s address %s up", VXLAN_TUNL_DEV1, MAC_TUNL_DEV1); 150 SYS("ip addr add dev %s %s/24", VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1); 151 SYS("ip neigh add %s lladdr %s dev %s", 152 IP4_ADDR_TUNL_DEV0, MAC_TUNL_DEV0, VXLAN_TUNL_DEV1); 153 154 return 0; 155 fail: 156 return -1; 157 } 158 159 static void delete_vxlan_tunnel(void) 160 { 161 SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s", 162 VXLAN_TUNL_DEV0); 163 SYS_NOFAIL("ip link delete dev %s", VXLAN_TUNL_DEV1); 164 } 165 166 static int add_ip6vxlan_tunnel(void) 167 { 168 SYS("ip netns exec at_ns0 ip -6 addr add %s/96 dev veth0", 169 IP6_ADDR_VETH0); 170 SYS("ip netns exec at_ns0 ip link set dev veth0 up"); 171 SYS("ip -6 addr add %s/96 dev veth1", IP6_ADDR1_VETH1); 172 SYS("ip -6 addr add %s/96 dev veth1", IP6_ADDR2_VETH1); 173 SYS("ip link set dev veth1 up"); 174 175 /* at_ns0 namespace */ 176 SYS("ip netns exec at_ns0 ip link add dev %s type vxlan external dstport 4789", 177 IP6VXLAN_TUNL_DEV0); 178 SYS("ip netns exec at_ns0 ip addr add dev %s %s/24", 179 IP6VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0); 180 SYS("ip netns exec at_ns0 ip link set dev %s address %s up", 181 IP6VXLAN_TUNL_DEV0, MAC_TUNL_DEV0); 182 183 /* root namespace */ 184 SYS("ip link add dev %s type vxlan external dstport 4789", 185 IP6VXLAN_TUNL_DEV1); 186 SYS("ip addr add dev %s %s/24", IP6VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1); 187 SYS("ip link set dev %s address %s up", 188 IP6VXLAN_TUNL_DEV1, MAC_TUNL_DEV1); 189 190 return 0; 191 fail: 192 return -1; 193 } 194 195 static void delete_ip6vxlan_tunnel(void) 196 { 197 SYS_NOFAIL("ip netns exec at_ns0 ip -6 addr delete %s/96 dev veth0", 198 IP6_ADDR_VETH0); 199 SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR1_VETH1); 200 SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR2_VETH1); 201 SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s", 202 IP6VXLAN_TUNL_DEV0); 203 SYS_NOFAIL("ip link delete dev %s", IP6VXLAN_TUNL_DEV1); 204 } 205 206 static int test_ping(int family, const char *addr) 207 { 208 SYS("%s %s %s > /dev/null", ping_command(family), PING_ARGS, addr); 209 return 0; 210 fail: 211 return -1; 212 } 213 214 static int attach_tc_prog(struct bpf_tc_hook *hook, int igr_fd, int egr_fd) 215 { 216 DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1, 217 .priority = 1, .prog_fd = igr_fd); 218 DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1, 219 .priority = 1, .prog_fd = egr_fd); 220 int ret; 221 222 ret = bpf_tc_hook_create(hook); 223 if (!ASSERT_OK(ret, "create tc hook")) 224 return ret; 225 226 if (igr_fd >= 0) { 227 hook->attach_point = BPF_TC_INGRESS; 228 ret = bpf_tc_attach(hook, &opts1); 229 if (!ASSERT_OK(ret, "bpf_tc_attach")) { 230 bpf_tc_hook_destroy(hook); 231 return ret; 232 } 233 } 234 235 if (egr_fd >= 0) { 236 hook->attach_point = BPF_TC_EGRESS; 237 ret = bpf_tc_attach(hook, &opts2); 238 if (!ASSERT_OK(ret, "bpf_tc_attach")) { 239 bpf_tc_hook_destroy(hook); 240 return ret; 241 } 242 } 243 244 return 0; 245 } 246 247 static void test_vxlan_tunnel(void) 248 { 249 struct test_tunnel_kern *skel = NULL; 250 struct nstoken *nstoken; 251 int local_ip_map_fd = -1; 252 int set_src_prog_fd, get_src_prog_fd; 253 int set_dst_prog_fd; 254 int key = 0, ifindex = -1; 255 uint local_ip; 256 int err; 257 DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook, 258 .attach_point = BPF_TC_INGRESS); 259 260 /* add vxlan tunnel */ 261 err = add_vxlan_tunnel(); 262 if (!ASSERT_OK(err, "add vxlan tunnel")) 263 goto done; 264 265 /* load and attach bpf prog to tunnel dev tc hook point */ 266 skel = test_tunnel_kern__open_and_load(); 267 if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) 268 goto done; 269 ifindex = if_nametoindex(VXLAN_TUNL_DEV1); 270 if (!ASSERT_NEQ(ifindex, 0, "vxlan11 ifindex")) 271 goto done; 272 tc_hook.ifindex = ifindex; 273 get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src); 274 set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src); 275 if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd")) 276 goto done; 277 if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd")) 278 goto done; 279 if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd)) 280 goto done; 281 282 /* load and attach bpf prog to veth dev tc hook point */ 283 ifindex = if_nametoindex("veth1"); 284 if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex")) 285 goto done; 286 tc_hook.ifindex = ifindex; 287 set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst); 288 if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd")) 289 goto done; 290 if (attach_tc_prog(&tc_hook, set_dst_prog_fd, -1)) 291 goto done; 292 293 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ 294 nstoken = open_netns("at_ns0"); 295 if (!ASSERT_OK_PTR(nstoken, "setns src")) 296 goto done; 297 ifindex = if_nametoindex(VXLAN_TUNL_DEV0); 298 if (!ASSERT_NEQ(ifindex, 0, "vxlan00 ifindex")) 299 goto done; 300 tc_hook.ifindex = ifindex; 301 set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst); 302 if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd")) 303 goto done; 304 if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd)) 305 goto done; 306 close_netns(nstoken); 307 308 /* use veth1 ip 2 as tunnel source ip */ 309 local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map); 310 if (!ASSERT_GE(local_ip_map_fd, 0, "bpf_map__fd")) 311 goto done; 312 local_ip = IP4_ADDR2_HEX_VETH1; 313 err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY); 314 if (!ASSERT_OK(err, "update bpf local_ip_map")) 315 goto done; 316 317 /* ping test */ 318 err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0); 319 if (!ASSERT_OK(err, "test_ping")) 320 goto done; 321 322 done: 323 /* delete vxlan tunnel */ 324 delete_vxlan_tunnel(); 325 if (local_ip_map_fd >= 0) 326 close(local_ip_map_fd); 327 if (skel) 328 test_tunnel_kern__destroy(skel); 329 } 330 331 static void test_ip6vxlan_tunnel(void) 332 { 333 struct test_tunnel_kern *skel = NULL; 334 struct nstoken *nstoken; 335 int local_ip_map_fd = -1; 336 int set_src_prog_fd, get_src_prog_fd; 337 int set_dst_prog_fd; 338 int key = 0, ifindex = -1; 339 uint local_ip; 340 int err; 341 DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook, 342 .attach_point = BPF_TC_INGRESS); 343 344 /* add vxlan tunnel */ 345 err = add_ip6vxlan_tunnel(); 346 if (!ASSERT_OK(err, "add_ip6vxlan_tunnel")) 347 goto done; 348 349 /* load and attach bpf prog to tunnel dev tc hook point */ 350 skel = test_tunnel_kern__open_and_load(); 351 if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) 352 goto done; 353 ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV1); 354 if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan11 ifindex")) 355 goto done; 356 tc_hook.ifindex = ifindex; 357 get_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src); 358 set_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src); 359 if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd")) 360 goto done; 361 if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd")) 362 goto done; 363 if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd)) 364 goto done; 365 366 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ 367 nstoken = open_netns("at_ns0"); 368 if (!ASSERT_OK_PTR(nstoken, "setns src")) 369 goto done; 370 ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV0); 371 if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan00 ifindex")) 372 goto done; 373 tc_hook.ifindex = ifindex; 374 set_dst_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst); 375 if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd")) 376 goto done; 377 if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd)) 378 goto done; 379 close_netns(nstoken); 380 381 /* use veth1 ip 2 as tunnel source ip */ 382 local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map); 383 if (!ASSERT_GE(local_ip_map_fd, 0, "get local_ip_map fd")) 384 goto done; 385 local_ip = IP6_ADDR2_HEX_VETH1; 386 err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY); 387 if (!ASSERT_OK(err, "update bpf local_ip_map")) 388 goto done; 389 390 /* ping test */ 391 err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0); 392 if (!ASSERT_OK(err, "test_ping")) 393 goto done; 394 395 done: 396 /* delete ipv6 vxlan tunnel */ 397 delete_ip6vxlan_tunnel(); 398 if (local_ip_map_fd >= 0) 399 close(local_ip_map_fd); 400 if (skel) 401 test_tunnel_kern__destroy(skel); 402 } 403 404 #define RUN_TEST(name) \ 405 ({ \ 406 if (test__start_subtest(#name)) { \ 407 test_ ## name(); \ 408 } \ 409 }) 410 411 static void *test_tunnel_run_tests(void *arg) 412 { 413 cleanup(); 414 config_device(); 415 416 RUN_TEST(vxlan_tunnel); 417 RUN_TEST(ip6vxlan_tunnel); 418 419 cleanup(); 420 421 return NULL; 422 } 423 424 void test_tunnel(void) 425 { 426 pthread_t test_thread; 427 int err; 428 429 /* Run the tests in their own thread to isolate the namespace changes 430 * so they do not affect the environment of other tests. 431 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns()) 432 */ 433 err = pthread_create(&test_thread, NULL, &test_tunnel_run_tests, NULL); 434 if (ASSERT_OK(err, "pthread_create")) 435 ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join"); 436 } 437