bpf: devmap: check XDP features in __xdp_enqueue routine
authorLorenzo Bianconi <lorenzo@kernel.org>
Wed, 1 Feb 2023 10:24:22 +0000 (11:24 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 3 Feb 2023 04:48:24 +0000 (20:48 -0800)
Check if the destination device implements ndo_xdp_xmit callback relying
on NETDEV_XDP_ACT_NDO_XMIT flags. Moreover, check if the destination device
supports XDP non-linear frame in __xdp_enqueue and is_valid_dst routines.
This patch allows to perform XDP_REDIRECT on non-linear XDP buffers.

Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Co-developed-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/26a94c33520c0bfba021b3fbb2cb8c1e69bf53b8.1675245258.git.lorenzo@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/devmap.c
net/core/filter.c

index d01e4c55b376a3a96a96c74b1ed92435d7f286ea..2675fefc6cb626e4d74a955c007664592567977b 100644 (file)
@@ -474,7 +474,11 @@ static inline int __xdp_enqueue(struct net_device *dev, struct xdp_frame *xdpf,
 {
        int err;
 
-       if (!dev->netdev_ops->ndo_xdp_xmit)
+       if (!(dev->xdp_features & NETDEV_XDP_ACT_NDO_XMIT))
+               return -EOPNOTSUPP;
+
+       if (unlikely(!(dev->xdp_features & NETDEV_XDP_ACT_NDO_XMIT_SG) &&
+                    xdp_frame_has_frags(xdpf)))
                return -EOPNOTSUPP;
 
        err = xdp_ok_fwd_dev(dev, xdp_get_frame_len(xdpf));
@@ -532,8 +536,14 @@ int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_frame *xdpf,
 
 static bool is_valid_dst(struct bpf_dtab_netdev *obj, struct xdp_frame *xdpf)
 {
-       if (!obj ||
-           !obj->dev->netdev_ops->ndo_xdp_xmit)
+       if (!obj)
+               return false;
+
+       if (!(obj->dev->xdp_features & NETDEV_XDP_ACT_NDO_XMIT))
+               return false;
+
+       if (unlikely(!(obj->dev->xdp_features & NETDEV_XDP_ACT_NDO_XMIT_SG) &&
+                    xdp_frame_has_frags(xdpf)))
                return false;
 
        if (xdp_ok_fwd_dev(obj->dev, xdp_get_frame_len(xdpf)))
index 0039cf16713e96211a57a039798a070171647a66..2ce06a72a5bae7011e665438c942b4c77e0fb1d3 100644 (file)
@@ -4318,16 +4318,13 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
        struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
        enum bpf_map_type map_type = ri->map_type;
 
-       /* XDP_REDIRECT is not fully supported yet for xdp frags since
-        * not all XDP capable drivers can map non-linear xdp_frame in
-        * ndo_xdp_xmit.
-        */
-       if (unlikely(xdp_buff_has_frags(xdp) &&
-                    map_type != BPF_MAP_TYPE_CPUMAP))
-               return -EOPNOTSUPP;
+       if (map_type == BPF_MAP_TYPE_XSKMAP) {
+               /* XDP_REDIRECT is not supported AF_XDP yet. */
+               if (unlikely(xdp_buff_has_frags(xdp)))
+                       return -EOPNOTSUPP;
 
-       if (map_type == BPF_MAP_TYPE_XSKMAP)
                return __xdp_do_redirect_xsk(ri, dev, xdp, xdp_prog);
+       }
 
        return __xdp_do_redirect_frame(ri, dev, xdp_convert_buff_to_frame(xdp),
                                       xdp_prog);