From: Mahe Tardy <mahe.tardy@gmail.com>
To: bpf@vger.kernel.org
Cc: andrew+netdev@lunn.ch, andrii@kernel.org, ast@kernel.org,
daniel@iogearbox.net, davem@davemloft.net, eddyz87@gmail.com,
edumazet@google.com, john.fastabend@gmail.com, kuba@kernel.org,
liamwisehart@meta.com, martin.lau@linux.dev, pabeni@redhat.com,
song@kernel.org, netdev@vger.kernel.org,
Mahe Tardy <mahe.tardy@gmail.com>
Subject: [PATCH bpf-next 3/6] selftests/bpf: Add ksock kfunc test
Date: Mon, 6 Jul 2026 09:35:22 +0000 [thread overview]
Message-ID: <20260706093525.13030-4-mahe.tardy@gmail.com> (raw)
In-Reply-To: <20260706093525.13030-1-mahe.tardy@gmail.com>
Add a selftest that exercises the ksock kfuncs end-to-end. One sycall
bpf setup program creates a ksock context and connect the socket.
Another syscall bpf program lookup the context and send test data.
The userspace harness create a network namespace and a new socket on
loopback, run the setup and send syscall bpf progs then check that the
userspace socket received the data from bpf.
Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
---
.../testing/selftests/bpf/prog_tests/ksock.c | 165 ++++++++++++++++++
.../testing/selftests/bpf/progs/ksock_basic.c | 68 ++++++++
.../selftests/bpf/progs/ksock_common.h | 73 ++++++++
3 files changed, 306 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/ksock.c
create mode 100644 tools/testing/selftests/bpf/progs/ksock_basic.c
create mode 100644 tools/testing/selftests/bpf/progs/ksock_common.h
diff --git a/tools/testing/selftests/bpf/prog_tests/ksock.c b/tools/testing/selftests/bpf/prog_tests/ksock.c
new file mode 100644
index 000000000000..085ddb59067e
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/ksock.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Isovalent */
+
+#include <arpa/inet.h>
+
+#include "test_progs.h"
+#include "network_helpers.h"
+#include "ksock_basic.skel.h"
+
+#define NS_TEST "ksock_basic_ns"
+#define LOOPBACK_IP "127.0.0.1"
+#define RECV_PORT 7777
+#define RECV_TIMEOUT_SEC 5
+
+struct ksock_test_env {
+ const char *netns;
+ bool netns_created;
+ struct nstoken *nstoken;
+ struct sockaddr_in addr;
+ int rfd;
+ char buf[32];
+};
+
+static bool ksock_test_env_setup(struct ksock_test_env *env, const char *netns)
+{
+ struct timeval tv;
+ int err;
+
+ memset(env, 0, sizeof(*env));
+ env->netns = netns;
+ env->rfd = -1;
+
+ SYS(fail, "ip netns add %s", netns);
+ env->netns_created = true;
+ SYS(fail, "ip -net %s link set lo up", netns);
+
+ env->nstoken = open_netns(netns);
+ if (!ASSERT_OK_PTR(env->nstoken, "open_netns"))
+ goto fail;
+
+ env->rfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (!ASSERT_OK_FD(env->rfd, "receiver socket"))
+ goto fail;
+
+ env->addr.sin_family = AF_INET;
+ env->addr.sin_addr.s_addr = inet_addr(LOOPBACK_IP);
+ env->addr.sin_port = htons(RECV_PORT);
+
+ err = bind(env->rfd, (struct sockaddr *)&env->addr, sizeof(env->addr));
+ if (!ASSERT_OK(err, "bind receiver"))
+ goto fail;
+
+ tv.tv_sec = RECV_TIMEOUT_SEC;
+ tv.tv_usec = 0;
+ err = setsockopt(env->rfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ if (!ASSERT_OK(err, "set rcvtimeo"))
+ goto fail;
+
+ return true;
+
+fail:
+ if (env->rfd >= 0) {
+ close(env->rfd);
+ env->rfd = -1;
+ }
+ if (env->nstoken) {
+ close_netns(env->nstoken);
+ env->nstoken = NULL;
+ }
+ if (env->netns_created) {
+ SYS_NOFAIL("ip netns del %s >/dev/null 2>&1", netns);
+ env->netns_created = false;
+ }
+ return false;
+}
+
+static void ksock_test_env_cleanup(struct ksock_test_env *env)
+{
+ if (env->rfd >= 0)
+ close(env->rfd);
+ if (env->nstoken)
+ close_netns(env->nstoken);
+ if (env->netns_created) {
+ SYS_NOFAIL("ip netns del %s >/dev/null 2>&1", env->netns);
+ env->netns_created = false;
+ }
+}
+
+static void ksock_assert_recv(struct ksock_test_env *env, const char *data,
+ size_t data_sz)
+{
+ ssize_t n;
+
+ memset(env->buf, 0, sizeof(env->buf));
+ n = recvfrom(env->rfd, env->buf, sizeof(env->buf), 0, NULL, NULL);
+ if (!ASSERT_EQ(n, data_sz, "recvfrom len"))
+ return;
+ ASSERT_MEMEQ(env->buf, data, data_sz, "payload match");
+}
+
+static bool ksock_setup_ctx(struct ksock_basic *skel)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, opts);
+ int err, pfd;
+
+ skel->bss->ipv4_remote = inet_addr(LOOPBACK_IP);
+ skel->bss->remote_port = RECV_PORT;
+
+ pfd = bpf_program__fd(skel->progs.ksock_setup);
+ if (!ASSERT_OK_FD(pfd, "ksock_setup fd"))
+ return false;
+
+ err = bpf_prog_test_run_opts(pfd, &opts);
+ if (!ASSERT_OK(err, "ksock_setup run"))
+ return false;
+ if (!ASSERT_OK(opts.retval, "ksock_setup retval"))
+ return false;
+
+ return true;
+}
+
+void test_ksock_basic(void)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, opts);
+ struct ksock_test_env env;
+ struct ksock_basic *skel;
+ int err, pfd;
+
+ skel = ksock_basic__open();
+ if (!ASSERT_OK_PTR(skel, "skel open"))
+ return;
+
+ err = ksock_basic__load(skel);
+ if (!ASSERT_OK(err, "skel load")) {
+ ksock_basic__destroy(skel);
+ return;
+ }
+
+ if (!ksock_test_env_setup(&env, NS_TEST))
+ goto fail;
+
+ /* Step 1: Run the setup SYSCALL prog to create ksock */
+ if (!ksock_setup_ctx(skel))
+ goto fail;
+
+ /* Step 2: Run the send SYSCALL prog */
+ pfd = bpf_program__fd(skel->progs.ksock_send);
+ if (!ASSERT_OK_FD(pfd, "ksock_send fd"))
+ goto fail;
+
+ err = bpf_prog_test_run_opts(pfd, &opts);
+ if (!ASSERT_OK(err, "ksock_send run"))
+ goto fail;
+ if (!ASSERT_EQ(opts.retval,
+ sizeof(skel->data->send_data), "sendmsg bytes"))
+ goto fail;
+
+ /* Step 3: Receive and verify the data */
+ ksock_assert_recv(&env, skel->data->send_data,
+ sizeof(skel->data->send_data));
+
+fail:
+ ksock_test_env_cleanup(&env);
+ ksock_basic__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/ksock_basic.c b/tools/testing/selftests/bpf/progs/ksock_basic.c
new file mode 100644
index 000000000000..e8131932d97b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/ksock_basic.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Isovalent */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_endian.h>
+#include "bpf_tracing_net.h"
+#include "ksock_common.h"
+
+__be32 ipv4_remote;
+__u16 remote_port;
+
+char send_data[32] = "hello from bpf ksock";
+
+SEC("syscall")
+int ksock_setup(void *ctx)
+{
+ struct bpf_ksock_create_opts create_opts = {};
+ struct bpf_ksock_addr_opts addr_opts = {};
+ struct bpf_ksock *ks;
+ int err = 0;
+
+ create_opts.family = AF_INET;
+ create_opts.type = SOCK_DGRAM;
+ create_opts.protocol = IPPROTO_UDP;
+
+ ks = bpf_ksock_create(&create_opts, sizeof(create_opts), &err);
+ if (!ks)
+ return err;
+
+ addr_opts.family = AF_INET;
+ addr_opts.port = remote_port;
+ addr_opts.ipv4_addr = ipv4_remote;
+
+ err = bpf_ksock_connect(ks, &addr_opts, sizeof(addr_opts));
+ if (err) {
+ bpf_ksock_release(ks);
+ return err;
+ }
+
+ err = ksock_ctx_insert(ks);
+ if (err && err != -EEXIST)
+ return err;
+ return 0;
+}
+
+SEC("syscall")
+int ksock_send(void *ctx)
+{
+ struct __ksock_ctx_value *v;
+ struct bpf_ksock *ks;
+ int send = -1;
+
+ v = ksock_ctx_value_lookup();
+ if (!v)
+ return -ENOENT;
+
+ ks = bpf_kptr_xchg(&v->ctx, NULL);
+ if (!ks)
+ return -ENOENT;
+
+ send = bpf_ksock_send(ks, send_data, sizeof(send_data));
+ bpf_ksock_release(ks);
+ return send;
+}
+
+char __license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/ksock_common.h b/tools/testing/selftests/bpf/progs/ksock_common.h
new file mode 100644
index 000000000000..87d92372d28d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/ksock_common.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2026 Isovalent */
+
+#ifndef _KSOCK_COMMON_H
+#define _KSOCK_COMMON_H
+
+#include "errno.h"
+#include <stdbool.h>
+
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define IPPROTO_TCP 6
+#define IPPROTO_UDP 17
+
+struct bpf_ksock *bpf_ksock_create(const struct bpf_ksock_create_opts *opts,
+ u32 opts__sz, int *err__uninit) __ksym;
+int bpf_ksock_bind(struct bpf_ksock *ks,
+ const struct bpf_ksock_addr_opts *opts, u32 opts__sz) __ksym;
+int bpf_ksock_connect(struct bpf_ksock *ks,
+ const struct bpf_ksock_addr_opts *opts, u32 opts__sz) __ksym;
+struct bpf_ksock *bpf_ksock_acquire(struct bpf_ksock *ks) __ksym;
+void bpf_ksock_release(struct bpf_ksock *ks) __ksym;
+int bpf_ksock_send(struct bpf_ksock *ks,
+ const void *data, u32 data__sz) __ksym;
+
+struct __ksock_ctx_value {
+ struct bpf_ksock __kptr * ctx;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __type(key, int);
+ __type(value, struct __ksock_ctx_value);
+ __uint(max_entries, 1);
+} __ksock_ctx_map SEC(".maps");
+
+static inline struct __ksock_ctx_value *ksock_ctx_value_lookup(void)
+{
+ u32 key = 0;
+
+ return bpf_map_lookup_elem(&__ksock_ctx_map, &key);
+}
+
+static inline int ksock_ctx_insert(struct bpf_ksock *ctx)
+{
+ struct __ksock_ctx_value local, *v;
+ struct bpf_ksock *old;
+ u32 key = 0;
+ int err;
+
+ local.ctx = NULL;
+ err = bpf_map_update_elem(&__ksock_ctx_map, &key, &local, 0);
+ if (err) {
+ bpf_ksock_release(ctx);
+ return err;
+ }
+
+ v = bpf_map_lookup_elem(&__ksock_ctx_map, &key);
+ if (!v) {
+ bpf_ksock_release(ctx);
+ return -ENOENT;
+ }
+
+ old = bpf_kptr_xchg(&v->ctx, ctx);
+ if (old) {
+ bpf_ksock_release(old);
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+#endif /* _KSOCK_COMMON_H */
--
2.34.1
next prev parent reply other threads:[~2026-07-06 9:35 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 9:35 [PATCH bpf-next 0/6] Introduce bpf_ksock Mahe Tardy
2026-07-06 9:35 ` [PATCH bpf-next 1/6] net: Add __sys_connect_socket() helper Mahe Tardy
2026-07-06 9:35 ` [PATCH bpf-next 2/6] bpf: Add ksock kfuncs Mahe Tardy
2026-07-06 10:01 ` sashiko-bot
2026-07-06 15:42 ` Mahe Tardy
2026-07-06 10:30 ` bot+bpf-ci
2026-07-06 15:28 ` Mahe Tardy
2026-07-06 16:58 ` Stanislav Fomichev
2026-07-06 17:26 ` Mahe Tardy
2026-07-06 20:21 ` Amery Hung
2026-07-06 21:02 ` Stanislav Fomichev
2026-07-06 22:50 ` Kuniyuki Iwashima
2026-07-07 9:41 ` Mahe Tardy
2026-07-06 21:33 ` Amery Hung
2026-07-07 9:48 ` Mahe Tardy
2026-07-06 23:01 ` Kuniyuki Iwashima
2026-07-07 10:06 ` Mahe Tardy
2026-07-06 9:35 ` Mahe Tardy [this message]
2026-07-06 10:10 ` [PATCH bpf-next 3/6] selftests/bpf: Add ksock kfunc test sashiko-bot
2026-07-06 16:11 ` Mahe Tardy
2026-07-06 10:16 ` bot+bpf-ci
2026-07-06 15:27 ` Mahe Tardy
2026-07-06 9:35 ` [PATCH bpf-next 4/6] selftests/bpf: Add ksock LSM recursion test Mahe Tardy
2026-07-06 9:35 ` [PATCH bpf-next 5/6] selftests/bpf: Add ksock net ns quota tests Mahe Tardy
2026-07-06 9:35 ` [PATCH bpf-next 6/6] selftests/bpf: Add ksock test for async callback guard Mahe Tardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260706093525.13030-4-mahe.tardy@gmail.com \
--to=mahe.tardy@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=liamwisehart@meta.com \
--cc=martin.lau@linux.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=song@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.