Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44fa2dbd authored by Jesper Dangaard Brouer's avatar Jesper Dangaard Brouer Committed by David S. Miller
Browse files

xdp: transition into using xdp_frame for ndo_xdp_xmit



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 59655a5b ("tuntap: XDP_TX can use native XDP")
V7: Adjust for commit d9314c47 ("i40e: add support for XDP_REDIRECT")

Signed-off-by: default avatarJesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 03993094
Loading
Loading
Loading
Loading
+17 −13
Original line number Diff line number Diff line
@@ -2203,9 +2203,20 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
#define I40E_XDP_CONSUMED 1
#define I40E_XDP_TX 2

static int i40e_xmit_xdp_ring(struct xdp_buff *xdp,
static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf,
			      struct i40e_ring *xdp_ring);

static int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp,
				 struct i40e_ring *xdp_ring)
{
	struct xdp_frame *xdpf = convert_to_xdp_frame(xdp);

	if (unlikely(!xdpf))
		return I40E_XDP_CONSUMED;

	return i40e_xmit_xdp_ring(xdpf, xdp_ring);
}

/**
 * i40e_run_xdp - run an XDP program
 * @rx_ring: Rx ring being processed
@@ -2233,7 +2244,7 @@ static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring,
		break;
	case XDP_TX:
		xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
		result = i40e_xmit_xdp_ring(xdp, xdp_ring);
		result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
		break;
	case XDP_REDIRECT:
		err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
@@ -3480,21 +3491,14 @@ static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 * @xdp: data to transmit
 * @xdp_ring: XDP Tx ring
 **/
static int i40e_xmit_xdp_ring(struct xdp_buff *xdp,
static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf,
			      struct i40e_ring *xdp_ring)
{
	u16 i = xdp_ring->next_to_use;
	struct i40e_tx_buffer *tx_bi;
	struct i40e_tx_desc *tx_desc;
	struct xdp_frame *xdpf;
	u32 size = xdpf->len;
	dma_addr_t dma;
	u32 size;

	xdpf = convert_to_xdp_frame(xdp);
	if (unlikely(!xdpf))
		return I40E_XDP_CONSUMED;

	size = xdpf->len;

	if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) {
		xdp_ring->tx_stats.tx_busy++;
@@ -3684,7 +3688,7 @@ netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 *
 * Returns Zero if sent, else an error code
 **/
int i40e_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
int i40e_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf)
{
	struct i40e_netdev_priv *np = netdev_priv(dev);
	unsigned int queue_index = smp_processor_id();
@@ -3697,7 +3701,7 @@ int i40e_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
	if (!i40e_enabled_xdp_vsi(vsi) || queue_index >= vsi->num_queue_pairs)
		return -ENXIO;

	err = i40e_xmit_xdp_ring(xdp, vsi->xdp_rings[queue_index]);
	err = i40e_xmit_xdp_ring(xdpf, vsi->xdp_rings[queue_index]);
	if (err != I40E_XDP_TX)
		return -ENOSPC;

+1 −1
Original line number Diff line number Diff line
@@ -511,7 +511,7 @@ u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);
void i40e_detect_recover_hung(struct i40e_vsi *vsi);
int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
bool __i40e_chk_linearize(struct sk_buff *skb);
int i40e_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp);
int i40e_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf);
void i40e_xdp_flush(struct net_device *dev);

/**
+13 −11
Original line number Diff line number Diff line
@@ -2262,7 +2262,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,
@@ -2270,6 +2270,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();
@@ -2278,12 +2279,19 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
	if (!xdp_prog)
		goto xdp_out;

	prefetchw(xdp->data_hard_start); /* xdp_frame write */

	act = bpf_prog_run_xdp(xdp_prog, xdp);
	switch (act) {
	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);
@@ -2386,7 +2394,6 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
			xdp.data_hard_start = xdp.data -
					      ixgbe_rx_offset(rx_ring);
			xdp.data_end = xdp.data + size;
			prefetchw(xdp.data_hard_start); /* xdp_frame write */

			skb = ixgbe_run_xdp(adapter, rx_ring, &xdp);
		}
@@ -8344,20 +8351,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)))
@@ -10010,7 +10012,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;
@@ -10026,7 +10028,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;

+12 −7
Original line number Diff line number Diff line
@@ -1301,18 +1301,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);
@@ -1336,6 +1331,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);
@@ -1683,7 +1688,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();
+14 −10
Original line number Diff line number Diff line
@@ -416,10 +416,10 @@ static void virtnet_xdp_flush(struct net_device *dev)
}

static int __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 int __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;
@@ -459,7 +455,7 @@ static int __virtnet_xdp_xmit(struct virtnet_info *vi,
	return 0;
}

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;
@@ -472,7 +468,7 @@ static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
	if (!xdp_prog)
		return -ENXIO;

	return __virtnet_xdp_xmit(vi, xdp);
	return __virtnet_xdp_xmit(vi, xdpf);
}

static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
@@ -569,6 +565,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;
@@ -611,7 +608,10 @@ static struct sk_buff *receive_small(struct net_device *dev,
			delta = orig_data - xdp.data;
			break;
		case XDP_TX:
			err = __virtnet_xdp_xmit(vi, &xdp);
			xdpf = convert_to_xdp_frame(&xdp);
			if (unlikely(!xdpf))
				goto err_xdp;
			err = __virtnet_xdp_xmit(vi, xdpf);
			if (unlikely(err)) {
				trace_xdp_exception(vi->dev, xdp_prog, act);
				goto err_xdp;
@@ -702,6 +702,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;
@@ -766,7 +767,10 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
			}
			break;
		case XDP_TX:
			err = __virtnet_xdp_xmit(vi, &xdp);
			xdpf = convert_to_xdp_frame(&xdp);
			if (unlikely(!xdpf))
				goto err_xdp;
			err = __virtnet_xdp_xmit(vi, xdpf);
			if (unlikely(err)) {
				trace_xdp_exception(vi->dev, xdp_prog, act);
				if (unlikely(xdp_page != page))
Loading