Re: [PATCH bpf-next v3 11/15] bpf: tcp: Support selected sock_ops callbacks as struct_ops

Amery Hung <[email protected]>
Newsgroups org.kernel.vger.bpf,org.kernel.vger.netdev
Message-ID <CAMB2axNmd8m4hp5Vti4pzxhbufr63dKzFSpN6szH6wXDLPTLDw@mail.gmail.com>
On Fri, Jul 31, 2026 at 2:11 PM Emil Tsalapatis <[email protected]> wrote:
>
> On Mon Jul 6, 2026 at 1:19 PM EDT, Amery Hung wrote:
> > In LSFMMBPF 2025, I have talked about moving the BPF_PROG_TYPE_SOCK_OPS
> > to a struct_ops interface [1].
> >
> > The BPF_SOCK_OPS_*_CB enum interface has grown over time as new TCP
> > callback points were added. A BPF_PROG_TYPE_SOCK_OPS program now
> > commonly needs a large switch on sock_ops->op, and the shared
> > bpf_sock_ops_kern context has become harder to extend because different
> > callbacks have different locking, argument, skb, and helper
> > requirements. The existing 'union { u32 args[4]; u32 replylong[4]; }' is
> > also not reliable in passing args to bpf prog when there are multiple
> > progs attached to a cgroup.
> >
> > The above has already been solved in struct_ops. Add a TCP-specific
> > struct_ops type, bpf_tcp_ops, and support attaching it to cgroups.
> > This allows each callback have its own func signature and allows
> > the verifier to select kfuncs/helpers based on the specific
> > struct_ops member being implemented.
> >
> > This patch wires up the following existing sock_ops callbacks:
> > - BPF_SOCK_OPS_TIMEOUT_INIT
> > - BPF_SOCK_OPS_RWND_INIT
> > - BPF_SOCK_OPS_RTT_CB
> > - BPF_SOCK_OPS_STATE_CB
> > - BPF_SOCK_OPS_RETRANS_CB
> > - BPF_SOCK_OPS_TCP_CONNECT_CB
> > - BPF_SOCK_OPS_TCP_LISTEN_CB
> > - BPF_SOCK_OPS_RTO_CB
> > - BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB
> > - BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB
> >
> > BASE_RTT is ignored as it is not particularly useful. NEEDS_ECN should
> > be done in bpf-tcp-cc instead. The tstamp ones should be a separate
> > struct_ops (e.g. "bpf_sock_ops") that can work in both TCP and UDP.
> >
> > timeout_init and rwnd_init could have a request_sock pointer. This patch
> > tries a different API and direclty passes the request_sock pointer as
> > an arg.
> >
> > Two other approaches were considered before settling on having
> > bpf_get_retval() read the dispatcher's run_ctx via saved_run_ctx. The
> > first was to inherit the retval in the trampoline itself: add a helper
> > in the four __bpf_prog_enter*() paths that, for struct_ops programs,
> > copies the chained value from the caller's run_ctx (now saved_run_ctx)
> > into the program's own run_ctx. It works but puts a per-enter
> > program-type check on the generic trampoline fast path, taxing all
> > fentry/fexit/lsm callers for a cgroup-struct_ops-only feature. The
> > second was to do that same inherit only for the int-returning members
> > via a gen_prologue that emits a hidden kfunc at the start of
> > timeout_init/rwnd_init; this keeps the cost off the generic path and
> > scoped to bpf_tcp_ops, but needs a kfunc + BTF_ID + prologue-emission
> > machinery. The chosen approach avoids both: it touches neither the
> > trampoline nor the program, since saved_run_ctx already points at the
> > dispatcher's run_ctx that carries the value.
> >
> > [1], page 13: https://drive.google.com/file/d/1wjKZth6T0llLJ_ONPAL_6Q_jbxbAjByp/view?usp=sharing
> >
> > Signed-off-by: Martin KaFai Lau <[email protected]>
> > Signed-off-by: Amery Hung <[email protected]>
>
> Reviewed-by: Emil Tsalapatis <[email protected]>
>
> Two nits below.
>
> > ---
> >  include/linux/bpf.h    |   1 +
> >  include/net/tcp.h      | 113 ++++++++++++++++++++++++-
> >  net/ipv4/Makefile      |   1 +
> >  net/ipv4/af_inet.c     |   1 +
> >  net/ipv4/bpf_tcp_ops.c | 188 +++++++++++++++++++++++++++++++++++++++++
> >  net/ipv4/tcp.c         |   1 +
> >  net/ipv4/tcp_input.c   |   4 +
> >  net/ipv4/tcp_output.c  |   2 +
> >  net/ipv4/tcp_timer.c   |   1 +
> >  9 files changed, 310 insertions(+), 2 deletions(-)
> >  create mode 100644 net/ipv4/bpf_tcp_ops.c
> >
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index df95ae690da5..91024d2da4ea 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
> > @@ -2597,6 +2597,7 @@ struct bpf_trace_run_ctx {
> >  struct bpf_tramp_run_ctx {
> >       struct bpf_run_ctx run_ctx;
> >       u64 bpf_cookie;
> > +     int retval;
> >       struct bpf_run_ctx *saved_run_ctx;
> >  };
> >
>
> <SNIP>
>
> The retval is in bpf_tramp_run_ctx is generic, so maybe we can make the
> helper for retrieving it generic, too. Should we at least rename it to
> make this obvious?

The helper cannot easily be made generic: the chaining is done in
bpf_tcp_ops_call_int(), which is bpf_tcp_ops specific, and the helper
reads the retval out of that dispatcher's run_ctx via saved_run_ctx. A
bpf_cgroup_struct_ops_ name would over-promise for now. I would rather
keep bpf_tcp_ops_get_retval() and rename it if and when a second user
shows up (it likely will follow the same convention).

The commit message describes two other approaches that would make it
generic: 1) inheriting the retval in __bpf_prog_enter*(), and 2) a
gen_prologue-emitted kfunc, and why neither was chosen.

>
> > +{
> > +     struct bpf_tramp_run_ctx *ctx =
> > +             container_of(current->bpf_ctx, struct bpf_tramp_run_ctx, run_ctx);
> > +
> > +     /* bpf_get_retval() is only exposed to timeout_init/rwnd_init, which
> > +      * always run via bpf_tcp_ops_call_int(). Its run_ctx carries the int
> > +      * return value chained across the bpf_tcp_ops attached to the cgroup
> > +      * and is this program's saved_run_ctx.
> > +      */
> > +     if (WARN_ON_ONCE(!ctx->saved_run_ctx))
> > +             return 0;
> > +
> > +     return container_of(ctx->saved_run_ctx, struct bpf_tramp_run_ctx,
> > +                         run_ctx)->retval;
> > +}
> > +
>
> <SNIP>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.