From: "Toke Høiland-Jørgensen" <toke@redhat.com>
To: Lorenz Bauer <lmb@cloudflare.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>,
Alexei Starovoitov <ast@kernel.org>,
Martin KaFai Lau <kafai@fb.com>, Song Liu <songliubraving@fb.com>,
Yonghong Song <yhs@fb.com>,
Marek Majkowski <marek@cloudflare.com>,
David Miller <davem@davemloft.net>,
Jesper Dangaard Brouer <brouer@redhat.com>,
Networking <netdev@vger.kernel.org>, bpf <bpf@vger.kernel.org>,
kernel-team <kernel-team@cloudflare.com>
Subject: Re: [PATCH bpf-next 2/9] xdp: Add new xdp_chain_map type for specifying XDP call sequences
Date: Wed, 02 Oct 2019 20:25:32 +0200 [thread overview]
Message-ID: <878sq3romb.fsf@toke.dk> (raw)
In-Reply-To: <CACAyw9-u7oAmC1F4rW8wH2a2aoxrDHCENcM4j5WmriS7YLmevQ@mail.gmail.com>
Lorenz Bauer <lmb@cloudflare.com> writes:
> On Wed, 2 Oct 2019 at 14:30, Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>>
>> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
>> index 113e1286e184..ab855095c830 100644
>> --- a/kernel/bpf/hashtab.c
>> +++ b/kernel/bpf/hashtab.c
>> @@ -1510,3 +1510,156 @@ const struct bpf_map_ops htab_of_maps_map_ops = {
>> .map_gen_lookup = htab_of_map_gen_lookup,
>> .map_check_btf = map_check_no_btf,
>> };
>> +
>> +struct xdp_chain_table {
>> + struct bpf_prog *wildcard_act;
>> + struct bpf_prog *act[XDP_ACT_MAX];
>> +};
>> +
>> +static int xdp_chain_map_alloc_check(union bpf_attr *attr)
>> +{
>> + BUILD_BUG_ON(sizeof(struct xdp_chain_table) / sizeof(void *) !=
>> + sizeof(struct xdp_chain_acts) / sizeof(u32));
>> +
>> + if (attr->key_size != sizeof(u32) ||
>> + attr->value_size != sizeof(struct xdp_chain_acts))
>> + return -EINVAL;
>
> How are we going to extend xdp_chain_acts if a new XDP action is
> introduced?
By just checking the size and reacting appropriately? Don't think that
is problematic, just takes a few if statements here?
>> +
>> + attr->value_size = sizeof(struct xdp_chain_table);
>> + return htab_map_alloc_check(attr);
>> +}
>> +
>> +struct bpf_prog *bpf_xdp_chain_map_get_prog(struct bpf_map *map,
>> + u32 prev_id,
>> + enum xdp_action action)
>> +{
>> + struct xdp_chain_table *tab;
>> + void *ptr;
>> +
>> + ptr = htab_map_lookup_elem(map, &prev_id);
>> +
>> + if (!ptr)
>> + return NULL;
>> +
>> + tab = READ_ONCE(ptr);
>> + return tab->act[action - 1] ?: tab->wildcard_act;
>> +}
>> +EXPORT_SYMBOL_GPL(bpf_xdp_chain_map_get_prog);
>> +
>> +/* only called from syscall */
>> +int bpf_xdp_chain_map_lookup_elem(struct bpf_map *map, void *key, void *value)
>> +{
>> + struct xdp_chain_acts *act = value;
>> + struct xdp_chain_table *tab;
>> + void *ptr;
>> + u32 *cur;
>> + int i;
>> +
>> + ptr = htab_map_lookup_elem(map, key);
>> + if (!ptr)
>> + return -ENOENT;
>> +
>> + tab = READ_ONCE(ptr);
>> +
>> + if (tab->wildcard_act)
>> + act->wildcard_act = tab->wildcard_act->aux->id;
>> +
>> + cur = &act->drop_act;
>> + for (i = 0; i < XDP_ACT_MAX; i++, cur++)
>> + if(tab->act[i])
>> + *cur = tab->act[i]->aux->id;
>
> For completeness, zero out *cur in the else case?
Ah, good point. I assumed the caller was kzalloc'ing; seems that's not
the case; will fix.
>> +
>> + return 0;
>> +}
>> +
>> +static void *xdp_chain_map_get_ptr(int fd)
>> +{
>> + struct bpf_prog *prog = bpf_prog_get(fd);
>> +
>> + if (IS_ERR(prog))
>> + return prog;
>> +
>> + if (prog->type != BPF_PROG_TYPE_XDP ||
>> + bpf_prog_is_dev_bound(prog->aux)) {
>> + bpf_prog_put(prog);
>> + return ERR_PTR(-EINVAL);
>> + }
>> +
>> + return prog;
>> +}
>> +
>> +static void xdp_chain_map_put_ptrs(void *value)
>> +{
>> + struct xdp_chain_table *tab = value;
>> + int i;
>> +
>> + for (i = 0; i < XDP_ACT_MAX; i++)
>> + if (tab->act[i])
>> + bpf_prog_put(tab->act[i]);
>> +
>> + if (tab->wildcard_act)
>> + bpf_prog_put(tab->wildcard_act);
>> +}
>> +
>> +/* only called from syscall */
>> +int bpf_xdp_chain_map_update_elem(struct bpf_map *map, void *key, void *value,
>> + u64 map_flags)
>
> Nit: check that map_flags == 0
Yup, will fix.
>> +{
>> + struct xdp_chain_acts *act = value;
>> + struct xdp_chain_table tab = {};
>> + u32 lookup_key = *((u32*)key);
>> + u32 *cur = &act->drop_act;
>> + bool found_val = false;
>> + int ret, i;
>> + void *ptr;
>> +
>> + if (!lookup_key)
>> + return -EINVAL;
>
> Is it possible to check that this is a valid prog id / fd or whatever
> it is?
I suppose we could. The reason I didn't was that I figured it would be
valid to insert IDs into the map that don't exist (yet, or any longer).
Theoretically, if you can predict the program ID, you could insert it
into the map before it's allocated. There's no clearing of maps when
program IDs are freed either.
>> +
>> + if (act->wildcard_act) {
>
> If this is an fd, 0 is a valid value no?
Yes, technically. But if we actually allow fd 0, that means the
userspace caller can't just pass a 0-initialised struct, but will have
to loop through and explicitly set everything to -1. Whereas if we just
disallow fd 0, that is no longer a problem (and normally you have to
jump through some hoops to end up with a bpf program pointer as standard
input, no?).
It's not ideal, but I figured this was the least ugly way to do it. If
you have a better idea I'm all ears? :)
>> + ptr = xdp_chain_map_get_ptr(act->wildcard_act);
>> + if (IS_ERR(ptr))
>> + return PTR_ERR(ptr);
>> + tab.wildcard_act = ptr;
>> + found_val = true;
>> + }
>> +
>> + for (i = 0; i < XDP_ACT_MAX; i++, cur++) {
>> + if (*cur) {
>> + ptr = xdp_chain_map_get_ptr(*cur);
>> + if (IS_ERR(ptr)) {
>> + ret = PTR_ERR(ptr);
>> + goto out_err;
>> + }
>> + tab.act[i] = ptr;
>> + found_val = true;
>> + }
>> + }
>> +
>> + if (!found_val) {
>> + ret = -EINVAL;
>> + goto out_err;
>> + }
>> +
>> + ret = htab_map_update_elem(map, key, &tab, map_flags);
>> + if (ret)
>> + goto out_err;
>> +
>> + return ret;
>> +
>> +out_err:
>> + xdp_chain_map_put_ptrs(&tab);
>> +
>> + return ret;
>> +}
>> +
>> +
>> +const struct bpf_map_ops xdp_chain_map_ops = {
>> + .map_alloc_check = xdp_chain_map_alloc_check,
>> + .map_alloc = htab_map_alloc,
>> + .map_free = fd_htab_map_free,
>> + .map_get_next_key = htab_map_get_next_key,
>> + .map_delete_elem = htab_map_delete_elem,
>> + .map_fd_put_value = xdp_chain_map_put_ptrs,
>> + .map_check_btf = map_check_no_btf,
>> +};
>
> --
> Lorenz Bauer | Systems Engineer
> 6th Floor, County Hall/The Riverside Building, SE1 7PB, UK
>
> www.cloudflare.com
next prev parent reply other threads:[~2019-10-02 18:25 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-02 13:30 [PATCH bpf-next 0/9] xdp: Support multiple programs on a single interface through chain calls Toke Høiland-Jørgensen
2019-10-02 13:30 ` [PATCH bpf-next 1/9] hashtab: Add new bpf_map_fd_put_value op Toke Høiland-Jørgensen
2019-10-02 13:30 ` [PATCH bpf-next 2/9] xdp: Add new xdp_chain_map type for specifying XDP call sequences Toke Høiland-Jørgensen
2019-10-02 15:50 ` Lorenz Bauer
2019-10-02 18:25 ` Toke Høiland-Jørgensen [this message]
2019-10-02 13:30 ` [PATCH bpf-next 3/9] xdp: Support setting and getting device chain map Toke Høiland-Jørgensen
2019-10-02 15:50 ` Lorenz Bauer
2019-10-02 18:32 ` Toke Høiland-Jørgensen
2019-10-02 18:07 ` kbuild test robot
2019-10-02 18:29 ` kbuild test robot
2019-10-02 13:30 ` [PATCH bpf-next 4/9] xdp: Implement chain call logic to support multiple programs on one interface Toke Høiland-Jørgensen
2019-10-02 17:33 ` kbuild test robot
2019-10-02 17:53 ` kbuild test robot
2019-10-02 13:30 ` [PATCH bpf-next 5/9] tools/include/uapi: Add XDP chain map definitions Toke Høiland-Jørgensen
2019-10-02 13:30 ` [PATCH bpf-next 6/9] tools/libbpf_probes: Add support for xdp_chain map type Toke Høiland-Jørgensen
2019-10-02 13:30 ` [PATCH bpf-next 7/9] bpftool: Add definitions " Toke Høiland-Jørgensen
2019-10-02 13:30 ` [PATCH bpf-next 8/9] libbpf: Add support for setting and getting XDP chain maps Toke Høiland-Jørgensen
2019-10-02 13:30 ` [PATCH bpf-next 9/9] selftests: Add tests for XDP chain calls Toke Høiland-Jørgensen
2019-10-02 15:10 ` [PATCH bpf-next 0/9] xdp: Support multiple programs on a single interface through " Alan Maguire
2019-10-02 15:33 ` Toke Høiland-Jørgensen
2019-10-02 16:34 ` John Fastabend
2019-10-02 18:33 ` Toke Høiland-Jørgensen
2019-10-02 20:34 ` John Fastabend
2019-10-03 7:48 ` Toke Høiland-Jørgensen
2019-10-03 10:09 ` Jesper Dangaard Brouer
2019-10-03 19:45 ` John Fastabend
2019-10-02 16:35 ` Lorenz Bauer
2019-10-02 18:54 ` Toke Høiland-Jørgensen
2019-10-02 16:43 ` John Fastabend
2019-10-02 19:09 ` Toke Høiland-Jørgensen
2019-10-02 19:15 ` Daniel Borkmann
2019-10-02 19:29 ` Toke Høiland-Jørgensen
2019-10-02 19:46 ` Alexei Starovoitov
2019-10-03 7:58 ` Toke Høiland-Jørgensen
2019-10-02 18:38 ` Song Liu
2019-10-02 18:54 ` Song Liu
2019-10-02 19:25 ` Toke Høiland-Jørgensen
2019-10-03 8:53 ` Jesper Dangaard Brouer
2019-10-03 14:03 ` Alexei Starovoitov
2019-10-03 14:33 ` Toke Høiland-Jørgensen
2019-10-03 14:53 ` Edward Cree
2019-10-03 18:49 ` Jesper Dangaard Brouer
2019-10-03 19:35 ` John Fastabend
2019-10-04 8:09 ` Toke Høiland-Jørgensen
2019-10-04 10:34 ` Edward Cree
2019-10-04 15:58 ` Lorenz Bauer
2019-10-07 16:43 ` Edward Cree
2019-10-07 17:12 ` Lorenz Bauer
2019-10-07 19:21 ` Edward Cree
2019-10-07 21:01 ` Alexei Starovoitov
2019-10-02 19:23 ` Toke Høiland-Jørgensen
2019-10-02 19:49 ` Song Liu
2019-10-03 7:59 ` Toke Høiland-Jørgensen
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=878sq3romb.fsf@toke.dk \
--to=toke@redhat.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brouer@redhat.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=kafai@fb.com \
--cc=kernel-team@cloudflare.com \
--cc=lmb@cloudflare.com \
--cc=marek@cloudflare.com \
--cc=netdev@vger.kernel.org \
--cc=songliubraving@fb.com \
--cc=yhs@fb.com \
/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 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).