diff options
author | Martin KaFai Lau <martin.lau@kernel.org> | 2022-11-11 14:00:20 -0800 |
---|---|---|
committer | Martin KaFai Lau <martin.lau@kernel.org> | 2022-11-14 14:51:43 -0800 |
commit | d2d2160958599732349aa30bb163d9d9a78cfe3a (patch) | |
tree | 65b9f2ca968d756f5eacbc3ab7bd91ce111f917b | |
parent | de763fbb2c5bfad1ab7c4232e6a804726f0b0744 (diff) | |
download | bpf-next-test_veth_perf.tar.gz |
bpf: A veth perf testtest_veth_perf
A test that test the veth performance. To avoid the ip routing
overhead, bpf_redirect_peer (phy-eth0 => veth) and
bpf_redirect_neigh (veth => phy-eth0) is used. In particular,
veth backlog queue performance is the interest here.
eth0 (phy-nic) < -- > veth0 (host) < -- > veth_eth0 (netns)
host:
VETH_ETH0_ADDR6="ip6-addr-at-veth_eth0(netns)" VETH0_ADDR="ip6-addr-at-veth0(host)" ./test_progs -v -t veth_perf
... ...
Press any key to cleanup:
netns:
ip netns exec ns_test bash # enter netns
./tcp_rr -6 -P 12345 -Q 64 -R 128 -l 30 -T 36 -U -F 1024 #run test server
client:
./tcp_rr -c -H 2803:6080:c124:5ab::3 -P 12345 -Q 64 -R 128 -l 30 -T 36 -U -F 256
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
-rw-r--r-- | tools/testing/selftests/bpf/prog_tests/veth_perf.c | 173 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/progs/veth_perf.c | 74 |
2 files changed, 247 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/veth_perf.c b/tools/testing/selftests/bpf/prog_tests/veth_perf.c new file mode 100644 index 00000000000000..f5238f5f93a8ef --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/veth_perf.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ +#define _GNU_SOURCE +#include <sched.h> +#include <net/if.h> +#include "test_progs.h" +#include "network_helpers.h" +#include "veth_perf.skel.h" + +static int eth0_ifindex; +static int veth0_ifindex; +static int veth_eth0_ifindex; + +static const char *veth_eth0_addr6_str = "2803:6080:c124:5ab::3"; +static const char *veth0_addr6_str = "2803:6080:c124:5ab::2"; +static const char *veth_eth0_mac = "00:22:33:44:55:66"; +static const char *veth0_mac = "00:11:22:33:44:55"; +static __u32 veth_eth0_addr6[4]; + +#define SYS(fmt, ...) \ + ({ \ + char cmd[1024]; \ + snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ + if (!ASSERT_OK(system(cmd), cmd)) \ + goto fail; \ + }) + +#define PIN_FNAME(__file) "/sys/fs/bpf/" #__file +#define PIN(__prog) ({ \ + int err = bpf_program__pin(skel->progs.__prog, PIN_FNAME(__prog)); \ + if (!ASSERT_OK(err, "pin " #__prog)) \ + goto fail; \ + }) +#define UNPIN(__prog) ({ bpf_program__unpin(skel->progs.__prog, PIN_FNAME(__prog)); }) + +static int saved_netns = -1; + +static int switch_netns(const char *name) +{ + char nspath[PATH_MAX]; + int err, nsfd; + + if (!ASSERT_EQ(saved_netns, -1, "saved_netns")) + return -1; + + saved_netns = open("/proc/self/ns/net", O_RDONLY); + if (!ASSERT_NEQ(saved_netns, -1, "open /proc/self/ns/net")) + return -1; + + snprintf(nspath, sizeof(nspath), "%s/%s", "/var/run/netns", name); + nsfd = open(nspath, O_RDONLY | O_CLOEXEC); + if (!ASSERT_GE(nsfd, 0, "open netns fd")) { + saved_netns = -1; + return -1; + } + + err = setns(nsfd, CLONE_NEWNET); + if (!ASSERT_OK(err, "setns")) { + saved_netns = -1; + return -1; + } + + return 0; +} + +static int restore_netns(void) +{ + int err; + + if (!ASSERT_NEQ(saved_netns, -1, "saved_netns")) + return -1; + + err = setns(saved_netns, CLONE_NEWNET); + if (!ASSERT_OK(err, "setns_by_fd")) + return -1; + + saved_netns = -1; + return 0; +} + +static int setup_veth(void) +{ + SYS("ip link add veth0 type veth peer name veth_eth0"); + + eth0_ifindex = if_nametoindex("eth0"); + if (!ASSERT_NEQ(eth0_ifindex, 0, "eth0_ifindex")) + goto fail; + + veth0_ifindex = if_nametoindex("veth0"); + if (!ASSERT_NEQ(veth0_ifindex, 0, "veth0_ifindex")) + goto fail; + + veth_eth0_ifindex = if_nametoindex("veth_eth0"); + if (!ASSERT_NEQ(veth_eth0_ifindex, 0, "veth_eth0_ifindex")) + goto fail; + + SYS("ip link set veth0 address %s", veth0_mac); + SYS("ip -6 addr add %s/64 dev veth0 nodad", veth0_addr6_str); + SYS("ip link set dev veth0 up"); + + SYS("ip netns add ns_test"); + SYS("ip link set dev veth_eth0 netns ns_test"); + + switch_netns("ns_test"); + SYS("ip link set veth_eth0 address %s", veth_eth0_mac); + SYS("ip -6 addr add %s/64 dev veth_eth0 nodad", veth_eth0_addr6_str); + SYS("ip -6 neigh add %s dev veth_eth0 lladdr %s", veth0_addr6_str, + veth0_mac); + SYS("ip link set dev veth_eth0 up"); + SYS("ip -6 route add default via %s dev veth_eth0", veth0_addr6_str); + restore_netns(); + + system("tc qdisc add dev eth0 clsact >& /dev/null"); + SYS("tc filter add dev eth0 ingress prio 10 bpf da object-pinned " + PIN_FNAME(eth0_ingress)); + + SYS("tc qdisc add dev veth0 clsact"); + SYS("tc filter add dev veth0 ingress prio 10 bpf da object-pinned " + PIN_FNAME(veth0_ingress)); + + return 0; +fail: + system("ip netns del ns_test >& /dev/null"); + system("ip link del veth0 >& /dev/null"); + system("tc filter del ingress dev eth0 prio 10 >& /dev/null"); + return -1; +} + +void test_veth_perf(void) +{ + struct veth_perf *skel; + const char *addr6_str; + int err; + char c; + + addr6_str = getenv("VETH_ETH0_ADDR6"); + if (addr6_str) + veth_eth0_addr6_str = addr6_str; + + addr6_str = getenv("VETH0_ADDR6"); + if (addr6_str) + veth0_addr6_str = addr6_str; + + err = inet_pton(AF_INET6, veth_eth0_addr6_str, veth_eth0_addr6); + if (!ASSERT_EQ(err, 1, "inet_pton")) + return; + + skel = veth_perf__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel")) + return; + PIN(eth0_ingress); + PIN(veth0_ingress); + + if (!ASSERT_OK(setup_veth(), "setup_veth")) + goto fail; + + memcpy(skel->bss->veth_eth0_addr6, veth_eth0_addr6, + sizeof(veth_eth0_addr6)); + skel->bss->eth0 = eth0_ifindex; + skel->bss->veth0 = veth0_ifindex; + + printf("Press any key to cleanup: "); + scanf("%c", &c); + + system("ip netns del ns_test"); + system("ip link del veth0"); + system("tc filter del ingress dev eth0 pref 10"); + +fail: + UNPIN(eth0_ingress); + UNPIN(veth0_ingress); + veth_perf__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/veth_perf.c b/tools/testing/selftests/bpf/progs/veth_perf.c new file mode 100644 index 00000000000000..4136c6769c76d6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/veth_perf.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ +#include <stddef.h> +#include <stdbool.h> + +#include <linux/bpf.h> +#include <linux/stddef.h> +#include <linux/pkt_cls.h> +#include <linux/if_ether.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> + +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_endian.h> + +#ifndef ctx_ptr +# define ctx_ptr(field) (void *)(long)(field) +#endif + +__u32 veth_eth0_addr6[4] = {}; +int veth0 = 0; +int eth0 = 0; + +static bool v6_equal(__u32 *a, __u32 *b) +{ + return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]; +} + +SEC("tc") +int veth0_ingress(struct __sk_buff *skb) +{ + void *data_end = ctx_ptr(skb->data_end); + void *data = ctx_ptr(skb->data); + struct ipv6hdr *ip6h; + + if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6)) + return TC_ACT_OK; + + if (data + sizeof(struct ethhdr) > data_end) + return TC_ACT_SHOT; + + ip6h = (struct ipv6hdr *)(data + sizeof(struct ethhdr)); + if ((void *)(ip6h + 1) > data_end) + return TC_ACT_SHOT; + + return bpf_redirect_neigh(eth0, NULL, 0, 0); +} + +SEC("tc") +int eth0_ingress(struct __sk_buff *skb) +{ + void *data_end = ctx_ptr(skb->data_end); + void *data = ctx_ptr(skb->data); + struct ipv6hdr *ip6h; + + if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6)) + return TC_ACT_UNSPEC; + + if (data + sizeof(struct ethhdr) > data_end) + return TC_ACT_UNSPEC; + + ip6h = (struct ipv6hdr *)(data + sizeof(struct ethhdr)); + if ((void *)(ip6h + 1) > data_end) + return TC_ACT_UNSPEC; + + if (!v6_equal(ip6h->daddr.s6_addr32, veth_eth0_addr6)) + return TC_ACT_UNSPEC; + + if (!veth0) + return TC_ACT_UNSPEC; + + return bpf_redirect_peer(veth0, 0); +} |