David Ahern <[email protected]> writes:

> From: David Ahern <[email protected]>
>
> Add BPF_XDP_DEVMAP attach type for use with programs associated with a
> DEVMAP entry.
>
> Allow DEVMAPs to associate a program with a device entry by adding
> a bpf_prog_fd to 'struct devmap_val'. Values read show the program
> id, so the fd and id are a union.
>
> 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
>  > 4-byte values.
>
> Block attach of BPF_XDP_DEVMAP programs to devices.
>
> Signed-off-by: David Ahern <[email protected]>
> ---
>  include/linux/bpf.h            |  5 +++
>  include/uapi/linux/bpf.h       |  5 +++
>  kernel/bpf/devmap.c            | 79 +++++++++++++++++++++++++++++++++-
>  net/core/dev.c                 | 18 ++++++++
>  tools/include/uapi/linux/bpf.h |  5 +++
>  5 files changed, 110 insertions(+), 2 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 d27302ecaa9c..2d9927b7a922 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
>  };
>  
> @@ -3628,6 +3629,10 @@ struct xdp_md {
>  /* DEVMAP values */
>  struct devmap_val {
>       __u32 ifindex;   /* device index */
> +     union {
> +             int   bpf_prog_fd;  /* prog fd on map write */
> +             __u32 bpf_prog_id;  /* prog id on map read */
> +     };
>  };
>  
>  enum sk_action {
> diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
> index 069a50113e26..a628585a31e1 100644
> --- a/kernel/bpf/devmap.c
> +++ b/kernel/bpf/devmap.c
> @@ -64,6 +64,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 devmap_val val;
> @@ -219,6 +220,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);
>                       }
> @@ -233,6 +236,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);
>               }
> @@ -319,6 +324,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)

nit (since you've gotten rid of the magic sizes everywhere else) how about:

map->value_size != sizeof_field(struct devmap_val, ifindex)

Reply via email to