* [PATCH bpf-next v2 1/3] bpf: add bpf_ksock_sendto() kfunc
2026-10-20 15:58 [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc Mahe Tardy
@ 2026-10-20 15:58 ` Mahe Tardy
2026-10-21 17:56 ` Andrii Nakryiko
2026-10-20 15:58 ` [PATCH bpf-next v2 2/3] selftests/bpf: Test ksock sendto() Mahe Tardy
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Mahe Tardy @ 2026-10-20 15:58 UTC (permalink / raw)
To: bpf
Cc: andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui, Mahe Tardy
The motivation is to plumb more of the socket API into ksock, thus
supporting sendto() in addition to send() which makes a lot of sense in
the context of UDP sockets which are the only type currently supported.
This is useful when ksock is used to reply to specific addresses or send
to multiple addresses.
Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
---
net/core/bpf_ksock.c | 96 +++++++++++++++++++++++++++++++-------------
1 file changed, 69 insertions(+), 27 deletions(-)
diff --git a/net/core/bpf_ksock.c b/net/core/bpf_ksock.c
index 48a2e2327ace..37168f43c16c 100644
--- a/net/core/bpf_ksock.c
+++ b/net/core/bpf_ksock.c
@@ -37,6 +37,49 @@ static void ksock_release_work_fn(struct work_struct *work)
kfree(ks);
}
+static int bpf_ksock_addr_to_sockaddr(const union bpf_ksock_addr *addr,
+ u32 addr_sz, struct sockaddr_storage *sa)
+{
+ if (!addr || addr_sz != sizeof(*addr))
+ return -EINVAL;
+
+ /* Kfunc memory arguments may be unaligned. */
+ memcpy(sa, addr, sizeof(*addr));
+
+ switch (sa->ss_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ default:
+ return -EAFNOSUPPORT;
+ }
+}
+
+static int ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data_sz,
+ const union bpf_ksock_addr *addr, u32 addr_sz)
+{
+ struct sockaddr_storage sa;
+ struct msghdr msg = {
+ .msg_flags = MSG_DONTWAIT,
+ };
+ struct kvec iov = {
+ .iov_base = (void *)data,
+ .iov_len = data_sz,
+ };
+ int addrlen;
+
+ if (addr) {
+ addrlen = bpf_ksock_addr_to_sockaddr(addr, addr_sz, &sa);
+ if (addrlen < 0)
+ return addrlen;
+ msg.msg_name = &sa;
+ msg.msg_namelen = addrlen;
+ }
+
+ return kernel_sendmsg(ks->sock, &msg, &iov, 1, data_sz);
+}
+
__bpf_kfunc_start_defs();
/**
@@ -155,22 +198,9 @@ __bpf_kfunc int bpf_ksock_connect(struct bpf_ksock *ks,
struct sockaddr_storage sa;
int addrlen;
- if (!addr || addr__sz != sizeof(*addr))
- return -EINVAL;
-
- /* Kfunc memory arguments may be unaligned. */
- memcpy(&sa, addr, sizeof(*addr));
-
- switch (sa.ss_family) {
- case AF_INET:
- addrlen = sizeof(struct sockaddr_in);
- break;
- case AF_INET6:
- addrlen = sizeof(struct sockaddr_in6);
- break;
- default:
- return -EAFNOSUPPORT;
- }
+ addrlen = bpf_ksock_addr_to_sockaddr(addr, addr__sz, &sa);
+ if (addrlen < 0)
+ return addrlen;
return connect_socket(ks->sock, &sa, addrlen, 0);
}
@@ -225,18 +255,29 @@ CFI_NOSEAL(bpf_ksock_release_dtor);
__bpf_kfunc int bpf_ksock_send(struct bpf_ksock *ks, const void *data,
u32 data__sz)
{
- struct msghdr msg = {
- .msg_flags = MSG_DONTWAIT,
- };
- struct kvec iov = {
- .iov_base = (void *)data,
- .iov_len = data__sz,
- };
- int ret;
-
- ret = kernel_sendmsg(ks->sock, &msg, &iov, 1, data__sz);
+ return ksock_sendto(ks, data, data__sz, NULL, 0);
+}
- return ret;
+/**
+ * bpf_ksock_sendto() - Send data through a BPF kernel socket to a remote address.
+ * @ks: The BPF kernel socket context. Must be an acquired reference.
+ * @data: Pointer to the data to send.
+ * @data__sz: Size of the data to send.
+ * @addr__nullable: Pointer to an IPv4 or IPv6 socket address, or NULL to use
+ * the connected destination.
+ * @addr__sz: Size of the address union, ignored when the address is NULL.
+ *
+ * Sends data to the specified address, or to the connected destination when
+ * the address is NULL, best-effort and nonblocking. This may sleep
+ * (kernel_sendmsg), so it can only be called from sleepable BPF programs.
+ *
+ * Return: Number of bytes sent on success, negative errno on error.
+ */
+__bpf_kfunc int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
+ const union bpf_ksock_addr *addr__nullable,
+ u32 addr__sz)
+{
+ return ksock_sendto(ks, data, data__sz, addr__nullable, addr__sz);
}
__bpf_kfunc_end_defs();
@@ -255,6 +296,7 @@ BTF_KFUNCS_START(ksock_kfunc_btf_ids)
BTF_ID_FLAGS(func, bpf_ksock_release, KF_RELEASE)
BTF_ID_FLAGS(func, bpf_ksock_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_ksock_send, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_ksock_sendto, KF_SLEEPABLE)
BTF_KFUNCS_END(ksock_kfunc_btf_ids)
#ifdef CONFIG_BPF_LSM
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH bpf-next v2 1/3] bpf: add bpf_ksock_sendto() kfunc
2026-10-20 15:58 ` [PATCH bpf-next v2 1/3] bpf: add " Mahe Tardy
@ 2026-10-21 17:56 ` Andrii Nakryiko
2026-10-21 18:39 ` Mahe Tardy
0 siblings, 1 reply; 9+ messages in thread
From: Andrii Nakryiko @ 2026-10-21 17:56 UTC (permalink / raw)
To: Mahe Tardy
Cc: bpf, andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui
On Tue, Oct 20, 2026 at 8:59 AM Mahe Tardy <mahe.tardy@gmail.com> wrote:
>
> The motivation is to plumb more of the socket API into ksock, thus
> supporting sendto() in addition to send() which makes a lot of sense in
> the context of UDP sockets which are the only type currently supported.
> This is useful when ksock is used to reply to specific addresses or send
> to multiple addresses.
>
> Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
> ---
> net/core/bpf_ksock.c | 96 +++++++++++++++++++++++++++++++-------------
> 1 file changed, 69 insertions(+), 27 deletions(-)
>
> diff --git a/net/core/bpf_ksock.c b/net/core/bpf_ksock.c
> index 48a2e2327ace..37168f43c16c 100644
> --- a/net/core/bpf_ksock.c
> +++ b/net/core/bpf_ksock.c
> @@ -37,6 +37,49 @@ static void ksock_release_work_fn(struct work_struct *work)
> kfree(ks);
> }
>
> +static int bpf_ksock_addr_to_sockaddr(const union bpf_ksock_addr *addr,
> + u32 addr_sz, struct sockaddr_storage *sa)
> +{
> + if (!addr || addr_sz != sizeof(*addr))
> + return -EINVAL;
> +
> + /* Kfunc memory arguments may be unaligned. */
> + memcpy(sa, addr, sizeof(*addr));
> +
> + switch (sa->ss_family) {
> + case AF_INET:
> + return sizeof(struct sockaddr_in);
> + case AF_INET6:
> + return sizeof(struct sockaddr_in6);
> + default:
> + return -EAFNOSUPPORT;
> + }
> +}
> +
> +static int ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data_sz,
> + const union bpf_ksock_addr *addr, u32 addr_sz)
> +{
> + struct sockaddr_storage sa;
> + struct msghdr msg = {
> + .msg_flags = MSG_DONTWAIT,
> + };
> + struct kvec iov = {
> + .iov_base = (void *)data,
> + .iov_len = data_sz,
> + };
> + int addrlen;
> +
> + if (addr) {
> + addrlen = bpf_ksock_addr_to_sockaddr(addr, addr_sz, &sa);
> + if (addrlen < 0)
> + return addrlen;
> + msg.msg_name = &sa;
> + msg.msg_namelen = addrlen;
> + }
> +
> + return kernel_sendmsg(ks->sock, &msg, &iov, 1, data_sz);
> +}
> +
> __bpf_kfunc_start_defs();
>
> /**
> @@ -155,22 +198,9 @@ __bpf_kfunc int bpf_ksock_connect(struct bpf_ksock *ks,
> struct sockaddr_storage sa;
> int addrlen;
>
> - if (!addr || addr__sz != sizeof(*addr))
> - return -EINVAL;
> -
> - /* Kfunc memory arguments may be unaligned. */
> - memcpy(&sa, addr, sizeof(*addr));
> -
> - switch (sa.ss_family) {
> - case AF_INET:
> - addrlen = sizeof(struct sockaddr_in);
> - break;
> - case AF_INET6:
> - addrlen = sizeof(struct sockaddr_in6);
> - break;
> - default:
> - return -EAFNOSUPPORT;
> - }
> + addrlen = bpf_ksock_addr_to_sockaddr(addr, addr__sz, &sa);
> + if (addrlen < 0)
> + return addrlen;
>
> return connect_socket(ks->sock, &sa, addrlen, 0);
> }
> @@ -225,18 +255,29 @@ CFI_NOSEAL(bpf_ksock_release_dtor);
> __bpf_kfunc int bpf_ksock_send(struct bpf_ksock *ks, const void *data,
> u32 data__sz)
> {
> - struct msghdr msg = {
> - .msg_flags = MSG_DONTWAIT,
> - };
> - struct kvec iov = {
> - .iov_base = (void *)data,
> - .iov_len = data__sz,
> - };
> - int ret;
> -
> - ret = kernel_sendmsg(ks->sock, &msg, &iov, 1, data__sz);
> + return ksock_sendto(ks, data, data__sz, NULL, 0);
> +}
>
> - return ret;
> +/**
> + * bpf_ksock_sendto() - Send data through a BPF kernel socket to a remote address.
> + * @ks: The BPF kernel socket context. Must be an acquired reference.
> + * @data: Pointer to the data to send.
> + * @data__sz: Size of the data to send.
> + * @addr__nullable: Pointer to an IPv4 or IPv6 socket address, or NULL to use
> + * the connected destination.
> + * @addr__sz: Size of the address union, ignored when the address is NULL.
> + *
> + * Sends data to the specified address, or to the connected destination when
> + * the address is NULL, best-effort and nonblocking. This may sleep
> + * (kernel_sendmsg), so it can only be called from sleepable BPF programs.
> + *
> + * Return: Number of bytes sent on success, negative errno on error.
> + */
> +__bpf_kfunc int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
This would limit API to fixed-sized data only. Have you considered
passing dynptr as a source of data, so you can send a wider variety of
data? I don't have a strong opinion whether we should add a separate
API or convert this one into dynptr, but I do think that having
ability to work with variable-sized data is super useful and should be
added early on.
> + const union bpf_ksock_addr *addr__nullable,
> + u32 addr__sz)
> +{
> + return ksock_sendto(ks, data, data__sz, addr__nullable, addr__sz);
> }
>
> __bpf_kfunc_end_defs();
> @@ -255,6 +296,7 @@ BTF_KFUNCS_START(ksock_kfunc_btf_ids)
> BTF_ID_FLAGS(func, bpf_ksock_release, KF_RELEASE)
> BTF_ID_FLAGS(func, bpf_ksock_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
> BTF_ID_FLAGS(func, bpf_ksock_send, KF_SLEEPABLE)
> +BTF_ID_FLAGS(func, bpf_ksock_sendto, KF_SLEEPABLE)
> BTF_KFUNCS_END(ksock_kfunc_btf_ids)
>
> #ifdef CONFIG_BPF_LSM
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH bpf-next v2 1/3] bpf: add bpf_ksock_sendto() kfunc
2026-10-21 17:56 ` Andrii Nakryiko
@ 2026-10-21 18:39 ` Mahe Tardy
2026-10-21 18:57 ` Andrii Nakryiko
0 siblings, 1 reply; 9+ messages in thread
From: Mahe Tardy @ 2026-10-21 18:39 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: bpf, andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui
On Wed, Oct 21, 2026 at 10:56:23AM -0700, Andrii Nakryiko wrote:
> On Tue, Oct 20, 2026 at 8:59 AM Mahe Tardy <mahe.tardy@gmail.com> wrote:
> >
> > The motivation is to plumb more of the socket API into ksock, thus
> > supporting sendto() in addition to send() which makes a lot of sense in
> > the context of UDP sockets which are the only type currently supported.
> > This is useful when ksock is used to reply to specific addresses or send
> > to multiple addresses.
> >
> > Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
> > ---
> > net/core/bpf_ksock.c | 96 +++++++++++++++++++++++++++++++-------------
> > 1 file changed, 69 insertions(+), 27 deletions(-)
> >
[...]
> >
> > - return ret;
> > +/**
> > + * bpf_ksock_sendto() - Send data through a BPF kernel socket to a remote address.
> > + * @ks: The BPF kernel socket context. Must be an acquired reference.
> > + * @data: Pointer to the data to send.
> > + * @data__sz: Size of the data to send.
> > + * @addr__nullable: Pointer to an IPv4 or IPv6 socket address, or NULL to use
> > + * the connected destination.
> > + * @addr__sz: Size of the address union, ignored when the address is NULL.
> > + *
> > + * Sends data to the specified address, or to the connected destination when
> > + * the address is NULL, best-effort and nonblocking. This may sleep
> > + * (kernel_sendmsg), so it can only be called from sleepable BPF programs.
> > + *
> > + * Return: Number of bytes sent on success, negative errno on error.
> > + */
> > +__bpf_kfunc int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
>
> This would limit API to fixed-sized data only. Have you considered
> passing dynptr as a source of data, so you can send a wider variety of
> data? I don't have a strong opinion whether we should add a separate
> API or convert this one into dynptr, but I do think that having
> ability to work with variable-sized data is super useful and should be
> added early on.
Oh wow this is really cool that you send this now. I was working this
afternoon on trying to see if a ksock sendmsg() would make sense, but
with these static buffer limitations as arguments, it actually didn't.
I'm not familiar with dynptr so I didn't think about it, but after a
quick check it looks like it would be a good match with the ksock API!
As I understand, since bpf_ksock_send() is already part of 7.3, it's
best to not touch it, and having a simple send() available with a
fixed-size data might make sense.
But since bpf_ksock_sendto() was just merged, we could make it evolve to
use dynptr perhaps? How much time do we have for something which was
merged yesterday to be part of a release? Is it going to be send with
the 7.4 pull soon?
>
> > + const union bpf_ksock_addr *addr__nullable,
> > + u32 addr__sz)
> > +{
> > + return ksock_sendto(ks, data, data__sz, addr__nullable, addr__sz);
> > }
> >
> > __bpf_kfunc_end_defs();
> > @@ -255,6 +296,7 @@ BTF_KFUNCS_START(ksock_kfunc_btf_ids)
> > BTF_ID_FLAGS(func, bpf_ksock_release, KF_RELEASE)
> > BTF_ID_FLAGS(func, bpf_ksock_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
> > BTF_ID_FLAGS(func, bpf_ksock_send, KF_SLEEPABLE)
> > +BTF_ID_FLAGS(func, bpf_ksock_sendto, KF_SLEEPABLE)
> > BTF_KFUNCS_END(ksock_kfunc_btf_ids)
> >
> > #ifdef CONFIG_BPF_LSM
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH bpf-next v2 1/3] bpf: add bpf_ksock_sendto() kfunc
2026-10-21 18:39 ` Mahe Tardy
@ 2026-10-21 18:57 ` Andrii Nakryiko
2026-10-21 19:50 ` Kumar Kartikeya Dwivedi
0 siblings, 1 reply; 9+ messages in thread
From: Andrii Nakryiko @ 2026-10-21 18:57 UTC (permalink / raw)
To: Mahe Tardy
Cc: bpf, andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui
On Wed, Oct 21, 2026 at 11:39 AM Mahe Tardy <mahe.tardy@gmail.com> wrote:
>
> On Wed, Oct 21, 2026 at 10:56:23AM -0700, Andrii Nakryiko wrote:
> > On Tue, Oct 20, 2026 at 8:59 AM Mahe Tardy <mahe.tardy@gmail.com> wrote:
> > >
> > > The motivation is to plumb more of the socket API into ksock, thus
> > > supporting sendto() in addition to send() which makes a lot of sense in
> > > the context of UDP sockets which are the only type currently supported.
> > > This is useful when ksock is used to reply to specific addresses or send
> > > to multiple addresses.
> > >
> > > Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
> > > ---
> > > net/core/bpf_ksock.c | 96 +++++++++++++++++++++++++++++++-------------
> > > 1 file changed, 69 insertions(+), 27 deletions(-)
> > >
>
> [...]
>
> > >
> > > - return ret;
> > > +/**
> > > + * bpf_ksock_sendto() - Send data through a BPF kernel socket to a remote address.
> > > + * @ks: The BPF kernel socket context. Must be an acquired reference.
> > > + * @data: Pointer to the data to send.
> > > + * @data__sz: Size of the data to send.
> > > + * @addr__nullable: Pointer to an IPv4 or IPv6 socket address, or NULL to use
> > > + * the connected destination.
> > > + * @addr__sz: Size of the address union, ignored when the address is NULL.
> > > + *
> > > + * Sends data to the specified address, or to the connected destination when
> > > + * the address is NULL, best-effort and nonblocking. This may sleep
> > > + * (kernel_sendmsg), so it can only be called from sleepable BPF programs.
> > > + *
> > > + * Return: Number of bytes sent on success, negative errno on error.
> > > + */
> > > +__bpf_kfunc int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
> >
> > This would limit API to fixed-sized data only. Have you considered
> > passing dynptr as a source of data, so you can send a wider variety of
> > data? I don't have a strong opinion whether we should add a separate
> > API or convert this one into dynptr, but I do think that having
> > ability to work with variable-sized data is super useful and should be
> > added early on.
>
> Oh wow this is really cool that you send this now. I was working this
> afternoon on trying to see if a ksock sendmsg() would make sense, but
> with these static buffer limitations as arguments, it actually didn't.
> I'm not familiar with dynptr so I didn't think about it, but after a
> quick check it looks like it would be a good match with the ksock API!
>
> As I understand, since bpf_ksock_send() is already part of 7.3, it's
> best to not touch it, and having a simple send() available with a
> fixed-size data might make sense.
agreed
>
> But since bpf_ksock_sendto() was just merged, we could make it evolve to
> use dynptr perhaps? How much time do we have for something which was
> merged yesterday to be part of a release? Is it going to be send with
> the 7.4 pull soon?
>
I'd send a follow up in the next few days, it can go in as a fix for
kfunc in rc1 or something, unless others have differing opinions on
this
> >
> > > + const union bpf_ksock_addr *addr__nullable,
> > > + u32 addr__sz)
> > > +{
> > > + return ksock_sendto(ks, data, data__sz, addr__nullable, addr__sz);
> > > }
> > >
> > > __bpf_kfunc_end_defs();
> > > @@ -255,6 +296,7 @@ BTF_KFUNCS_START(ksock_kfunc_btf_ids)
> > > BTF_ID_FLAGS(func, bpf_ksock_release, KF_RELEASE)
> > > BTF_ID_FLAGS(func, bpf_ksock_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
> > > BTF_ID_FLAGS(func, bpf_ksock_send, KF_SLEEPABLE)
> > > +BTF_ID_FLAGS(func, bpf_ksock_sendto, KF_SLEEPABLE)
> > > BTF_KFUNCS_END(ksock_kfunc_btf_ids)
> > >
> > > #ifdef CONFIG_BPF_LSM
> > > --
> > > 2.43.0
> > >
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH bpf-next v2 1/3] bpf: add bpf_ksock_sendto() kfunc
2026-10-21 18:57 ` Andrii Nakryiko
@ 2026-10-21 19:50 ` Kumar Kartikeya Dwivedi
0 siblings, 0 replies; 9+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-10-21 19:50 UTC (permalink / raw)
To: Andrii Nakryiko, Mahe Tardy
Cc: bpf, andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, emil,
almagui
On Wed Oct 21, 2026 at 8:57 PM CEST, Andrii Nakryiko wrote:
> On Wed, Oct 21, 2026 at 11:39 AM Mahe Tardy <mahe.tardy@gmail.com> wrote:
>>
>> On Wed, Oct 21, 2026 at 10:56:23AM -0700, Andrii Nakryiko wrote:
>> > On Tue, Oct 20, 2026 at 8:59 AM Mahe Tardy <mahe.tardy@gmail.com> wrote:
>> > >
>> > > The motivation is to plumb more of the socket API into ksock, thus
>> > > supporting sendto() in addition to send() which makes a lot of sense in
>> > > the context of UDP sockets which are the only type currently supported.
>> > > This is useful when ksock is used to reply to specific addresses or send
>> > > to multiple addresses.
>> > >
>> > > Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
>> > > ---
>> > > net/core/bpf_ksock.c | 96 +++++++++++++++++++++++++++++++-------------
>> > > 1 file changed, 69 insertions(+), 27 deletions(-)
>> > >
>>
>> [...]
>>
>> > >
>> > > - return ret;
>> > > +/**
>> > > + * bpf_ksock_sendto() - Send data through a BPF kernel socket to a remote address.
>> > > + * @ks: The BPF kernel socket context. Must be an acquired reference.
>> > > + * @data: Pointer to the data to send.
>> > > + * @data__sz: Size of the data to send.
>> > > + * @addr__nullable: Pointer to an IPv4 or IPv6 socket address, or NULL to use
>> > > + * the connected destination.
>> > > + * @addr__sz: Size of the address union, ignored when the address is NULL.
>> > > + *
>> > > + * Sends data to the specified address, or to the connected destination when
>> > > + * the address is NULL, best-effort and nonblocking. This may sleep
>> > > + * (kernel_sendmsg), so it can only be called from sleepable BPF programs.
>> > > + *
>> > > + * Return: Number of bytes sent on success, negative errno on error.
>> > > + */
>> > > +__bpf_kfunc int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
>> >
>> > This would limit API to fixed-sized data only. Have you considered
>> > passing dynptr as a source of data, so you can send a wider variety of
>> > data? I don't have a strong opinion whether we should add a separate
>> > API or convert this one into dynptr, but I do think that having
>> > ability to work with variable-sized data is super useful and should be
>> > added early on.
>>
>> Oh wow this is really cool that you send this now. I was working this
>> afternoon on trying to see if a ksock sendmsg() would make sense, but
>> with these static buffer limitations as arguments, it actually didn't.
>> I'm not familiar with dynptr so I didn't think about it, but after a
>> quick check it looks like it would be a good match with the ksock API!
>>
>> As I understand, since bpf_ksock_send() is already part of 7.3, it's
>> best to not touch it, and having a simple send() available with a
>> fixed-size data might make sense.
>
> agreed
>
>>
>> But since bpf_ksock_sendto() was just merged, we could make it evolve to
>> use dynptr perhaps? How much time do we have for something which was
>> merged yesterday to be part of a release? Is it going to be send with
>> the 7.4 pull soon?
>>
>
> I'd send a follow up in the next few days, it can go in as a fix for
> kfunc in rc1 or something, unless others have differing opinions on
> this
>
Another option is to add dynptr variants of both, a pattern we have in other
APIs as well, so there would be no rush. We just have two more kfuncs:
bpf_ksock_send_dynptr() and bpf_ksock_sendto_dynptr().
>> >
>> > > + const union bpf_ksock_addr *addr__nullable,
>> > > + u32 addr__sz)
>> > > +{
>> > > + return ksock_sendto(ks, data, data__sz, addr__nullable, addr__sz);
>> > > }
>> > >
>> > > __bpf_kfunc_end_defs();
>> > > @@ -255,6 +296,7 @@ BTF_KFUNCS_START(ksock_kfunc_btf_ids)
>> > > BTF_ID_FLAGS(func, bpf_ksock_release, KF_RELEASE)
>> > > BTF_ID_FLAGS(func, bpf_ksock_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
>> > > BTF_ID_FLAGS(func, bpf_ksock_send, KF_SLEEPABLE)
>> > > +BTF_ID_FLAGS(func, bpf_ksock_sendto, KF_SLEEPABLE)
>> > > BTF_KFUNCS_END(ksock_kfunc_btf_ids)
>> > >
>> > > #ifdef CONFIG_BPF_LSM
>> > > --
>> > > 2.43.0
>> > >
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH bpf-next v2 2/3] selftests/bpf: Test ksock sendto()
2026-10-20 15:58 [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc Mahe Tardy
2026-10-20 15:58 ` [PATCH bpf-next v2 1/3] bpf: add " Mahe Tardy
@ 2026-10-20 15:58 ` Mahe Tardy
2026-10-20 15:58 ` [PATCH bpf-next v2 3/3] selftests/bpf: Test forbidden bpf_ksock_sendto() LSM attach Mahe Tardy
2026-10-20 21:00 ` [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc patchwork-bot+netdevbpf
3 siblings, 0 replies; 9+ messages in thread
From: Mahe Tardy @ 2026-10-20 15:58 UTC (permalink / raw)
To: bpf
Cc: andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui, Mahe Tardy
These tests are covering that:
1. sendto() on a unconnected UDP socket works (and that the socket stays
unconnected, i.e. send() on it fails with -EDESTADDRREQ).
2. sendto() on a connected UDP socket with a NULL address is equivalent
to send().
3. sendto() on a connected socket with an explicit address doesn't
change the peer of the socket (send() after sendto() still sends to
the original connected address).
Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
---
.../selftests/bpf/prog_tests/ksock_sendto.c | 108 ++++++++++++++++++
.../selftests/bpf/progs/ksock_common.h | 2 +
.../selftests/bpf/progs/ksock_sendto.c | 59 ++++++++++
3 files changed, 169 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/ksock_sendto.c
create mode 100644 tools/testing/selftests/bpf/progs/ksock_sendto.c
diff --git a/tools/testing/selftests/bpf/prog_tests/ksock_sendto.c b/tools/testing/selftests/bpf/prog_tests/ksock_sendto.c
new file mode 100644
index 000000000000..498f0e1be6ee
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/ksock_sendto.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Isovalent */
+
+#include "test_progs.h"
+#include "network_helpers.h"
+#include "ksock_sendto.skel.h"
+
+struct sendto_test_case {
+ const char *name;
+ bool connected;
+ bool use_sendto_addr;
+};
+
+static bool recv_payload(int fd, const void *expected, size_t len)
+{
+ char buf[64];
+ ssize_t n;
+
+ n = recv(fd, buf, sizeof(buf), MSG_TRUNC);
+ if (!ASSERT_EQ(n, len, "recv length"))
+ return false;
+ return ASSERT_MEMEQ(buf, expected, len, "recv payload");
+}
+
+static void test_sendto_case(const struct sendto_test_case *test)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, opts);
+ struct ksock_sendto *skel;
+ int receivers[2] = { -1, -1 };
+ int err, i, port, sendto_fd;
+ char buf[64];
+ ssize_t n;
+
+ skel = ksock_sendto__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "ksock_sendto open and load"))
+ return;
+
+ /* Use separate receivers for the default peer and explicit destination. */
+ for (i = 0; i < ARRAY_SIZE(receivers); i++) {
+ receivers[i] = start_server(AF_INET, SOCK_DGRAM, "127.0.0.1", 0, 1000);
+ if (!ASSERT_OK_FD(receivers[i], "receiver socket"))
+ goto out;
+ }
+
+ port = get_socket_local_port(receivers[0]);
+ if (!ASSERT_GE(port, 0, "connected port"))
+ goto out;
+ skel->bss->connected_port = port;
+ port = get_socket_local_port(receivers[1]);
+ if (!ASSERT_GE(port, 0, "sendto port"))
+ goto out;
+ skel->bss->sendto_port = port;
+ skel->bss->connected = test->connected;
+ skel->bss->use_sendto_addr = test->use_sendto_addr;
+
+ err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_sendto), &opts);
+ if (!ASSERT_OK(err, "run test_sendto") || !ASSERT_OK(opts.retval, "test_sendto retval"))
+ goto out;
+
+ /* Check sendto() outcome */
+ if (!ASSERT_EQ(skel->data->sendto_ret, sizeof(skel->data->sendto_data), "sendto bytes"))
+ goto out;
+ sendto_fd = receivers[test->use_sendto_addr ? 1 : 0];
+ if (!recv_payload(sendto_fd, skel->data->sendto_data, sizeof(skel->data->sendto_data)))
+ goto out;
+
+ /* Check send() outcome */
+ if (test->connected) {
+ if (!ASSERT_EQ(skel->data->send_ret, sizeof(skel->data->send_data), "send bytes"))
+ goto out;
+ if (!recv_payload(receivers[0], skel->data->send_data,
+ sizeof(skel->data->send_data)))
+ goto out;
+ } else if (!ASSERT_EQ(skel->data->send_ret, -EDESTADDRREQ,
+ "send after sendto remains unconnected")) {
+ goto out;
+ }
+
+ /* Catch unexpected deliveries to either destination. */
+ for (i = 0; i < ARRAY_SIZE(receivers); i++) {
+ n = recv(receivers[i], buf, sizeof(buf), MSG_DONTWAIT);
+ if (!ASSERT_EQ(n, -1, "no extra datagram") ||
+ !ASSERT_EQ(errno, EAGAIN, "recv errno"))
+ goto out;
+ }
+
+out:
+ for (i = 0; i < ARRAY_SIZE(receivers); i++) {
+ if (receivers[i] >= 0)
+ close(receivers[i]);
+ }
+ ksock_sendto__destroy(skel);
+}
+
+void test_ksock_sendto(void)
+{
+ static const struct sendto_test_case tests[] = {
+ { .name = "unconnected", .use_sendto_addr = true },
+ { .name = "connected_null_addr", .connected = true },
+ { .name = "connected_explicit_addr", .connected = true, .use_sendto_addr = true },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (test__start_subtest(tests[i].name))
+ test_sendto_case(&tests[i]);
+ }
+}
diff --git a/tools/testing/selftests/bpf/progs/ksock_common.h b/tools/testing/selftests/bpf/progs/ksock_common.h
index 01edaeb9fdd4..2a32cff2fbe9 100644
--- a/tools/testing/selftests/bpf/progs/ksock_common.h
+++ b/tools/testing/selftests/bpf/progs/ksock_common.h
@@ -16,6 +16,8 @@ int bpf_ksock_connect(struct bpf_ksock *ks, const union bpf_ksock_addr *addr,
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;
+int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
+ const union bpf_ksock_addr *addr__nullable, u32 addr__sz) __ksym;
void bpf_rcu_read_lock(void) __ksym;
void bpf_rcu_read_unlock(void) __ksym;
diff --git a/tools/testing/selftests/bpf/progs/ksock_sendto.c b/tools/testing/selftests/bpf/progs/ksock_sendto.c
new file mode 100644
index 000000000000..b6eacf277fcb
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/ksock_sendto.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Isovalent */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+#include "bpf_tracing_net.h"
+#include "ksock_common.h"
+
+char sendto_data[] = "hello from bpf sendto";
+char send_data[] = "hello from bpf send";
+
+__be16 connected_port;
+__be16 sendto_port;
+bool connected;
+bool use_sendto_addr;
+int sendto_ret = -1;
+int send_ret = -1;
+
+SEC("syscall")
+int test_sendto(void *ctx)
+{
+ struct bpf_ksock_create_opts opts = {
+ .family = AF_INET,
+ .type = SOCK_DGRAM,
+ .protocol = IPPROTO_UDP,
+ };
+ union bpf_ksock_addr addr = {};
+ struct bpf_ksock *ks;
+ int err = 0;
+
+ ks = bpf_ksock_create(&opts, sizeof(opts), &err);
+ if (!ks)
+ return err;
+
+ addr.sin.sin_family = AF_INET;
+ addr.sin.sin_addr.s_addr = bpf_htonl(0x7f000001);
+ if (connected) {
+ addr.sin.sin_port = connected_port;
+ err = bpf_ksock_connect(ks, &addr, sizeof(addr));
+ if (err)
+ goto out;
+ }
+
+ addr.sin.sin_port = sendto_port;
+ if (use_sendto_addr)
+ sendto_ret = bpf_ksock_sendto(ks, sendto_data, sizeof(sendto_data),
+ &addr, sizeof(addr));
+ else
+ sendto_ret = bpf_ksock_sendto(ks, sendto_data, sizeof(sendto_data), NULL, 0);
+
+ /* sendto() must neither connect the socket nor change its default peer. */
+ send_ret = bpf_ksock_send(ks, send_data, sizeof(send_data));
+out:
+ bpf_ksock_release(ks);
+ return err;
+}
+
+char __license[] SEC("license") = "GPL";
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH bpf-next v2 3/3] selftests/bpf: Test forbidden bpf_ksock_sendto() LSM attach
2026-10-20 15:58 [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc Mahe Tardy
2026-10-20 15:58 ` [PATCH bpf-next v2 1/3] bpf: add " Mahe Tardy
2026-10-20 15:58 ` [PATCH bpf-next v2 2/3] selftests/bpf: Test ksock sendto() Mahe Tardy
@ 2026-10-20 15:58 ` Mahe Tardy
2026-10-20 21:00 ` [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc patchwork-bot+netdevbpf
3 siblings, 0 replies; 9+ messages in thread
From: Mahe Tardy @ 2026-10-20 15:58 UTC (permalink / raw)
To: bpf
Cc: andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui, Mahe Tardy
Similarly to '7b0dfbf5776b ("selftests/bpf: Test forbidden
bpf_ksock_send() LSM attach")', tests that the verifier filter prevents
bpf_ksock_sendto() to be called in a LSM program attached to
security_socket_sendmsg() as it would create a direct recursion.
Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
---
.../selftests/bpf/progs/ksock_lsm_verifier.c | 25 ++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/progs/ksock_lsm_verifier.c b/tools/testing/selftests/bpf/progs/ksock_lsm_verifier.c
index fd2ccfdb5802..9533570eb340 100644
--- a/tools/testing/selftests/bpf/progs/ksock_lsm_verifier.c
+++ b/tools/testing/selftests/bpf/progs/ksock_lsm_verifier.c
@@ -12,7 +12,7 @@ char send_data[11] = "dummy data";
SEC("lsm.s/socket_sendmsg")
__description("bpf_ksock_send is rejected from socket_sendmsg LSM hook")
__failure __msg("calling kernel function bpf_ksock_send is not allowed")
-int BPF_PROG(ksock_socket_sendmsg, struct socket *sock, struct msghdr *msg,
+int BPF_PROG(socket_sendmsg_ksock_send, struct socket *sock, struct msghdr *msg,
int size, int ret)
{
struct __ksock_ctx_value *v;
@@ -32,4 +32,27 @@ int BPF_PROG(ksock_socket_sendmsg, struct socket *sock, struct msghdr *msg,
return ret;
}
+SEC("lsm.s/socket_sendmsg")
+__description("bpf_ksock_sendto is rejected from socket_sendmsg LSM hook")
+__failure __msg("calling kernel function bpf_ksock_sendto is not allowed")
+int BPF_PROG(socket_sendmsg_ksock_sendto, struct socket *sock,
+ struct msghdr *msg, int size, int ret)
+{
+ struct __ksock_ctx_value *v;
+ struct bpf_ksock *ks;
+
+ v = ksock_ctx_value_lookup();
+ if (!v)
+ return ret;
+
+ ks = bpf_kptr_xchg(&v->ctx, NULL);
+ if (!ks)
+ return ret;
+
+ bpf_ksock_sendto(ks, send_data, sizeof(send_data), NULL, 0);
+ bpf_ksock_release(ks);
+
+ return ret;
+}
+
char __license[] SEC("license") = "GPL";
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc
2026-10-20 15:58 [PATCH bpf-next v2 0/3] bpf: Add bpf_ksock_sendto() kfunc Mahe Tardy
` (2 preceding siblings ...)
2026-10-20 15:58 ` [PATCH bpf-next v2 3/3] selftests/bpf: Test forbidden bpf_ksock_sendto() LSM attach Mahe Tardy
@ 2026-10-20 21:00 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 9+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-10-20 21:00 UTC (permalink / raw)
To: Mahe Tardy
Cc: bpf, andrii, ast, daniel, davem, willemb, eddyz87, edumazet,
john.fastabend, kuba, horms, liamwisehart, martin.lau, pabeni,
song, netdev, sdf.kernel, yonghong.song, jolsa, kuniyu, memxor,
emil, almagui
Hello:
This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Tue, 20 Oct 2026 15:58:45 +0000 you wrote:
> This patch series improves the bpf_ksock infrastructure in line with the
> work proposed during Prague Plumbers 2026 presentation[^1] by adding
> the bpf_ksock_sendto() kfunc to complement the bpf_ksock_send().
>
> This is useful when using ksock to reply to differents peers while
> reusing the same UDP socket and generally works toward the goal of ksock
> to support the basic socket operations.
>
> [...]
Here is the summary with links:
- [bpf-next,v2,1/3] bpf: add bpf_ksock_sendto() kfunc
https://git.kernel.org/bpf/bpf-next/c/74be619845bd
- [bpf-next,v2,2/3] selftests/bpf: Test ksock sendto()
https://git.kernel.org/bpf/bpf-next/c/7d563ae3ed74
- [bpf-next,v2,3/3] selftests/bpf: Test forbidden bpf_ksock_sendto() LSM attach
https://git.kernel.org/bpf/bpf-next/c/d90912846f26
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 9+ messages in thread