Changing API ndo_xdp_xmit to take a struct xdp_frame instead of struct
xdp_buff.  This brings xdp_return_frame and ndp_xdp_xmit in sync.

This builds towards changing the API further to become a bulk API,
because xdp_buff is not a queue-able object while xdp_frame is.

V4: Adjust for commit 59655a5b6c83 ("tuntap: XDP_TX can use native XDP")

Signed-off-by: Jesper Dangaard Brouer <bro...@redhat.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   21 +++++++++++----------
 drivers/net/tun.c                             |   19 ++++++++++++-------
 drivers/net/virtio_net.c                      |   24 ++++++++++++++----------
 include/linux/netdevice.h                     |    4 ++--
 net/core/filter.c                             |   17 +++++++++++++++--
 5 files changed, 54 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index e6e9b28ecfba..f78096ed4c86 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2252,7 +2252,7 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring 
*rx_ring,
 #define IXGBE_XDP_TX 2
 
 static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
-                              struct xdp_buff *xdp);
+                              struct xdp_frame *xdpf);
 
 static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
                                     struct ixgbe_ring *rx_ring,
@@ -2260,6 +2260,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter 
*adapter,
 {
        int err, result = IXGBE_XDP_PASS;
        struct bpf_prog *xdp_prog;
+       struct xdp_frame *xdpf;
        u32 act;
 
        rcu_read_lock();
@@ -2273,7 +2274,12 @@ static struct sk_buff *ixgbe_run_xdp(struct 
ixgbe_adapter *adapter,
        case XDP_PASS:
                break;
        case XDP_TX:
-               result = ixgbe_xmit_xdp_ring(adapter, xdp);
+               xdpf = convert_to_xdp_frame(xdp);
+               if (unlikely(!xdpf)) {
+                       result = IXGBE_XDP_CONSUMED;
+                       break;
+               }
+               result = ixgbe_xmit_xdp_ring(adapter, xdpf);
                break;
        case XDP_REDIRECT:
                err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog);
@@ -8329,20 +8335,15 @@ static u16 ixgbe_select_queue(struct net_device *dev, 
struct sk_buff *skb,
 }
 
 static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
-                              struct xdp_buff *xdp)
+                              struct xdp_frame *xdpf)
 {
        struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()];
        struct ixgbe_tx_buffer *tx_buffer;
        union ixgbe_adv_tx_desc *tx_desc;
-       struct xdp_frame *xdpf;
        u32 len, cmd_type;
        dma_addr_t dma;
        u16 i;
 
-       xdpf = convert_to_xdp_frame(xdp);
-       if (unlikely(!xdpf))
-               return -EOVERFLOW;
-
        len = xdpf->len;
 
        if (unlikely(!ixgbe_desc_unused(ring)))
@@ -9995,7 +9996,7 @@ static int ixgbe_xdp(struct net_device *dev, struct 
netdev_bpf *xdp)
        }
 }
 
-static int ixgbe_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
+static int ixgbe_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
        struct ixgbe_ring *ring;
@@ -10011,7 +10012,7 @@ static int ixgbe_xdp_xmit(struct net_device *dev, 
struct xdp_buff *xdp)
        if (unlikely(!ring))
                return -ENXIO;
 
-       err = ixgbe_xmit_xdp_ring(adapter, xdp);
+       err = ixgbe_xmit_xdp_ring(adapter, xdpf);
        if (err != IXGBE_XDP_TX)
                return -ENOSPC;
 
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a7e42ae1b220..da0402ebc5ce 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1293,18 +1293,13 @@ static const struct net_device_ops tun_netdev_ops = {
        .ndo_get_stats64        = tun_net_get_stats64,
 };
 
-static int tun_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
+static int tun_xdp_xmit(struct net_device *dev, struct xdp_frame *frame)
 {
        struct tun_struct *tun = netdev_priv(dev);
-       struct xdp_frame *frame;
        struct tun_file *tfile;
        u32 numqueues;
        int ret = 0;
 
-       frame = convert_to_xdp_frame(xdp);
-       if (unlikely(!frame))
-               return -EOVERFLOW;
-
        rcu_read_lock();
 
        numqueues = READ_ONCE(tun->numqueues);
@@ -1328,6 +1323,16 @@ static int tun_xdp_xmit(struct net_device *dev, struct 
xdp_buff *xdp)
        return ret;
 }
 
+static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp)
+{
+       struct xdp_frame *frame = convert_to_xdp_frame(xdp);
+
+       if (unlikely(!frame))
+               return -EOVERFLOW;
+
+       return tun_xdp_xmit(dev, frame);
+}
+
 static void tun_xdp_flush(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
@@ -1675,7 +1680,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct 
*tun,
                case XDP_TX:
                        get_page(alloc_frag->page);
                        alloc_frag->offset += buflen;
-                       if (tun_xdp_xmit(tun->dev, &xdp))
+                       if (tun_xdp_tx(tun->dev, &xdp))
                                goto err_redirect;
                        tun_xdp_flush(tun->dev);
                        rcu_read_unlock();
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 479a80339fad..906fcd9ff49b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -416,10 +416,10 @@ static void virtnet_xdp_flush(struct net_device *dev)
 }
 
 static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
-                              struct xdp_buff *xdp)
+                              struct xdp_frame *xdpf)
 {
        struct virtio_net_hdr_mrg_rxbuf *hdr;
-       struct xdp_frame *xdpf, *xdpf_sent;
+       struct xdp_frame *xdpf_sent;
        struct send_queue *sq;
        unsigned int len;
        unsigned int qp;
@@ -432,10 +432,6 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
        while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL)
                xdp_return_frame(xdpf_sent);
 
-       xdpf = convert_to_xdp_frame(xdp);
-       if (unlikely(!xdpf))
-               return -EOVERFLOW;
-
        /* virtqueue want to use data area in-front of packet */
        if (unlikely(xdpf->metasize > 0))
                return -EOPNOTSUPP;
@@ -460,7 +456,7 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
        return true;
 }
 
-static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
+static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf)
 {
        struct virtnet_info *vi = netdev_priv(dev);
        struct receive_queue *rq = vi->rq;
@@ -474,7 +470,7 @@ static int virtnet_xdp_xmit(struct net_device *dev, struct 
xdp_buff *xdp)
        if (!xdp_prog)
                return -ENXIO;
 
-       sent = __virtnet_xdp_xmit(vi, xdp);
+       sent = __virtnet_xdp_xmit(vi, xdpf);
        if (!sent)
                return -ENOSPC;
        return 0;
@@ -575,6 +571,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
        xdp_prog = rcu_dereference(rq->xdp_prog);
        if (xdp_prog) {
                struct virtio_net_hdr_mrg_rxbuf *hdr = buf + header_offset;
+               struct xdp_frame *xdpf;
                struct xdp_buff xdp;
                void *orig_data;
                u32 act;
@@ -617,7 +614,10 @@ static struct sk_buff *receive_small(struct net_device 
*dev,
                        delta = orig_data - xdp.data;
                        break;
                case XDP_TX:
-                       sent = __virtnet_xdp_xmit(vi, &xdp);
+                       xdpf = convert_to_xdp_frame(&xdp);
+                       if (unlikely(!xdpf))
+                               goto err_xdp;
+                       sent = __virtnet_xdp_xmit(vi, xdpf);
                        if (unlikely(!sent)) {
                                trace_xdp_exception(vi->dev, xdp_prog, act);
                                goto err_xdp;
@@ -709,6 +709,7 @@ static struct sk_buff *receive_mergeable(struct net_device 
*dev,
        rcu_read_lock();
        xdp_prog = rcu_dereference(rq->xdp_prog);
        if (xdp_prog) {
+               struct xdp_frame *xdpf;
                struct page *xdp_page;
                struct xdp_buff xdp;
                void *data;
@@ -773,7 +774,10 @@ static struct sk_buff *receive_mergeable(struct net_device 
*dev,
                        }
                        break;
                case XDP_TX:
-                       sent = __virtnet_xdp_xmit(vi, &xdp);
+                       xdpf = convert_to_xdp_frame(&xdp);
+                       if (unlikely(!xdpf))
+                               goto err_xdp;
+                       sent = __virtnet_xdp_xmit(vi, xdpf);
                        if (unlikely(!sent)) {
                                trace_xdp_exception(vi->dev, xdp_prog, act);
                                if (unlikely(xdp_page != page))
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 913b1cc882cf..62d984ac6c7c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1164,7 +1164,7 @@ struct dev_ifalias {
  *     This function is used to set or query state related to XDP on the
  *     netdevice and manage BPF offload. See definition of
  *     enum bpf_netdev_command for details.
- * int (*ndo_xdp_xmit)(struct net_device *dev, struct xdp_buff *xdp);
+ * int (*ndo_xdp_xmit)(struct net_device *dev, struct xdp_frame *xdp);
  *     This function is used to submit a XDP packet for transmit on a
  *     netdevice.
  * void (*ndo_xdp_flush)(struct net_device *dev);
@@ -1355,7 +1355,7 @@ struct net_device_ops {
        int                     (*ndo_bpf)(struct net_device *dev,
                                           struct netdev_bpf *bpf);
        int                     (*ndo_xdp_xmit)(struct net_device *dev,
-                                               struct xdp_buff *xdp);
+                                               struct xdp_frame *xdp);
        void                    (*ndo_xdp_flush)(struct net_device *dev);
 };
 
diff --git a/net/core/filter.c b/net/core/filter.c
index c86f03fd9ea5..189ae8e4dda3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2724,13 +2724,18 @@ static int __bpf_tx_xdp(struct net_device *dev,
                        struct xdp_buff *xdp,
                        u32 index)
 {
+       struct xdp_frame *xdpf;
        int err;
 
        if (!dev->netdev_ops->ndo_xdp_xmit) {
                return -EOPNOTSUPP;
        }
 
-       err = dev->netdev_ops->ndo_xdp_xmit(dev, xdp);
+       xdpf = convert_to_xdp_frame(xdp);
+       if (unlikely(!xdpf))
+               return -EOVERFLOW;
+
+       err = dev->netdev_ops->ndo_xdp_xmit(dev, xdpf);
        if (err)
                return err;
        dev->netdev_ops->ndo_xdp_flush(dev);
@@ -2746,11 +2751,19 @@ static int __bpf_tx_xdp_map(struct net_device *dev_rx, 
void *fwd,
 
        if (map->map_type == BPF_MAP_TYPE_DEVMAP) {
                struct net_device *dev = fwd;
+               struct xdp_frame *xdpf;
 
                if (!dev->netdev_ops->ndo_xdp_xmit)
                        return -EOPNOTSUPP;
 
-               err = dev->netdev_ops->ndo_xdp_xmit(dev, xdp);
+               xdpf = convert_to_xdp_frame(xdp);
+               if (unlikely(!xdpf))
+                       return -EOVERFLOW;
+
+               /* TODO: move to inside map code instead, for bulk support
+                * err = dev_map_enqueue(dev, xdp);
+                */
+               err = dev->netdev_ops->ndo_xdp_xmit(dev, xdpf);
                if (err)
                        return err;
                __dev_map_insert_ctx(map, index);

Reply via email to