Add a selftest that exercises the bpf_netpoll kfuncs end-to-end with IPv6, reusing the code that was added for IPv4. Signed-off-by: Mahe Tardy --- .../selftests/bpf/prog_tests/netpoll.c | 42 +++++++++++++++---- .../selftests/bpf/progs/netpoll_sanity.c | 33 +++++++++++---- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/netpoll.c b/tools/testing/selftests/bpf/prog_tests/netpoll.c index 1cfac4b13e7d..eac0378c426a 100644 --- a/tools/testing/selftests/bpf/prog_tests/netpoll.c +++ b/tools/testing/selftests/bpf/prog_tests/netpoll.c @@ -9,15 +9,20 @@ #include "netpoll_sanity.skel.h" #define NS_TEST "netpoll_sanity_ns" +#define NS_TEST_V6 "netpoll_sanity_ns_v6" #define DUMMY_DEV "dummy0" #define DUMMY_IP "10.0.0.1" #define REMOTE_IP "10.0.0.2" +#define DUMMY_IP6 "fd00::1" +#define REMOTE_IP6 "fd00::2" -void test_netpoll_sanity(void) +static void run_netpoll_test(const char *ns_name, const char *local_ip, + const char *remote_ip, bool ipv6) { LIBBPF_OPTS(bpf_test_run_opts, opts); struct nstoken *nstoken = NULL; struct netpoll_sanity *skel; + struct in6_addr addr6; int err, pfd, fd; skel = netpoll_sanity__open_and_load(); @@ -25,18 +30,28 @@ void test_netpoll_sanity(void) return; /* Create a network namespace with a dummy device */ - SYS(fail, "ip netns add %s", NS_TEST); - SYS(fail, "ip -net %s link add %s type dummy", NS_TEST, DUMMY_DEV); - SYS(fail, "ip -net %s addr add %s/24 dev %s", NS_TEST, DUMMY_IP, DUMMY_DEV); - SYS(fail, "ip -net %s link set %s up", NS_TEST, DUMMY_DEV); - - nstoken = open_netns(NS_TEST); + SYS(fail, "ip netns add %s", ns_name); + SYS(fail, "ip -net %s link add %s type dummy", ns_name, DUMMY_DEV); + if (ipv6) + SYS(fail, "ip -net %s addr add %s/64 dev %s", ns_name, local_ip, DUMMY_DEV); + else + SYS(fail, "ip -net %s addr add %s/24 dev %s", ns_name, local_ip, DUMMY_DEV); + SYS(fail, "ip -net %s link set %s up", ns_name, DUMMY_DEV); + + nstoken = open_netns(ns_name); if (!ASSERT_OK_PTR(nstoken, "open_netns")) goto fail; /* Configure the BPF program globals */ snprintf(skel->bss->dev_name, sizeof(skel->bss->dev_name), "%s", DUMMY_DEV); - skel->bss->remote_ip = inet_addr(REMOTE_IP); + if (ipv6) { + if (inet_pton(AF_INET6, remote_ip, &addr6) != 1) + goto fail; + __builtin_memcpy(&skel->bss->remote_ip6, &addr6, sizeof(addr6)); + skel->bss->ipv6 = 1; + } else { + skel->bss->remote_ip = inet_addr(remote_ip); + } skel->bss->local_port = 5555; skel->bss->remote_port = 6666; skel->bss->remote_mac[0] = 0xaa; @@ -87,6 +102,15 @@ void test_netpoll_sanity(void) fail: if (nstoken) close_netns(nstoken); - SYS_NOFAIL("ip netns del " NS_TEST " &> /dev/null"); + SYS_NOFAIL("ip netns del %s &> /dev/null", ns_name); netpoll_sanity__destroy(skel); } + +void test_netpoll_sanity(void) +{ + if (test__start_subtest("ipv4")) + run_netpoll_test(NS_TEST, DUMMY_IP, REMOTE_IP, false); + + if (test__start_subtest("ipv6")) + run_netpoll_test(NS_TEST_V6, DUMMY_IP6, REMOTE_IP6, true); +} diff --git a/tools/testing/selftests/bpf/progs/netpoll_sanity.c b/tools/testing/selftests/bpf/progs/netpoll_sanity.c index 9e1e595eff2c..26303632ebde 100644 --- a/tools/testing/selftests/bpf/progs/netpoll_sanity.c +++ b/tools/testing/selftests/bpf/progs/netpoll_sanity.c @@ -12,9 +12,11 @@ /* Globals for passing config from userspace */ char dev_name[16] = {}; __be32 remote_ip; +struct in6_addr remote_ip6; __u16 local_port; __u16 remote_port; __u8 remote_mac[6] = {}; +int ipv6; /* Results */ int status; @@ -35,10 +37,14 @@ int netpoll_setup_test(void *ctx) status = 0; __builtin_memcpy(opts.dev_name, dev_name, 16); - opts.remote_ip = remote_ip; + if (ipv6) + __builtin_memcpy(&opts.remote_ip6, &remote_ip6, sizeof(remote_ip6)); + else + opts.remote_ip = remote_ip; opts.local_port = local_port; opts.remote_port = remote_port; __builtin_memcpy(opts.remote_mac, remote_mac, 6); + opts.ipv6 = ipv6; bnp = bpf_netpoll_create(&opts, sizeof(opts), &err); if (!bnp) { @@ -88,7 +94,9 @@ int BPF_PROG(netpoll_dummy_xmit, struct sk_buff *skb, struct net_device *dev) unsigned char *data; struct ethhdr eth; struct iphdr ip; + struct ipv6hdr ip6; struct udphdr udp; + unsigned int offset; if (bpf_probe_read_kernel(&data, sizeof(data), &skb->data) < 0) return 0; @@ -97,19 +105,28 @@ int BPF_PROG(netpoll_dummy_xmit, struct sk_buff *skb, struct net_device *dev) if (bpf_probe_read_kernel(ð, sizeof(eth), data) < 0) return 0; - if (eth.h_proto != bpf_htons(ETH_P_IP)) - return 0; - if (bpf_probe_read_kernel(&ip, sizeof(ip), data + sizeof(struct ethhdr)) < 0) - return 0; - if (ip.protocol != IPPROTO_UDP) + if (eth.h_proto == bpf_htons(ETH_P_IP)) { + if (bpf_probe_read_kernel(&ip, sizeof(ip), data + sizeof(struct ethhdr)) < 0) + return 0; + if (ip.protocol != IPPROTO_UDP) + return 0; + offset = sizeof(struct ethhdr) + (ip.ihl * 4); + } else if (eth.h_proto == bpf_htons(ETH_P_IPV6)) { + if (bpf_probe_read_kernel(&ip6, sizeof(ip6), data + sizeof(struct ethhdr)) < 0) + return 0; + if (ip6.nexthdr != IPPROTO_UDP) + return 0; + offset = sizeof(struct ethhdr) + sizeof(struct ipv6hdr); + } else { return 0; + } - if (bpf_probe_read_kernel(&udp, sizeof(udp), data + sizeof(struct ethhdr) + (ip.ihl * 4)) < 0) + if (bpf_probe_read_kernel(&udp, sizeof(udp), data + offset) < 0) return 0; if (udp.dest != bpf_htons(remote_port)) return 0; - if (bpf_probe_read_kernel(&driver_xmit, sizeof(driver_xmit), data + sizeof(struct ethhdr) + (ip.ihl * 4) + sizeof(struct udphdr)) < 0) + if (bpf_probe_read_kernel(&driver_xmit, sizeof(driver_xmit), data + offset + sizeof(struct udphdr)) < 0) return 0; return 0; -- 2.34.1