lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251120033016.3809474-6-dw@davidwei.uk>
Date: Wed, 19 Nov 2025 19:30:14 -0800
From: David Wei <dw@...idwei.uk>
To: netdev@...r.kernel.org
Cc: Andrew Lunn <andrew+netdev@...n.ch>,
	"David S. Miller" <davem@...emloft.net>,
	Eric Dumazet <edumazet@...gle.com>,
	Jakub Kicinski <kuba@...nel.org>,
	Paolo Abeni <pabeni@...hat.com>,
	Daniel Borkmann <daniel@...earbox.net>
Subject: [PATCH net-next v1 5/7] selftests/net: add bpf skb forwarding program

This is needed for netkit container datapath selftests. Add two things:

  1. nk_forward.bpf.c, a bpf program that forwards skbs matching some
     IPv6 prefix received on eth0 ifindex to a specified netkit ifindex.
  2. nk_forward.c, a C loader program that accepts eth0/netkit ifindex
     and IPv6 prefix.

Selftests will load and unload this bpf program via the loader.

Signed-off-by: David Wei <dw@...idwei.uk>
---
 .../selftests/drivers/net/hw/.gitignore       |   3 +
 .../testing/selftests/drivers/net/hw/Makefile |   9 +-
 .../selftests/drivers/net/hw/nk_forward.bpf.c |  49 +++++++++
 .../selftests/drivers/net/hw/nk_forward.c     | 102 ++++++++++++++++++
 4 files changed, 162 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/drivers/net/hw/nk_forward.bpf.c
 create mode 100644 tools/testing/selftests/drivers/net/hw/nk_forward.c

diff --git a/tools/testing/selftests/drivers/net/hw/.gitignore b/tools/testing/selftests/drivers/net/hw/.gitignore
index 6942bf575497..ca6947f30561 100644
--- a/tools/testing/selftests/drivers/net/hw/.gitignore
+++ b/tools/testing/selftests/drivers/net/hw/.gitignore
@@ -1,3 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 iou-zcrx
 ncdevmem
+nk_forward
+*.skel.h
+tools/
diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile
index 8133d1a0051c..855363bc8d48 100644
--- a/tools/testing/selftests/drivers/net/hw/Makefile
+++ b/tools/testing/selftests/drivers/net/hw/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+ OR MIT
 
-TEST_GEN_FILES = iou-zcrx
+TEST_GEN_FILES = iou-zcrx nk_forward
 
 TEST_PROGS = \
 	csum.py \
@@ -55,3 +55,10 @@ include ../../../net/ynl.mk
 include ../../../net/bpf.mk
 
 $(OUTPUT)/iou-zcrx: LDLIBS += -luring
+
+$(OUTPUT)/nk_forward: $(OUTPUT)/nk_forward.skel.h $(BPFOBJ)
+$(OUTPUT)/nk_forward: CFLAGS += $(CCINCLUDE) -I$(OUTPUT)
+$(OUTPUT)/nk_forward: LDLIBS += $(BPFOBJ) -lelf -lz
+
+$(OUTPUT)/nk_forward.skel.h: $(OUTPUT)/nk_forward.bpf.o
+	bpftool gen skeleton $< name nk_forward > $@
diff --git a/tools/testing/selftests/drivers/net/hw/nk_forward.bpf.c b/tools/testing/selftests/drivers/net/hw/nk_forward.bpf.c
new file mode 100644
index 000000000000..103b259d288a
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/nk_forward.bpf.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <linux/pkt_cls.h>
+#include <linux/if_ether.h>
+#include <linux/ipv6.h>
+#include <linux/in6.h>
+#include <bpf/bpf_endian.h>
+#include <bpf/bpf_helpers.h>
+
+#define TC_ACT_OK 0
+#define ETH_P_IPV6 0x86DD
+
+#define ctx_ptr(field)		(void *)(long)(field)
+
+#define v6_p64_equal(a, b)	(a.s6_addr32[0] == b.s6_addr32[0] && \
+				 a.s6_addr32[1] == b.s6_addr32[1])
+
+volatile __u32 netkit_ifindex;
+volatile __u8 ipv6_prefix[16] __attribute__((aligned(4)));
+
+SEC("tc/ingress")
+int tc_redirect_peer(struct __sk_buff *skb)
+{
+	void *data_end = ctx_ptr(skb->data_end);
+	void *data = ctx_ptr(skb->data);
+	struct in6_addr *peer_addr;
+	struct ipv6hdr *ip6h;
+	struct ethhdr *eth;
+
+	peer_addr = (struct in6_addr *)ipv6_prefix;
+
+	if (skb->protocol != bpf_htons(ETH_P_IPV6))
+		return TC_ACT_OK;
+
+	eth = data;
+	if ((void *)(eth + 1) > data_end)
+		return TC_ACT_OK;
+
+	ip6h = data + sizeof(struct ethhdr);
+	if ((void *)(ip6h + 1) > data_end)
+		return TC_ACT_OK;
+
+	if (!v6_p64_equal(ip6h->daddr, (*peer_addr)))
+		return TC_ACT_OK;
+
+	return bpf_redirect_peer(netkit_ifindex, 0);
+}
+
+char __license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/drivers/net/hw/nk_forward.c b/tools/testing/selftests/drivers/net/hw/nk_forward.c
new file mode 100644
index 000000000000..9519d20cd363
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/nk_forward.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <linux/in6.h>
+#include <linux/if_link.h>
+#include <bpf/libbpf.h>
+#include <bpf/bpf.h>
+
+#include "nk_forward.skel.h"
+
+static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
+{
+	return vfprintf(stderr, format, args);
+}
+
+static void usage(const char *prog)
+{
+	fprintf(stderr, "Usage: %s -n <netkit_ifindex> -e <eth0_ifindex> -i <ipv6_prefix>\n", prog);
+	fprintf(stderr, "  -n  netkit interface index\n");
+	fprintf(stderr, "  -e  eth0 interface index\n");
+	fprintf(stderr, "  -i  IPv6 prefix to match\n");
+	fprintf(stderr, "  -h  show this help\n");
+}
+
+int main(int argc, char **argv)
+{
+	unsigned int netkit_ifindex = 0;
+	const char *ipv6_prefix = NULL;
+	unsigned int eth0_ifindex = 0;
+	struct nk_forward *skel;
+	struct in6_addr ip6_addr;
+	struct bpf_link *link;
+	int opt, err, i;
+
+	while ((opt = getopt(argc, argv, "n:e:i:h")) != -1) {
+		switch (opt) {
+		case 'n':
+			netkit_ifindex = atoi(optarg);
+			break;
+		case 'e':
+			eth0_ifindex = atoi(optarg);
+			break;
+		case 'i':
+			ipv6_prefix = optarg;
+			break;
+		case 'h':
+		default:
+			usage(argv[0]);
+			return opt == 'h' ? 0 : 1;
+		}
+	}
+
+	if (!netkit_ifindex || !eth0_ifindex || !ipv6_prefix) {
+		fprintf(stderr, "Error: All options -n, -e, and -i are required\n\n");
+		usage(argv[0]);
+		return 1;
+	}
+
+	if (inet_pton(AF_INET6, ipv6_prefix, &ip6_addr) != 1) {
+		fprintf(stderr, "Error: Invalid IPv6 address: %s\n", ipv6_prefix);
+		return 1;
+	}
+
+	libbpf_set_print(libbpf_print_fn);
+	skel = nk_forward__open();
+	if (!skel) {
+		fprintf(stderr, "Error: Failed to open BPF skeleton\n");
+		return 1;
+	}
+
+	skel->bss->netkit_ifindex = netkit_ifindex;
+	memcpy((void *)&skel->bss->ipv6_prefix, &ip6_addr, sizeof(struct in6_addr));
+
+	err = nk_forward__load(skel);
+	if (err) {
+		fprintf(stderr, "Error: Failed to load BPF skeleton: %d\n", err);
+		goto cleanup;
+	}
+
+	LIBBPF_OPTS(bpf_tcx_opts, opts);
+	link = bpf_program__attach_tcx(skel->progs.tc_redirect_peer, eth0_ifindex, &opts);
+	if (!link) {
+		err = -errno;
+		fprintf(stderr, "Error: Failed to attach TC program to ifindex %u: %s\n",
+			eth0_ifindex, strerror(errno));
+		goto cleanup;
+	}
+
+	while (1)
+		sleep(1);
+
+cleanup:
+	bpf_link__destroy(link);
+	nk_forward__destroy(skel);
+	return err != 0;
+}
-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ