bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* XDP bpf_tail_call_redirect(): yea or nay?
@ 2020-05-07 12:20 Björn Töpel
  2020-05-07 13:44 ` Toke Høiland-Jørgensen
  0 siblings, 1 reply; 10+ messages in thread
From: Björn Töpel @ 2020-05-07 12:20 UTC (permalink / raw)
  To: bpf; +Cc: Netdev

Before I start hacking on this, I might as well check with the XDP
folks if this considered a crappy idea or not. :-)

The XDP redirect flow for a packet is typical a dance of
bpf_redirect_map() that updates the bpf_redirect_info structure with
maps type/items, which is then followed by an xdp_do_redirect(). That
function takes an action based on the bpf_redirect_info content.

I'd like to get rid of the xdp_do_redirect() call, and the
bpf_redirect_info (per-cpu) lookup. The idea is to introduce a new
(oh-no!) XDP action, say, XDP_CONSUMED and a built-in helper with
tail-call semantics.

Something across the lines of:

--8<--

struct {
        __uint(type, BPF_MAP_TYPE_XSKMAP);
        __uint(max_entries, MAX_SOCKS);
        __uint(key_size, sizeof(int));
        __uint(value_size, sizeof(int));
} xsks_map SEC(".maps");

SEC("xdp1")
int xdp_prog1(struct xdp_md *ctx)
{
        bpf_tail_call_redirect(ctx, &xsks_map, 0);
        // Redirect the packet to an AF_XDP socket at entry 0 of the
        // map.
        //
        // After a successful call, ctx is said to be
        // consumed. XDP_CONSUMED will be returned by the program.
        // Note that if the call is not successful, the buffer is
        // still valid.
        //
        // XDP_CONSUMED in the driver means that the driver should not
        // issue an xdp_do_direct() call, but only xdp_flush().
        //
        // The verifier need to be taught that XDP_CONSUMED can only
        // be returned "indirectly", meaning a bpf_tail_call_XXX()
        // call. An explicit "return XDP_CONSUMED" should be
        // rejected. Can that be implemented?
        return XDP_PASS; // or any other valid action.
}

-->8--

The bpf_tail_call_redirect() would work with all redirectable maps.

Thoughts? Tomatoes? Pitchforks?


Björn

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 12:20 XDP bpf_tail_call_redirect(): yea or nay? Björn Töpel
@ 2020-05-07 13:44 ` Toke Høiland-Jørgensen
  2020-05-07 14:00   ` Björn Töpel
  0 siblings, 1 reply; 10+ messages in thread
From: Toke Høiland-Jørgensen @ 2020-05-07 13:44 UTC (permalink / raw)
  To: Björn Töpel, bpf; +Cc: Netdev

Björn Töpel <bjorn.topel@gmail.com> writes:

> Before I start hacking on this, I might as well check with the XDP
> folks if this considered a crappy idea or not. :-)
>
> The XDP redirect flow for a packet is typical a dance of
> bpf_redirect_map() that updates the bpf_redirect_info structure with
> maps type/items, which is then followed by an xdp_do_redirect(). That
> function takes an action based on the bpf_redirect_info content.
>
> I'd like to get rid of the xdp_do_redirect() call, and the
> bpf_redirect_info (per-cpu) lookup. The idea is to introduce a new
> (oh-no!) XDP action, say, XDP_CONSUMED and a built-in helper with
> tail-call semantics.
>
> Something across the lines of:
>
> --8<--
>
> struct {
>         __uint(type, BPF_MAP_TYPE_XSKMAP);
>         __uint(max_entries, MAX_SOCKS);
>         __uint(key_size, sizeof(int));
>         __uint(value_size, sizeof(int));
> } xsks_map SEC(".maps");
>
> SEC("xdp1")
> int xdp_prog1(struct xdp_md *ctx)
> {
>         bpf_tail_call_redirect(ctx, &xsks_map, 0);
>         // Redirect the packet to an AF_XDP socket at entry 0 of the
>         // map.
>         //
>         // After a successful call, ctx is said to be
>         // consumed. XDP_CONSUMED will be returned by the program.
>         // Note that if the call is not successful, the buffer is
>         // still valid.
>         //
>         // XDP_CONSUMED in the driver means that the driver should not
>         // issue an xdp_do_direct() call, but only xdp_flush().
>         //
>         // The verifier need to be taught that XDP_CONSUMED can only
>         // be returned "indirectly", meaning a bpf_tail_call_XXX()
>         // call. An explicit "return XDP_CONSUMED" should be
>         // rejected. Can that be implemented?
>         return XDP_PASS; // or any other valid action.
> }
>
> -->8--
>
> The bpf_tail_call_redirect() would work with all redirectable maps.
>
> Thoughts? Tomatoes? Pitchforks?

The above answers the 'what'. Might be easier to evaluate if you also
included the 'why'? :)

-Toke


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 13:44 ` Toke Høiland-Jørgensen
@ 2020-05-07 14:00   ` Björn Töpel
  2020-05-07 14:48     ` Toke Høiland-Jørgensen
  0 siblings, 1 reply; 10+ messages in thread
From: Björn Töpel @ 2020-05-07 14:00 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen; +Cc: bpf, Netdev

On Thu, 7 May 2020 at 15:44, Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>
> Björn Töpel <bjorn.topel@gmail.com> writes:
>
> > Before I start hacking on this, I might as well check with the XDP
> > folks if this considered a crappy idea or not. :-)
> >
> > The XDP redirect flow for a packet is typical a dance of
> > bpf_redirect_map() that updates the bpf_redirect_info structure with
> > maps type/items, which is then followed by an xdp_do_redirect(). That
> > function takes an action based on the bpf_redirect_info content.
> >
> > I'd like to get rid of the xdp_do_redirect() call, and the
> > bpf_redirect_info (per-cpu) lookup. The idea is to introduce a new
> > (oh-no!) XDP action, say, XDP_CONSUMED and a built-in helper with
> > tail-call semantics.
> >
> > Something across the lines of:
> >
> > --8<--
> >
> > struct {
> >         __uint(type, BPF_MAP_TYPE_XSKMAP);
> >         __uint(max_entries, MAX_SOCKS);
> >         __uint(key_size, sizeof(int));
> >         __uint(value_size, sizeof(int));
> > } xsks_map SEC(".maps");
> >
> > SEC("xdp1")
> > int xdp_prog1(struct xdp_md *ctx)
> > {
> >         bpf_tail_call_redirect(ctx, &xsks_map, 0);
> >         // Redirect the packet to an AF_XDP socket at entry 0 of the
> >         // map.
> >         //
> >         // After a successful call, ctx is said to be
> >         // consumed. XDP_CONSUMED will be returned by the program.
> >         // Note that if the call is not successful, the buffer is
> >         // still valid.
> >         //
> >         // XDP_CONSUMED in the driver means that the driver should not
> >         // issue an xdp_do_direct() call, but only xdp_flush().
> >         //
> >         // The verifier need to be taught that XDP_CONSUMED can only
> >         // be returned "indirectly", meaning a bpf_tail_call_XXX()
> >         // call. An explicit "return XDP_CONSUMED" should be
> >         // rejected. Can that be implemented?
> >         return XDP_PASS; // or any other valid action.
> > }
> >
> > -->8--
> >
> > The bpf_tail_call_redirect() would work with all redirectable maps.
> >
> > Thoughts? Tomatoes? Pitchforks?
>
> The above answers the 'what'. Might be easier to evaluate if you also
> included the 'why'? :)
>

Ah! Sorry! Performance, performance, performance. Getting rid of a
bunch of calls/instructions per packet, which helps my (AF_XDP) case.
This would be faster than the regular REDIRECT path. Today, in
bpf_redirect_map(), instead of actually performing the action, we
populate the bpf_redirect_info structure, just to look up the action
again in xdp_do_redirect().

I'm pretty certain this would be a gain for AF_XDP (quite easy to do a
quick hack, and measure). It would also shave off the same amount of
instructions for "vanilla" XDP_REDIRECT cases. The bigger issue; Is
this new semantic something people would be comfortable being added to
XDP.


Cheers,
Björn

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 14:00   ` Björn Töpel
@ 2020-05-07 14:48     ` Toke Høiland-Jørgensen
  2020-05-07 18:08       ` John Fastabend
  2020-05-08  9:08       ` Björn Töpel
  0 siblings, 2 replies; 10+ messages in thread
From: Toke Høiland-Jørgensen @ 2020-05-07 14:48 UTC (permalink / raw)
  To: Björn Töpel; +Cc: bpf, Netdev, Jesper Dangaard Brouer

Björn Töpel <bjorn.topel@gmail.com> writes:

> On Thu, 7 May 2020 at 15:44, Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>>
>> Björn Töpel <bjorn.topel@gmail.com> writes:
>>
>> > Before I start hacking on this, I might as well check with the XDP
>> > folks if this considered a crappy idea or not. :-)
>> >
>> > The XDP redirect flow for a packet is typical a dance of
>> > bpf_redirect_map() that updates the bpf_redirect_info structure with
>> > maps type/items, which is then followed by an xdp_do_redirect(). That
>> > function takes an action based on the bpf_redirect_info content.
>> >
>> > I'd like to get rid of the xdp_do_redirect() call, and the
>> > bpf_redirect_info (per-cpu) lookup. The idea is to introduce a new
>> > (oh-no!) XDP action, say, XDP_CONSUMED and a built-in helper with
>> > tail-call semantics.
>> >
>> > Something across the lines of:
>> >
>> > --8<--
>> >
>> > struct {
>> >         __uint(type, BPF_MAP_TYPE_XSKMAP);
>> >         __uint(max_entries, MAX_SOCKS);
>> >         __uint(key_size, sizeof(int));
>> >         __uint(value_size, sizeof(int));
>> > } xsks_map SEC(".maps");
>> >
>> > SEC("xdp1")
>> > int xdp_prog1(struct xdp_md *ctx)
>> > {
>> >         bpf_tail_call_redirect(ctx, &xsks_map, 0);
>> >         // Redirect the packet to an AF_XDP socket at entry 0 of the
>> >         // map.
>> >         //
>> >         // After a successful call, ctx is said to be
>> >         // consumed. XDP_CONSUMED will be returned by the program.
>> >         // Note that if the call is not successful, the buffer is
>> >         // still valid.
>> >         //
>> >         // XDP_CONSUMED in the driver means that the driver should not
>> >         // issue an xdp_do_direct() call, but only xdp_flush().
>> >         //
>> >         // The verifier need to be taught that XDP_CONSUMED can only
>> >         // be returned "indirectly", meaning a bpf_tail_call_XXX()
>> >         // call. An explicit "return XDP_CONSUMED" should be
>> >         // rejected. Can that be implemented?
>> >         return XDP_PASS; // or any other valid action.
>> > }
>> >
>> > -->8--
>> >
>> > The bpf_tail_call_redirect() would work with all redirectable maps.
>> >
>> > Thoughts? Tomatoes? Pitchforks?
>>
>> The above answers the 'what'. Might be easier to evaluate if you also
>> included the 'why'? :)
>>
>
> Ah! Sorry! Performance, performance, performance. Getting rid of a
> bunch of calls/instructions per packet, which helps my (AF_XDP) case.
> This would be faster than the regular REDIRECT path. Today, in
> bpf_redirect_map(), instead of actually performing the action, we
> populate the bpf_redirect_info structure, just to look up the action
> again in xdp_do_redirect().
>
> I'm pretty certain this would be a gain for AF_XDP (quite easy to do a
> quick hack, and measure). It would also shave off the same amount of
> instructions for "vanilla" XDP_REDIRECT cases. The bigger issue; Is
> this new semantic something people would be comfortable being added to
> XDP.

Well, my immediate thought would be that the added complexity would not
be worth it, because:

- A new action would mean either you'd need to patch all drivers or
  (more likely) we'd end up with yet another difference between drivers'
  XDP support.

- BPF developers would suddenly have to choose - do this new faster
  thing, or be compatible? And manage the choice based on drivers they
  expect to run on, etc. This was already confusing with
  bpf_redirect()/bpf_redirect_map(), and this would introduce a third
  option!

So in light of this, I'd say the performance benefit would have to be
quite substantial for this to be worth it. Which we won't know until you
try it, I guess :)

Thinking of alternatives - couldn't you shoe-horn this into the existing
helper and return code? Say, introduce an IMMEDIATE_RETURN flag to the
existing helpers, which would change the behaviour to the tail call
semantics. When used, xdp_do_redirect() would then return immediately
(or you could even turn xdp_do_redirect() into an inlined wrapper that
checks the flag before issuing a CALL to the existing function). Any
reason why that wouldn't work?

-Toke


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 14:48     ` Toke Høiland-Jørgensen
@ 2020-05-07 18:08       ` John Fastabend
  2020-05-07 22:25         ` Toke Høiland-Jørgensen
                           ` (2 more replies)
  2020-05-08  9:08       ` Björn Töpel
  1 sibling, 3 replies; 10+ messages in thread
From: John Fastabend @ 2020-05-07 18:08 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, Björn Töpel
  Cc: bpf, Netdev, Jesper Dangaard Brouer

Toke Høiland-Jørgensen wrote:
> Björn Töpel <bjorn.topel@gmail.com> writes:
> 
> > On Thu, 7 May 2020 at 15:44, Toke Høiland-Jørgensen <toke@redhat.com> wrote:
> >>
> >> Björn Töpel <bjorn.topel@gmail.com> writes:
> >>
> >> > Before I start hacking on this, I might as well check with the XDP
> >> > folks if this considered a crappy idea or not. :-)
> >> >
> >> > The XDP redirect flow for a packet is typical a dance of
> >> > bpf_redirect_map() that updates the bpf_redirect_info structure with
> >> > maps type/items, which is then followed by an xdp_do_redirect(). That
> >> > function takes an action based on the bpf_redirect_info content.
> >> >
> >> > I'd like to get rid of the xdp_do_redirect() call, and the
> >> > bpf_redirect_info (per-cpu) lookup. The idea is to introduce a new
> >> > (oh-no!) XDP action, say, XDP_CONSUMED and a built-in helper with
> >> > tail-call semantics.
> >> >
> >> > Something across the lines of:
> >> >
> >> > --8<--
> >> >
> >> > struct {
> >> >         __uint(type, BPF_MAP_TYPE_XSKMAP);
> >> >         __uint(max_entries, MAX_SOCKS);
> >> >         __uint(key_size, sizeof(int));
> >> >         __uint(value_size, sizeof(int));
> >> > } xsks_map SEC(".maps");
> >> >
> >> > SEC("xdp1")
> >> > int xdp_prog1(struct xdp_md *ctx)
> >> > {
> >> >         bpf_tail_call_redirect(ctx, &xsks_map, 0);
> >> >         // Redirect the packet to an AF_XDP socket at entry 0 of the
> >> >         // map.
> >> >         //
> >> >         // After a successful call, ctx is said to be
> >> >         // consumed. XDP_CONSUMED will be returned by the program.
> >> >         // Note that if the call is not successful, the buffer is
> >> >         // still valid.
> >> >         //
> >> >         // XDP_CONSUMED in the driver means that the driver should not
> >> >         // issue an xdp_do_direct() call, but only xdp_flush().
> >> >         //
> >> >         // The verifier need to be taught that XDP_CONSUMED can only
> >> >         // be returned "indirectly", meaning a bpf_tail_call_XXX()
> >> >         // call. An explicit "return XDP_CONSUMED" should be
> >> >         // rejected. Can that be implemented?
> >> >         return XDP_PASS; // or any other valid action.
> >> > }

I'm wondering if we can teach the verifier to recognize tail calls,

int xdp_prog1(struct xdp_md *ctx)
{
	return xdp_do_redirect(ctx, &xsks_map, 0);
}

This would be useful for normal calls as well. I guess the question here
is would a tail call be sufficient for above case or do you need the
'return XDP_PASS' at the end? If so maybe we could fold it into the
helper somehow.

I think it would also address Toke's concerns, no new action so
bpf developers can just develope like normal but "smart" developers
will try do calls as tail calls. Not sure it can be done without
driver changes though.

> >> >
> >> > -->8--
> >> >
> >> > The bpf_tail_call_redirect() would work with all redirectable maps.
> >> >
> >> > Thoughts? Tomatoes? Pitchforks?
> >>
> >> The above answers the 'what'. Might be easier to evaluate if you also
> >> included the 'why'? :)
> >>
> >
> > Ah! Sorry! Performance, performance, performance. Getting rid of a
> > bunch of calls/instructions per packet, which helps my (AF_XDP) case.
> > This would be faster than the regular REDIRECT path. Today, in
> > bpf_redirect_map(), instead of actually performing the action, we
> > populate the bpf_redirect_info structure, just to look up the action
> > again in xdp_do_redirect().
> >
> > I'm pretty certain this would be a gain for AF_XDP (quite easy to do a
> > quick hack, and measure). It would also shave off the same amount of
> > instructions for "vanilla" XDP_REDIRECT cases. The bigger issue; Is
> > this new semantic something people would be comfortable being added to
> > XDP.
> 
> Well, my immediate thought would be that the added complexity would not
> be worth it, because:
> 
> - A new action would mean either you'd need to patch all drivers or
>   (more likely) we'd end up with yet another difference between drivers'
>   XDP support.
> 
> - BPF developers would suddenly have to choose - do this new faster
>   thing, or be compatible? And manage the choice based on drivers they
>   expect to run on, etc. This was already confusing with
>   bpf_redirect()/bpf_redirect_map(), and this would introduce a third
>   option!
> 
> So in light of this, I'd say the performance benefit would have to be
> quite substantial for this to be worth it. Which we won't know until you
> try it, I guess :)

Knowing the number would be useful. But if it can be done in general
way it may not need to be as high because its not a special xdp thing.

> 
> Thinking of alternatives - couldn't you shoe-horn this into the existing
> helper and return code? Say, introduce an IMMEDIATE_RETURN flag to the
> existing helpers, which would change the behaviour to the tail call
> semantics. When used, xdp_do_redirect() would then return immediately
> (or you could even turn xdp_do_redirect() into an inlined wrapper that
> checks the flag before issuing a CALL to the existing function). Any
> reason why that wouldn't work?

I think it would work but I it would be even nicer if clang, verifier
and jit caught the tail call pattern and did it automatically.

> 
> -Toke
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 18:08       ` John Fastabend
@ 2020-05-07 22:25         ` Toke Høiland-Jørgensen
  2020-05-07 23:41         ` Alexei Starovoitov
  2020-05-08  9:09         ` Björn Töpel
  2 siblings, 0 replies; 10+ messages in thread
From: Toke Høiland-Jørgensen @ 2020-05-07 22:25 UTC (permalink / raw)
  To: John Fastabend, Björn Töpel; +Cc: bpf, Netdev, Jesper Dangaard Brouer

John Fastabend <john.fastabend@gmail.com> writes:

> Toke Høiland-Jørgensen wrote:
>> Björn Töpel <bjorn.topel@gmail.com> writes:
>> 
>> > On Thu, 7 May 2020 at 15:44, Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>> >>
>> >> Björn Töpel <bjorn.topel@gmail.com> writes:
>> >>
>> >> > Before I start hacking on this, I might as well check with the XDP
>> >> > folks if this considered a crappy idea or not. :-)
>> >> >
>> >> > The XDP redirect flow for a packet is typical a dance of
>> >> > bpf_redirect_map() that updates the bpf_redirect_info structure with
>> >> > maps type/items, which is then followed by an xdp_do_redirect(). That
>> >> > function takes an action based on the bpf_redirect_info content.
>> >> >
>> >> > I'd like to get rid of the xdp_do_redirect() call, and the
>> >> > bpf_redirect_info (per-cpu) lookup. The idea is to introduce a new
>> >> > (oh-no!) XDP action, say, XDP_CONSUMED and a built-in helper with
>> >> > tail-call semantics.
>> >> >
>> >> > Something across the lines of:
>> >> >
>> >> > --8<--
>> >> >
>> >> > struct {
>> >> >         __uint(type, BPF_MAP_TYPE_XSKMAP);
>> >> >         __uint(max_entries, MAX_SOCKS);
>> >> >         __uint(key_size, sizeof(int));
>> >> >         __uint(value_size, sizeof(int));
>> >> > } xsks_map SEC(".maps");
>> >> >
>> >> > SEC("xdp1")
>> >> > int xdp_prog1(struct xdp_md *ctx)
>> >> > {
>> >> >         bpf_tail_call_redirect(ctx, &xsks_map, 0);
>> >> >         // Redirect the packet to an AF_XDP socket at entry 0 of the
>> >> >         // map.
>> >> >         //
>> >> >         // After a successful call, ctx is said to be
>> >> >         // consumed. XDP_CONSUMED will be returned by the program.
>> >> >         // Note that if the call is not successful, the buffer is
>> >> >         // still valid.
>> >> >         //
>> >> >         // XDP_CONSUMED in the driver means that the driver should not
>> >> >         // issue an xdp_do_direct() call, but only xdp_flush().
>> >> >         //
>> >> >         // The verifier need to be taught that XDP_CONSUMED can only
>> >> >         // be returned "indirectly", meaning a bpf_tail_call_XXX()
>> >> >         // call. An explicit "return XDP_CONSUMED" should be
>> >> >         // rejected. Can that be implemented?
>> >> >         return XDP_PASS; // or any other valid action.
>> >> > }
>
> I'm wondering if we can teach the verifier to recognize tail calls,
>
> int xdp_prog1(struct xdp_md *ctx)
> {
> 	return xdp_do_redirect(ctx, &xsks_map, 0);
> }
>
> This would be useful for normal calls as well. I guess the question here
> is would a tail call be sufficient for above case or do you need the
> 'return XDP_PASS' at the end? If so maybe we could fold it into the
> helper somehow.
>
> I think it would also address Toke's concerns, no new action so
> bpf developers can just develope like normal but "smart" developers
> will try do calls as tail calls.

This is certainly an interesting idea! Functional languages tend to
auto-optimise tail calls, so detecting them is certainly possible, at
least for the compiler. I suppose this could be a follow-on
optimisation, though, couldn't it? From the PoV of the surrounding code
(in the kernel), it doesn't really matter if the behaviour was signalled
by an explicit flag added in the code, or if this flag was automatically
added by the compiler.

> Not sure it can be done without driver changes though.

Well yeah, that's hard to know in the abstract, obviously. My point is
just that we should look very hard indeed before we decide it can't :)

-Toke


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 18:08       ` John Fastabend
  2020-05-07 22:25         ` Toke Høiland-Jørgensen
@ 2020-05-07 23:41         ` Alexei Starovoitov
  2020-05-08  9:09         ` Björn Töpel
  2 siblings, 0 replies; 10+ messages in thread
From: Alexei Starovoitov @ 2020-05-07 23:41 UTC (permalink / raw)
  To: John Fastabend
  Cc: Toke Høiland-Jørgensen, Björn Töpel, bpf,
	Netdev, Jesper Dangaard Brouer

On Thu, May 7, 2020 at 11:09 AM John Fastabend <john.fastabend@gmail.com> wrote:
>
> I think it would work but I it would be even nicer if clang, verifier
> and jit caught the tail call pattern and did it automatically.

I've been advocating for proper tail calls for some time :)
All it needs is indirect jump instruction in the ISA.
The changes to llvm are trivial. Encoding of new insn is
straightforward as well.
The verifier side is tricky.
What you're proposing makes sense to me.
Somehow I thought that we need full indirect jump from day one,
but above is much simpler. It's a subset of it.
It's still an indirect jump, but target is always fixed.
The register will be initialized with fixed address of next kernel function
(or helper). That should be easy enough to support in the verifier.
llvm will generate:
ld_imm64 rX = addr_of_next_helper // that could be encoded via pseudo,
like for calls to helpers
jmp *rX

We can introduce an extension to JA insn instead that
takes 64-bit immediate or pc relative offset, but I think
it will be more messy to support through llvm, libbpf relocations and
the verifier.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 14:48     ` Toke Høiland-Jørgensen
  2020-05-07 18:08       ` John Fastabend
@ 2020-05-08  9:08       ` Björn Töpel
  1 sibling, 0 replies; 10+ messages in thread
From: Björn Töpel @ 2020-05-08  9:08 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen; +Cc: bpf, Netdev, Jesper Dangaard Brouer

On Thu, 7 May 2020 at 16:48, Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>
[]
> Well, my immediate thought would be that the added complexity would not
> be worth it, because:
>
> - A new action would mean either you'd need to patch all drivers or
>   (more likely) we'd end up with yet another difference between drivers'
>   XDP support.
>

Right, but it would be trivial to add for drivers that already support
XDP_REDIRECT, so I'm not worried about that particular problem. That
aside, let's move on. I agree that adding action should be avoided!

> - BPF developers would suddenly have to choose - do this new faster
>   thing, or be compatible? And manage the choice based on drivers they
>   expect to run on, etc. This was already confusing with
>   bpf_redirect()/bpf_redirect_map(), and this would introduce a third
>   option!
>

True. For the sake of the argument; Adding flags vs adding a new
helper, i.e. bpf_redirect_map(flag_with_new_semantic) vs a new helper.
Today XDP developers that use bpf_redirect_map() need to consider
whether the kernel support the "pass action via flags" or not, so this
would be a *fourth* option. :-P

I'm with you here. The best option would be a transparent one.


> So in light of this, I'd say the performance benefit would have to be
> quite substantial for this to be worth it. Which we won't know until you
> try it, I guess :)
>

Hear, hear!

> Thinking of alternatives - couldn't you shoe-horn this into the existing
> helper and return code? Say, introduce an IMMEDIATE_RETURN flag to the
> existing helpers, which would change the behaviour to the tail call
> semantics. When used, xdp_do_redirect() would then return immediately
> (or you could even turn xdp_do_redirect() into an inlined wrapper that
> checks the flag before issuing a CALL to the existing function). Any
> reason why that wouldn't work?
>

Sure, but this wouldn't remove the per-cpu/bpf_redirect_info lookup.
Then again, maybe it's better to start there. To clarify, just a flag
isn't sufficient. It would need to be a guarantee that the program
exists after the call, i.e. tail call support. From clang/BPF
instruction (Alexei's/John's replies), or something like
bpf_tail_call(). Unless I'm missing something... Or do you mean that
the flag IMMEDIATE_RETURN would perform the action in the helper? The
context would be stale after that call, and the verifier should reject
a program that pokes the context, but the flag is a runtime thing. It
sounds like a pretty complex verifier task to determine if
IMMEDIATE_RETURN is set, and then reject ctx accesses there.


Thanks for the input, and good ideas!
Björn

> -Toke
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-07 18:08       ` John Fastabend
  2020-05-07 22:25         ` Toke Høiland-Jørgensen
  2020-05-07 23:41         ` Alexei Starovoitov
@ 2020-05-08  9:09         ` Björn Töpel
  2020-05-08 14:18           ` Toke Høiland-Jørgensen
  2 siblings, 1 reply; 10+ messages in thread
From: Björn Töpel @ 2020-05-08  9:09 UTC (permalink / raw)
  To: John Fastabend
  Cc: Toke Høiland-Jørgensen, bpf, Netdev, Jesper Dangaard Brouer

On Thu, 7 May 2020 at 20:08, John Fastabend <john.fastabend@gmail.com> wrote:
>
[]
>
> I'm wondering if we can teach the verifier to recognize tail calls,
>
> int xdp_prog1(struct xdp_md *ctx)
> {
>         return xdp_do_redirect(ctx, &xsks_map, 0);
> }
>
> This would be useful for normal calls as well. I guess the question here
> is would a tail call be sufficient for above case or do you need the
> 'return XDP_PASS' at the end? If so maybe we could fold it into the
> helper somehow.
>

No, that was just for handling the "failed call", bpf_tail_call() style.

> I think it would also address Toke's concerns, no new action so
> bpf developers can just develope like normal but "smart" developers
> will try do calls as tail calls. Not sure it can be done without
> driver changes though.
>

Take me though this. So, the new xdp_do_redirect() would return
XDP_REDIRECT? If the call is a tail call, we can "consume" (perform
the REDIRECT action) in the helper, set a "we're done/tail call
performed" flag in bpf_redirect_info and the xdp_do_redirect() checks
this flag and returns directly. If the call is *not* a tail call, the
regular REDIRECT path is performed. Am I following that correctly? So
we would be able to detect if the optimization has been performed, so
the "consume" semantics can be done.

Or do you mean that xdp_do_redirect() is only allowed if it can be
tailcall optimized?

int xdp_prog1(struct xdp_md *ctx)
{
        int ret;

        ret = xdp_do_redirect(ctx, &xsks_map, 0);
        // If xdp_do_redirect() consumes the context, the ctx is stale
        // here.
        ...
        return ret;
}

Let me clarify what I'm trying to do. bpf_redirect_map() performs a
lookup into the map. It would make sense to perform the action here as
well, since everything (maptype/item)is known. Today,
bpf_redirect_info is populated, and then the maptype is looked up
again from xdp_do_redirect(), and bpf_redirect_info() is cleared. I'd
like to get rid of bpf_redirect_info and xdp_do_redirect(), when
possible.

> > >> >
> > >> > -->8--
> > >> >
> > >> > The bpf_tail_call_redirect() would work with all redirectable maps.
> > >> >
> > >> > Thoughts? Tomatoes? Pitchforks?
> > >>
> > >> The above answers the 'what'. Might be easier to evaluate if you also
> > >> included the 'why'? :)
> > >>
> > >
> > > Ah! Sorry! Performance, performance, performance. Getting rid of a
> > > bunch of calls/instructions per packet, which helps my (AF_XDP) case.
> > > This would be faster than the regular REDIRECT path. Today, in
> > > bpf_redirect_map(), instead of actually performing the action, we
> > > populate the bpf_redirect_info structure, just to look up the action
> > > again in xdp_do_redirect().
> > >
> > > I'm pretty certain this would be a gain for AF_XDP (quite easy to do a
> > > quick hack, and measure). It would also shave off the same amount of
> > > instructions for "vanilla" XDP_REDIRECT cases. The bigger issue; Is
> > > this new semantic something people would be comfortable being added to
> > > XDP.
> >
> > Well, my immediate thought would be that the added complexity would not
> > be worth it, because:
> >
> > - A new action would mean either you'd need to patch all drivers or
> >   (more likely) we'd end up with yet another difference between drivers'
> >   XDP support.
> >
> > - BPF developers would suddenly have to choose - do this new faster
> >   thing, or be compatible? And manage the choice based on drivers they
> >   expect to run on, etc. This was already confusing with
> >   bpf_redirect()/bpf_redirect_map(), and this would introduce a third
> >   option!
> >
> > So in light of this, I'd say the performance benefit would have to be
> > quite substantial for this to be worth it. Which we won't know until you
> > try it, I guess :)
>
> Knowing the number would be useful. But if it can be done in general
> way it may not need to be as high because its not a special xdp thing.
>

Yeah, I need to do some experimentation here!

> >
> > Thinking of alternatives - couldn't you shoe-horn this into the existing
> > helper and return code? Say, introduce an IMMEDIATE_RETURN flag to the
> > existing helpers, which would change the behaviour to the tail call
> > semantics. When used, xdp_do_redirect() would then return immediately
> > (or you could even turn xdp_do_redirect() into an inlined wrapper that
> > checks the flag before issuing a CALL to the existing function). Any
> > reason why that wouldn't work?
>
> I think it would work but I it would be even nicer if clang, verifier
> and jit caught the tail call pattern and did it automatically.
>

Yes. :-)


Thanks for the input, and the ideas!
Björn

> >
> > -Toke
> >

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: XDP bpf_tail_call_redirect(): yea or nay?
  2020-05-08  9:09         ` Björn Töpel
@ 2020-05-08 14:18           ` Toke Høiland-Jørgensen
  0 siblings, 0 replies; 10+ messages in thread
From: Toke Høiland-Jørgensen @ 2020-05-08 14:18 UTC (permalink / raw)
  To: Björn Töpel, John Fastabend; +Cc: bpf, Netdev, Jesper Dangaard Brouer

Björn Töpel <bjorn.topel@gmail.com> writes:

> On Thu, 7 May 2020 at 20:08, John Fastabend <john.fastabend@gmail.com> wrote:
>>
> []
>>
>> I'm wondering if we can teach the verifier to recognize tail calls,
>>
>> int xdp_prog1(struct xdp_md *ctx)
>> {
>>         return xdp_do_redirect(ctx, &xsks_map, 0);
>> }
>>
>> This would be useful for normal calls as well. I guess the question here
>> is would a tail call be sufficient for above case or do you need the
>> 'return XDP_PASS' at the end? If so maybe we could fold it into the
>> helper somehow.
>>
>
> No, that was just for handling the "failed call", bpf_tail_call() style.
>
>> I think it would also address Toke's concerns, no new action so
>> bpf developers can just develope like normal but "smart" developers
>> will try do calls as tail calls. Not sure it can be done without
>> driver changes though.
>>
>
> Take me though this. So, the new xdp_do_redirect() would return
> XDP_REDIRECT? If the call is a tail call, we can "consume" (perform
> the REDIRECT action) in the helper, set a "we're done/tail call
> performed" flag in bpf_redirect_info and the xdp_do_redirect() checks
> this flag and returns directly. If the call is *not* a tail call, the
> regular REDIRECT path is performed. Am I following that correctly? So
> we would be able to detect if the optimization has been performed, so
> the "consume" semantics can be done.

Yeah, that was my understanding. And what I meant with the 'new flag'
bit was that you could prototype this by just adding a new flag to
bpf_redirect_map() which would trigger this consume behaviour. That
would allow you to get performance numbers without waiting for the
verifier to learn about tail calls... :)

-Toke


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-05-08 14:18 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-07 12:20 XDP bpf_tail_call_redirect(): yea or nay? Björn Töpel
2020-05-07 13:44 ` Toke Høiland-Jørgensen
2020-05-07 14:00   ` Björn Töpel
2020-05-07 14:48     ` Toke Høiland-Jørgensen
2020-05-07 18:08       ` John Fastabend
2020-05-07 22:25         ` Toke Høiland-Jørgensen
2020-05-07 23:41         ` Alexei Starovoitov
2020-05-08  9:09         ` Björn Töpel
2020-05-08 14:18           ` Toke Høiland-Jørgensen
2020-05-08  9:08       ` Björn Töpel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).