Toke Høiland-Jørgensen <t...@redhat.com> writes: > Daniel Borkmann <dan...@iogearbox.net> writes: > >> On 06/28/2019 09:17 AM, Toke Høiland-Jørgensen wrote: >>> Daniel Borkmann <dan...@iogearbox.net> writes: >>> >>>> On 06/23/2019 04:17 AM, Toke Høiland-Jørgensen wrote: >>>>> From: Toke Høiland-Jørgensen <t...@redhat.com> >>>>> >>>>> The bpf_redirect_map() helper used by XDP programs doesn't return any >>>>> indication of whether it can successfully redirect to the map index it was >>>>> given. Instead, BPF programs have to track this themselves, leading to >>>>> programs using duplicate maps to track which entries are populated in the >>>>> devmap. >>>>> >>>>> This patch fixes this by moving the map lookup into the bpf_redirect_map() >>>>> helper, which makes it possible to return failure to the eBPF program. The >>>>> lower bits of the flags argument is used as the return code, which means >>>>> that existing users who pass a '0' flag argument will get XDP_ABORTED. >>>>> >>>>> With this, a BPF program can check the return code from the helper call >>>>> and >>>>> react by, for instance, substituting a different redirect. This works for >>>>> any type of map used for redirect. >>>>> >>>>> Signed-off-by: Toke Høiland-Jørgensen <t...@redhat.com> >>>> >>>> Overall series looks good to me. Just very small things inline here & in >>>> the >>>> other two patches: >>>> >>>> [...] >>>>> @@ -3750,9 +3742,16 @@ BPF_CALL_3(bpf_xdp_redirect_map, struct bpf_map *, >>>>> map, u32, ifindex, >>>>> { >>>>> struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); >>>>> >>>>> - if (unlikely(flags)) >>>>> + /* Lower bits of the flags are used as return code on lookup failure */ >>>>> + if (unlikely(flags > XDP_TX)) >>>>> return XDP_ABORTED; >>>>> >>>>> + ri->item = __xdp_map_lookup_elem(map, ifindex); >>>>> + if (unlikely(!ri->item)) { >>>>> + WRITE_ONCE(ri->map, NULL); >>>> >>>> This WRITE_ONCE() is not needed. We never set it before at this point. >>> >>> You mean the WRITE_ONCE() wrapper is not needed, or the set-to-NULL is >>> not needed? The reason I added it is in case an eBPF program calls the >>> helper twice before returning, where the first lookup succeeds but the >>> second fails; in that case we want to clear the ->map pointer, no? >> >> Yeah I meant the set-to-NULL. So if first call succeeds, and the second one >> fails, then the expected semantics wrt the first call are as if the program >> would have called bpf_xdp_redirect() only? >> >> Looking at the code again, if we set ri->item to NULL, then we /must/ >> also set ri->map to NULL. I guess there are two options: i) leave as >> is, ii) keep the __xdp_map_lookup_elem() result in a temp var, if it's >> NULL return flags, otherwise only /then/ update ri->item, so that >> semantics are similar to the invalid flags check earlier. I guess fine >> either way, in case of i) there should probably be a comment since >> it's less obvious. > > Yeah, I think a temp var is probably clearer, will do that :)
Actually, thinking about this some more, I think it's better to completely clear out the state the second time around. I'll add a comment to explain. -Toke