// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* * End-to-end eBPF tunnel test suite * The file tests BPF network tunnel implementation. * * Topology: * --------- * root namespace | at_ns0 namespace * | * ----------- | ----------- * | tnl dev | | | tnl dev | (overlay network) * ----------- | ----------- * metadata-mode | metadata-mode * with bpf | with bpf * | * ---------- | ---------- * | veth1 | --------- | veth0 | (underlay network) * ---------- peer ---------- * * * Device Configuration * -------------------- * root namespace with metadata-mode tunnel + BPF * Device names and addresses: * veth1 IP 1: 172.16.1.200, IPv6: 00::22 (underlay) * IP 2: 172.16.1.20, IPv6: 00::bb (underlay) * tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay) * * Namespace at_ns0 with native tunnel * Device names and addresses: * veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay) * tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay) * * * End-to-end ping packet flow * --------------------------- * Most of the tests start by namespace creation, device configuration, * then ping the underlay and overlay network. When doing 'ping 10.1.1.100' * from root namespace, the following operations happen: * 1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev. * 2) Tnl device's egress BPF program is triggered and set the tunnel metadata, * with local_ip=172.16.1.200, remote_ip=172.16.1.100. BPF program choose * the primary or secondary ip of veth1 as the local ip of tunnel. The * choice is made based on the value of bpf map local_ip_map. * 3) Outer tunnel header is prepended and route the packet to veth1's egress. * 4) veth0's ingress queue receive the tunneled packet at namespace at_ns0. * 5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet. * 6) Forward the packet to the overlay tnl dev.
*/
staticint config_device(void)
{
SYS(fail, "ip netns add at_ns0");
SYS(fail, "ip link add veth0 address " MAC_VETH1 " type veth peer name veth1");
SYS(fail, "ip link set veth0 netns at_ns0");
SYS(fail, "ip addr add " IP4_ADDR1_VETH1 "/24 dev veth1");
SYS(fail, "ip link set dev veth1 up mtu 1500");
SYS(fail, "ip netns exec at_ns0 ip addr add " IP4_ADDR_VETH0 "/24 dev veth0");
SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up mtu 1500");
return 0;
fail: return -1;
}
staticvoid cleanup(void)
{
SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0");
SYS_NOFAIL("ip link del veth1");
SYS_NOFAIL("ip link del %s", VXLAN_TUNL_DEV1);
SYS_NOFAIL("ip link del %s", IP6VXLAN_TUNL_DEV1);
}
staticint add_vxlan_tunnel(void)
{ /* at_ns0 namespace */
SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external gbp dstport 4789",
VXLAN_TUNL_DEV0);
SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up",
VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24",
VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev %s",
IP4_ADDR_TUNL_DEV1, MAC_TUNL_DEV1, VXLAN_TUNL_DEV0);
SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev veth0",
IP4_ADDR2_VETH1, MAC_VETH1);
/* root namespace */
SYS(fail, "ip link add dev %s type vxlan external gbp dstport 4789",
VXLAN_TUNL_DEV1);
SYS(fail, "ip link set dev %s address %s up", VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
SYS(fail, "ip addr add dev %s %s/24", VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
SYS(fail, "ip neigh add %s lladdr %s dev %s",
IP4_ADDR_TUNL_DEV0, MAC_TUNL_DEV0, VXLAN_TUNL_DEV1);
return 0;
fail: return -1;
}
staticvoid delete_vxlan_tunnel(void)
{
SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
VXLAN_TUNL_DEV0);
SYS_NOFAIL("ip link delete dev %s", VXLAN_TUNL_DEV1);
}
staticint add_ip6vxlan_tunnel(void)
{
SYS(fail, "ip netns exec at_ns0 ip -6 addr add %s/96 dev veth0",
IP6_ADDR_VETH0);
SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up");
SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR1_VETH1);
SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR2_VETH1);
SYS(fail, "ip link set dev veth1 up");
/* at_ns0 namespace */
SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external dstport 4789",
IP6VXLAN_TUNL_DEV0);
SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24",
IP6VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up",
IP6VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
/* root namespace */
SYS(fail, "ip link add dev %s type vxlan external dstport 4789",
IP6VXLAN_TUNL_DEV1);
SYS(fail, "ip addr add dev %s %s/24", IP6VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
SYS(fail, "ip link set dev %s address %s up",
IP6VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
return 0;
fail: return -1;
}
staticvoid delete_ip6vxlan_tunnel(void)
{
SYS_NOFAIL("ip netns exec at_ns0 ip -6 addr delete %s/96 dev veth0",
IP6_ADDR_VETH0);
SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR1_VETH1);
SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR2_VETH1);
SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
IP6VXLAN_TUNL_DEV0);
SYS_NOFAIL("ip link delete dev %s", IP6VXLAN_TUNL_DEV1);
}
enum ipip_encap {
NONE = 0,
FOU = 1,
GUE = 2,
};
staticint set_ipip_encap(constchar *ipproto, constchar *type)
{
SYS(fail, "ip -n at_ns0 fou add port 5555 %s", ipproto);
SYS(fail, "ip -n at_ns0 link set dev %s type ipip encap %s",
IPIP_TUNL_DEV0, type);
SYS(fail, "ip -n at_ns0 link set dev %s type ipip encap-dport 5555",
IPIP_TUNL_DEV0);
return 0;
fail: return -1;
}
staticint set_ipv4_addr(constchar *dev0, constchar *dev1)
{
SYS(fail, "ip -n at_ns0 link set dev %s up", dev0);
SYS(fail, "ip -n at_ns0 addr add dev %s %s/24", dev0, IP4_ADDR_TUNL_DEV0);
SYS(fail, "ip link set dev %s up", dev1);
SYS(fail, "ip addr add dev %s %s/24", dev1, IP4_ADDR_TUNL_DEV1);
return 0;
fail: return 1;
}
staticint add_ipip_tunnel(enum ipip_encap encap)
{ int err; constchar *ipproto, *type;
switch (encap) { case FOU:
ipproto = "ipproto 4";
type = "fou"; break; case GUE:
ipproto = "gue";
type = ipproto; break; default:
ipproto = NULL;
type = ipproto;
}
/* at_ns0 namespace */
SYS(fail, "ip -n at_ns0 link add dev %s type ipip local %s remote %s",
IPIP_TUNL_DEV0, IP4_ADDR_VETH0, IP4_ADDR1_VETH1);
if (type && ipproto) {
err = set_ipip_encap(ipproto, type); if (!ASSERT_OK(err, "set_ipip_encap")) goto fail;
}
SYS(fail, "ip -n at_ns0 link set dev %s up", IPIP_TUNL_DEV0);
SYS(fail, "ip -n at_ns0 addr add dev %s %s/24",
IPIP_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
/* root namespace */ if (type && ipproto)
SYS(fail, "ip fou add port 5555 %s", ipproto);
SYS(fail, "ip link add dev %s type ipip external", IPIP_TUNL_DEV1);
SYS(fail, "ip link set dev %s up", IPIP_TUNL_DEV1);
SYS(fail, "ip addr add dev %s %s/24", IPIP_TUNL_DEV1,
IP4_ADDR_TUNL_DEV1);
return 0;
fail: return -1;
}
staticvoid delete_ipip_tunnel(void)
{
SYS_NOFAIL("ip -n at_ns0 link delete dev %s", IPIP_TUNL_DEV0);
SYS_NOFAIL("ip -n at_ns0 fou del port 5555");
SYS_NOFAIL("ip link delete dev %s", IPIP_TUNL_DEV1);
SYS_NOFAIL("ip fou del port 5555");
}
SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s", dev0);
SYS_NOFAIL("ip link delete dev %s", dev1);
}
staticint set_ipv6_addr(constchar *dev0, constchar *dev1)
{ /* disable IPv6 DAD because it might take too long and fail tests */
SYS(fail, "ip -n at_ns0 addr add %s/96 dev veth0 nodad", IP6_ADDR_VETH0);
SYS(fail, "ip -n at_ns0 link set dev veth0 up");
SYS(fail, "ip addr add %s/96 dev veth1 nodad", IP6_ADDR1_VETH1);
SYS(fail, "ip link set dev veth1 up");
SYS(fail, "ip -n at_ns0 addr add dev %s %s/24", dev0, IP4_ADDR_TUNL_DEV0);
SYS(fail, "ip -n at_ns0 addr add dev %s %s/96 nodad", dev0, IP6_ADDR_TUNL_DEV0);
SYS(fail, "ip -n at_ns0 link set dev %s up", dev0);
SYS(fail, "ip addr add dev %s %s/24", dev1, IP4_ADDR_TUNL_DEV1);
SYS(fail, "ip addr add dev %s %s/96 nodad", dev1, IP6_ADDR_TUNL_DEV1);
SYS(fail, "ip link set dev %s up", dev1); return 0;
fail: return 1;
}
/* load and attach bpf prog to tunnel dev tc hook point */
skel = test_tunnel_kern__open_and_load(); if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) goto done;
get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src);
set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src); if (generic_attach(VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) goto done;
/* load and attach bpf prog to veth dev tc hook point */
set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst); if (generic_attach_igr("veth1", set_dst_prog_fd)) goto done;
/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
nstoken = open_netns("at_ns0"); if (!ASSERT_OK_PTR(nstoken, "setns src")) goto done;
set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst); if (generic_attach_egr(VXLAN_TUNL_DEV0, set_dst_prog_fd)) goto done;
close_netns(nstoken);
/* use veth1 ip 2 as tunnel source ip */
local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map); if (!ASSERT_GE(local_ip_map_fd, 0, "bpf_map__fd")) goto done;
local_ip = IP4_ADDR2_HEX_VETH1;
err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY); if (!ASSERT_OK(err, "update bpf local_ip_map")) goto done;
/* ping test */
ping_dev0();
done: /* delete vxlan tunnel */
delete_vxlan_tunnel(); if (local_ip_map_fd >= 0)
close(local_ip_map_fd); if (skel)
test_tunnel_kern__destroy(skel);
}
staticvoid test_ip6vxlan_tunnel(void)
{ struct test_tunnel_kern *skel = NULL; struct nstoken *nstoken; int local_ip_map_fd = -1; int set_src_prog_fd, get_src_prog_fd; int set_dst_prog_fd; int key = 0;
uint local_ip; int err;
/* load and attach bpf prog to tunnel dev tc hook point */
skel = test_tunnel_kern__open_and_load(); if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) goto done;
staticvoid test_xfrm_tunnel(void)
{
LIBBPF_OPTS(bpf_xdp_attach_opts, opts); struct test_tunnel_kern *skel = NULL; int xdp_prog_fd; int tc_prog_fd; int ifindex; int err;
err = add_xfrm_tunnel(); if (!ASSERT_OK(err, "add_xfrm_tunnel")) return;
skel = test_tunnel_kern__open_and_load(); if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) goto done;
/* attach tc prog to tunnel dev */
tc_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state); if (generic_attach_igr("veth1", tc_prog_fd)) goto done;
/* attach xdp prog to tunnel dev */
ifindex = if_nametoindex("veth1"); if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex")) goto done;
xdp_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state_xdp); if (!ASSERT_GE(xdp_prog_fd, 0, "bpf_program__fd")) goto done;
err = bpf_xdp_attach(ifindex, xdp_prog_fd, XDP_FLAGS_REPLACE, &opts); if (!ASSERT_OK(err, "bpf_xdp_attach")) goto done;
ping_dev1();
if (!ASSERT_EQ(skel->bss->xfrm_reqid, 1, "req_id")) goto done; if (!ASSERT_EQ(skel->bss->xfrm_spi, XFRM_SPI_IN_TO_OUT, "spi")) goto done; if (!ASSERT_EQ(skel->bss->xfrm_remote_ip, 0xac100164, "remote_ip")) goto done; if (!ASSERT_EQ(skel->bss->xfrm_replay_window, 42, "replay_window")) goto done;
done:
delete_xfrm_tunnel(); if (skel)
test_tunnel_kern__destroy(skel);
}
void test_tunnel(void)
{
pthread_t test_thread; int err;
/* Run the tests in their own thread to isolate the namespace changes * so they do not affect the environment of other tests. * (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
*/
err = pthread_create(&test_thread, NULL, &test_tunnel_run_tests, NULL); if (ASSERT_OK(err, "pthread_create"))
ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.