diff mbox series

[net-next,V7,07/16] virtio_net: convert to use generic xdp_frame and xdp_return_frame API

Message ID 152234289201.17048.17760447330628182817.stgit@firesoul
State Superseded, archived
Delegated to: David Miller
Headers show
Series XDP redirect memory return API | expand

Commit Message

Jesper Dangaard Brouer March 29, 2018, 5:01 p.m. UTC
The virtio_net driver assumes XDP frames are always released based on
page refcnt (via put_page).  Thus, is only queues the XDP data pointer
address and uses virt_to_head_page() to retrieve struct page.

Use the XDP return API to get away from such assumptions. Instead
queue an xdp_frame, which allow us to use the xdp_return_frame API,
when releasing the frame.

Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
---
 drivers/net/virtio_net.c |   31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

Comments

kernel test robot March 30, 2018, 6:22 p.m. UTC | #1
Hi Jesper,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Jesper-Dangaard-Brouer/XDP-redirect-memory-return-API/20180330-203122
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

>> drivers/net/virtio_net.c:451:26: sparse: incorrect type in assignment (different base types) @@    expected restricted __virtio16 [usertype] hdr_len @@    got unsirestricted __virtio16 [usertype] hdr_len @@
   drivers/net/virtio_net.c:451:26:    expected restricted __virtio16 [usertype] hdr_len
   drivers/net/virtio_net.c:451:26:    got unsigned short [unsigned] [usertype] len
   drivers/net/virtio_net.c:2140:27: sparse: incorrect type in assignment (different base types) @@    expected unsigned long long [unsigned] [usertype] ctrl_offloads @@    got unsigned] [usertype] ctrl_offloads @@
   drivers/net/virtio_net.c:2140:27:    expected unsigned long long [unsigned] [usertype] ctrl_offloads
   drivers/net/virtio_net.c:2140:27:    got restricted __virtio64

vim +451 drivers/net/virtio_net.c

   417	
   418	static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
   419				       struct xdp_buff *xdp)
   420	{
   421		struct virtio_net_hdr_mrg_rxbuf *hdr;
   422		struct xdp_frame *xdpf, *xdpf_sent;
   423		struct send_queue *sq;
   424		unsigned int len;
   425		unsigned int qp;
   426		int err;
   427	
   428		qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id();
   429		sq = &vi->sq[qp];
   430	
   431		/* Free up any pending old buffers before queueing new ones. */
   432		while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL)
   433			xdp_return_frame(xdpf_sent->data, &xdpf_sent->mem);
   434	
   435		xdpf = convert_to_xdp_frame(xdp);
   436		if (unlikely(!xdpf))
   437			return -EOVERFLOW;
   438	
   439		/* virtqueue want to use data area in-front of packet */
   440		if (unlikely(xdpf->metasize > 0))
   441			return -EOPNOTSUPP;
   442	
   443		if (unlikely(xdpf->headroom < vi->hdr_len))
   444			return -EOVERFLOW;
   445	
   446		/* Make room for virtqueue hdr (also change xdpf->headroom?) */
   447		xdpf->data -= vi->hdr_len;
   448		/* Zero header and leave csum up to XDP layers */
   449		hdr = xdpf->data;
   450		memset(hdr, 0, vi->hdr_len);
 > 451		hdr->hdr.hdr_len = xdpf->len; /* Q: is this needed? */
   452		xdpf->len   += vi->hdr_len;
   453	
   454		sg_init_one(sq->sg, xdpf->data, xdpf->len);
   455	
   456		err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdpf, GFP_ATOMIC);
   457		if (unlikely(err))
   458			return false; /* Caller handle free/refcnt */
   459	
   460		return true;
   461	}
   462	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Jesper Dangaard Brouer March 31, 2018, 8:56 a.m. UTC | #2
On Sat, 31 Mar 2018 02:22:35 +0800 kbuild test robot <lkp@intel.com> wrote:

> reproduce:
>         # apt-get install sparse
>         make ARCH=x86_64 allmodconfig
>         make C=1 CF=-D__CHECK_ENDIAN__

[...]
>    417	
>    418	static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
>    419				       struct xdp_buff *xdp)
>    420	{
[...]
>    445	
>    446		/* Make room for virtqueue hdr (also change xdpf->headroom?) */
>    447		xdpf->data -= vi->hdr_len;
>    448		/* Zero header and leave csum up to XDP layers */
>    449		hdr = xdpf->data;
>    450		memset(hdr, 0, vi->hdr_len);
>  > 451		hdr->hdr.hdr_len = xdpf->len; /* Q: is this needed? */ 

I'll just remove this line, as Jason previously told me that it is not
strictly necessary (so lets avoid playing with endianness here).

>    452		xdpf->len   += vi->hdr_len;
>    453
diff mbox series

Patch

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 7b187ec7411e..53acfac8390c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -419,30 +419,41 @@  static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
 			       struct xdp_buff *xdp)
 {
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
-	unsigned int len;
+	struct xdp_frame *xdpf, *xdpf_sent;
 	struct send_queue *sq;
+	unsigned int len;
 	unsigned int qp;
-	void *xdp_sent;
 	int err;
 
 	qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id();
 	sq = &vi->sq[qp];
 
 	/* Free up any pending old buffers before queueing new ones. */
-	while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) {
-		struct page *sent_page = virt_to_head_page(xdp_sent);
+	while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL)
+		xdp_return_frame(xdpf_sent->data, &xdpf_sent->mem);
 
-		put_page(sent_page);
-	}
+	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;
+
+	if (unlikely(xdpf->headroom < vi->hdr_len))
+		return -EOVERFLOW;
 
-	xdp->data -= vi->hdr_len;
+	/* Make room for virtqueue hdr (also change xdpf->headroom?) */
+	xdpf->data -= vi->hdr_len;
 	/* Zero header and leave csum up to XDP layers */
-	hdr = xdp->data;
+	hdr = xdpf->data;
 	memset(hdr, 0, vi->hdr_len);
+	hdr->hdr.hdr_len = xdpf->len; /* Q: is this needed? */
+	xdpf->len   += vi->hdr_len;
 
-	sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data);
+	sg_init_one(sq->sg, xdpf->data, xdpf->len);
 
-	err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdp->data, GFP_ATOMIC);
+	err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdpf, GFP_ATOMIC);
 	if (unlikely(err))
 		return false; /* Caller handle free/refcnt */