[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <875zch3de6.fsf@toke.dk>
Date: Wed, 27 May 2020 12:01:21 +0200
From: Toke Høiland-Jørgensen <toke@...hat.com>
To: David Ahern <dsahern@...nel.org>, netdev@...r.kernel.org
Cc: davem@...emloft.net, kuba@...nel.org, brouer@...hat.com,
daniel@...earbox.net, john.fastabend@...il.com, ast@...nel.org,
kafai@...com, songliubraving@...com, yhs@...com, andriin@...com,
dsahern@...il.com, David Ahern <dsahern@...nel.org>
Subject: Re: [PATCH bpf-next 2/5] bpf: Add support to attach bpf program to a devmap entry
David Ahern <dsahern@...nel.org> writes:
> Add BPF_XDP_DEVMAP attach type for use with programs associated with a
> DEVMAP entry.
>
> DEVMAPs can associate a program with a device entry by setting the
> value to <index, fd> pair. The program associated with the fd must have
> type XDP with expected attach type BPF_XDP_DEVMAP. When a program is
> associated with a device index, the program is run on an XDP_REDIRECT
> and before the buffer is added to the per-cpu queue. At this point
> rxq data is still valid; the next patch adds tx device information
> allowing the prorgam to see both ingress and egress device indices.
>
> XDP generic is skb based and XDP programs do not work with skb's. Block
> the use case by walking maps used by a program that is to be attached
> via xdpgeneric and fail if any of them are DEVMAP / DEVMAP_HASH with
> 8-bytes values.
>
> Block attach of BPF_XDP_DEVMAP programs to devices.
>
> Signed-off-by: David Ahern <dsahern@...nel.org>
> ---
> include/linux/bpf.h | 5 ++
> include/uapi/linux/bpf.h | 1 +
> kernel/bpf/devmap.c | 92 ++++++++++++++++++++++++++++++----
> net/core/dev.c | 18 +++++++
> tools/include/uapi/linux/bpf.h | 1 +
> 5 files changed, 108 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index efe8836b5c48..088751bc09aa 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1242,6 +1242,7 @@ int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_buff *xdp,
> struct net_device *dev_rx);
> int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,
> struct bpf_prog *xdp_prog);
> +bool dev_map_can_have_prog(struct bpf_map *map);
>
> struct bpf_cpu_map_entry *__cpu_map_lookup_elem(struct bpf_map *map, u32 key);
> void __cpu_map_flush(void);
> @@ -1355,6 +1356,10 @@ static inline struct net_device *__dev_map_hash_lookup_elem(struct bpf_map *map
> {
> return NULL;
> }
> +static inline bool dev_map_can_have_prog(struct bpf_map *map)
> +{
> + return false;
> +}
>
> static inline void __dev_flush(void)
> {
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 97e1fd19ff58..8c2c0d0c9a0e 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -224,6 +224,7 @@ enum bpf_attach_type {
> BPF_CGROUP_INET6_GETPEERNAME,
> BPF_CGROUP_INET4_GETSOCKNAME,
> BPF_CGROUP_INET6_GETSOCKNAME,
> + BPF_XDP_DEVMAP,
> __MAX_BPF_ATTACH_TYPE
> };
>
> diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
> index 95db6d8beebc..7658b3e2e7fc 100644
> --- a/kernel/bpf/devmap.c
> +++ b/kernel/bpf/devmap.c
> @@ -73,6 +73,7 @@ struct bpf_dtab_netdev {
> struct net_device *dev; /* must be first member, due to tracepoint */
> struct hlist_node index_hlist;
> struct bpf_dtab *dtab;
> + struct bpf_prog *xdp_prog;
> struct rcu_head rcu;
> unsigned int idx;
> struct dev_map_ext_val val;
> @@ -231,6 +232,8 @@ static void dev_map_free(struct bpf_map *map)
>
> hlist_for_each_entry_safe(dev, next, head, index_hlist) {
> hlist_del_rcu(&dev->index_hlist);
> + if (dev->xdp_prog)
> + bpf_prog_put(dev->xdp_prog);
> dev_put(dev->dev);
> kfree(dev);
> }
> @@ -245,6 +248,8 @@ static void dev_map_free(struct bpf_map *map)
> if (!dev)
> continue;
>
> + if (dev->xdp_prog)
> + bpf_prog_put(dev->xdp_prog);
> dev_put(dev->dev);
> kfree(dev);
> }
> @@ -331,6 +336,16 @@ static int dev_map_hash_get_next_key(struct bpf_map *map, void *key,
> return -ENOENT;
> }
>
> +bool dev_map_can_have_prog(struct bpf_map *map)
> +{
> + if ((map->map_type == BPF_MAP_TYPE_DEVMAP ||
> + map->map_type == BPF_MAP_TYPE_DEVMAP_HASH) &&
> + map->value_size != 4)
> + return true;
> +
> + return false;
> +}
> +
> static int bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)
> {
> struct net_device *dev = bq->dev;
> @@ -455,6 +470,35 @@ static inline int __xdp_enqueue(struct net_device *dev, struct xdp_buff *xdp,
> return bq_enqueue(dev, xdpf, dev_rx);
> }
>
> +static struct xdp_buff *dev_map_run_prog(struct net_device *dev,
> + struct xdp_buff *xdp,
> + struct bpf_prog *xdp_prog)
> +{
> + u32 act;
> +
> + act = bpf_prog_run_xdp(xdp_prog, xdp);
> + switch (act) {
> + case XDP_DROP:
> + fallthrough;
> + case XDP_PASS:
> + break;
> + default:
> + bpf_warn_invalid_xdp_action(act);
> + fallthrough;
> + case XDP_ABORTED:
> + trace_xdp_exception(dev, xdp_prog, act);
> + act = XDP_DROP;
> + break;
> + }
> +
> + if (act == XDP_DROP) {
> + xdp_return_buff(xdp);
> + xdp = NULL;
> + }
> +
> + return xdp;
> +}
> +
> int dev_xdp_enqueue(struct net_device *dev, struct xdp_buff *xdp,
> struct net_device *dev_rx)
> {
> @@ -466,6 +510,11 @@ int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_buff *xdp,
> {
> struct net_device *dev = dst->dev;
>
> + if (dst->xdp_prog) {
> + xdp = dev_map_run_prog(dev, xdp, dst->xdp_prog);
> + if (!xdp)
> + return 0;
> + }
> return __xdp_enqueue(dev, xdp, dev_rx);
> }
Did you give any special consideration to where the hook should be? I'm
asking because my immediate thought was that it should be on flush
(i.e., in bq_xmit_all()), but now that I see this I'm so sure anymore.
What were your thoughts around this?
-Toke
Powered by blists - more mailing lists