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