diff mbox

[RFC] ixgbe: use xdp_buff to simplify call path

Message ID 20170303210437.13969.48559.stgit@john-Precision-Tower-5810
State RFC
Headers show

Commit Message

John Fastabend March 3, 2017, 9:04 p.m. UTC
Alex, is this what you are thinking w.r.t. pushing the xdp_buff
through the ixgbe skb build routines. It seems to look OK but
only lightly tested for now.

I hvaen't decided if I want to push it into the first set of
patches or as a 4th patch.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   95 +++++++++++--------------
 1 file changed, 41 insertions(+), 54 deletions(-)

Comments

Alexander Duyck March 4, 2017, 12:29 a.m. UTC | #1
On Fri, Mar 3, 2017 at 1:04 PM, John Fastabend <john.fastabend@gmail.com> wrote:
> Alex, is this what you are thinking w.r.t. pushing the xdp_buff
> through the ixgbe skb build routines. It seems to look OK but
> only lightly tested for now.
>
> I hvaen't decided if I want to push it into the first set of
> patches or as a 4th patch.

Yeah, this is more or less what I was thinking.  Basically we just end
up pulling most of the rx_buffer_info structure onto the stack and
then process it there.  If we folded it into the other patches it
might actually make them a bit smaller since this patch is having to
go through and unto a number of things those patches are doing.

> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
> ---
>  drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   95 +++++++++++--------------
>  1 file changed, 41 insertions(+), 54 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> index 49f7eb6..db89588 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> @@ -2114,23 +2114,26 @@ static void ixgbe_put_rx_buffer(struct ixgbe_ring *rx_ring,
>
>  static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
>                                            struct ixgbe_rx_buffer *rx_buffer,
> -                                          union ixgbe_adv_rx_desc *rx_desc,
> -                                          unsigned int headroom,
> -                                          unsigned int size)
> +                                          struct xdp_buff *xdp,
> +                                          union ixgbe_adv_rx_desc *rx_desc)
>  {
> -       void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
> +       unsigned int size = xdp->data_end - xdp->data;
>  #if (PAGE_SIZE < 8192)
>         unsigned int truesize = ixgbe_rx_pg_size(rx_ring) / 2;
>  #else
>         unsigned int truesize = SKB_DATA_ALIGN(size);
>  #endif
> -       unsigned int off_page;
>         struct sk_buff *skb;
> +#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
> +       __u32 page_offset;
> +#else
> +       __u16 page_offset;
> +#endif

You can just use an unsigned int here.  No point in doing anything
fancy since it is just on the stack anyway.

>         /* prefetch first cache line of first page */
> -       prefetch(va);
> +       prefetch(xdp->data);
>  #if L1_CACHE_BYTES < 128
> -       prefetch(va + L1_CACHE_BYTES);
> +       prefetch(xdp->data + L1_CACHE_BYTES);
>  #endif
>
>         /* allocate a skb to store the frags */
> @@ -2138,14 +2141,12 @@ static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
>         if (unlikely(!skb))
>                 return NULL;
>
> -       off_page = IXGBE_SKB_PAD - headroom;
> -
>         if (size > IXGBE_RX_HDR_SIZE) {
>                 if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
>                         IXGBE_CB(skb)->dma = rx_buffer->dma;
>
> -               skb_add_rx_frag(skb, 0, rx_buffer->page,
> -                               rx_buffer->page_offset - off_page,
> +               page_offset = xdp->data - page_address(rx_buffer->page);
> +               skb_add_rx_frag(skb, 0, rx_buffer->page, page_offset,
>                                 size, truesize);

Actually it looks like this is the only place you use page_offset
anyway.  You could probably just drop the subtraction in the place of
the argument in the function call.

>  #if (PAGE_SIZE < 8192)
>                 rx_buffer->page_offset ^= truesize;
> @@ -2153,7 +2154,7 @@ static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
>                 rx_buffer->page_offset += truesize;
>  #endif
>         } else {
> -               memcpy(__skb_put(skb, size), va - off_page,
> +               memcpy(__skb_put(skb, size), xdp->data,
>                        ALIGN(size, sizeof(long)));
>                 rx_buffer->pagecnt_bias++;
>         }
> @@ -2163,11 +2164,9 @@ static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
>
>  static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring,
>                                        struct ixgbe_rx_buffer *rx_buffer,
> -                                      union ixgbe_adv_rx_desc *rx_desc,
> -                                      unsigned int headroom,
> -                                      unsigned int size)
> +                                      struct xdp_buff *xdp,
> +                                      union ixgbe_adv_rx_desc *rx_desc)
>  {
> -       void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
>  #if (PAGE_SIZE < 8192)
>         unsigned int truesize = ixgbe_rx_pg_size(rx_ring) / 2;
>  #else
> @@ -2177,19 +2176,19 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring,
>         struct sk_buff *skb;
>
>         /* prefetch first cache line of first page */
> -       prefetch(va);
> +       prefetch(xdp->data);
>  #if L1_CACHE_BYTES < 128
> -       prefetch(va + L1_CACHE_BYTES);
> +       prefetch(xdp->data + L1_CACHE_BYTES);
>  #endif
>
>         /* build an skb to around the page buffer */
> -       skb = build_skb(va - IXGBE_SKB_PAD, truesize);
> +       skb = build_skb(xdp->data_hard_start, truesize);
>         if (unlikely(!skb))
>                 return NULL;
>
>         /* update pointers within the skb to store the data */
> -       skb_reserve(skb, headroom);
> -       __skb_put(skb, size);
> +       skb_reserve(skb, xdp->data - xdp->data_hard_start);
> +       __skb_put(skb, xdp->data_end - xdp->data);
>
>         /* record DMA address if this is the start of a chain of buffers */
>         if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
> @@ -2214,14 +2213,10 @@ static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
>
>  static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
>                                      struct ixgbe_ring  *rx_ring,
> -                                    struct ixgbe_rx_buffer *rx_buffer,
> -                                    unsigned int *headroom,
> -                                    unsigned int *size)
> +                                    struct xdp_buff *xdp)
>  {
>         int result = IXGBE_XDP_PASS;
>         struct bpf_prog *xdp_prog;
> -       struct xdp_buff xdp;
> -       void *addr;
>         u32 act;
>
>         rcu_read_lock();
> @@ -2230,30 +2225,12 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
>         if (!xdp_prog)
>                 goto xdp_out;
>
> -       addr = page_address(rx_buffer->page) + rx_buffer->page_offset;
> -       xdp.data_hard_start = addr - *headroom;
> -       xdp.data = addr;
> -       xdp.data_end = addr + *size;
> -
> -       act = bpf_prog_run_xdp(xdp_prog, &xdp);
> +       act = bpf_prog_run_xdp(xdp_prog, xdp);
>         switch (act) {
>         case XDP_PASS:
> -               *headroom = xdp.data - xdp.data_hard_start;
> -               *size = xdp.data_end - xdp.data;
>                 return IXGBE_XDP_PASS;
>         case XDP_TX:
> -               result = ixgbe_xmit_xdp_ring(adapter, &xdp);
> -               if (result == IXGBE_XDP_TX) {
> -#if (PAGE_SIZE < 8192)
> -                       rx_buffer->page_offset ^= ixgbe_rx_pg_size(rx_ring) / 2;
> -#else
> -                       rx_buffer->page_offset += ring_uses_build_skb(rx_ring) ?
> -                                       SKB_DATA_ALIGN(IXGBE_SKB_PAD + size) :
> -                                       SKB_DATA_ALIGN(size);
> -#endif
> -               } else {
> -                       rx_buffer->pagecnt_bias++; /* give page back */
> -               }
> +               result = ixgbe_xmit_xdp_ring(adapter, xdp);
>                 break;
>         default:
>                 bpf_warn_invalid_xdp_action(act);
> @@ -2261,7 +2238,6 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
>                 trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
>                 /* fallthrough -- handle aborts by dropping packet */
>         case XDP_DROP:
> -               rx_buffer->pagecnt_bias++; /* give page back */
>                 result = IXGBE_XDP_CONSUMED;
>                 break;
>         }
> @@ -2296,10 +2272,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
>         u16 cleaned_count = ixgbe_desc_unused(rx_ring);
>
>         while (likely(total_rx_packets < budget)) {
> -               unsigned int headroom = ixgbe_rx_offset(rx_ring);
>                 union ixgbe_adv_rx_desc *rx_desc;
>                 struct ixgbe_rx_buffer *rx_buffer;
>                 struct sk_buff *skb;
> +               struct xdp_buff xdp;
>                 unsigned int size;
>
>                 /* return some buffers to hardware, one at a time is too slow */
> @@ -2320,20 +2296,31 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
>                 dma_rmb();
>
>                 rx_buffer = ixgbe_get_rx_buffer(rx_ring, rx_desc, &skb, size);
> +               xdp.data = page_address(rx_buffer->page) + rx_buffer->page_offset;
> +               xdp.data_hard_start = xdp.data - ixgbe_rx_offset(rx_ring);
> +               xdp.data_end = xdp.data + size;
>
> -               skb = ixgbe_run_xdp(adapter, rx_ring, rx_buffer,
> -                                   &headroom, &size);
> +               skb = ixgbe_run_xdp(adapter, rx_ring, &xdp);
>                 if (IS_ERR(skb)) { /* XDP consumed buffer */
> +                       if (PTR_ERR(skb) == -IXGBE_XDP_TX) {
> +#if (PAGE_SIZE < 8192)
> +                               rx_buffer->page_offset ^= ixgbe_rx_pg_size(rx_ring) / 2;
> +#else
> +                               rx_buffer->page_offset += ring_uses_build_skb(rx_ring) ?
> +                                               SKB_DATA_ALIGN(IXGBE_SKB_PAD + size) :
> +                                               SKB_DATA_ALIGN(size);
> +#endif
> +                       } else {
> +                               rx_buffer->pagecnt_bias++; /* give page back */
> +                       }
>                         total_rx_packets++;
>                         total_rx_bytes += size;
>                 } else if (skb) {
>                         ixgbe_add_rx_frag(rx_ring, rx_buffer, skb, size);
>                 } else if (ring_uses_build_skb(rx_ring)) {
> -                       skb = ixgbe_build_skb(rx_ring, rx_buffer,
> -                                             rx_desc, headroom, size);
> +                       skb = ixgbe_build_skb(rx_ring, rx_buffer, &xdp, rx_desc);
>                 } else {
> -                       skb = ixgbe_construct_skb(rx_ring, rx_buffer,
> -                                                 rx_desc, headroom, size);
> +                       skb = ixgbe_construct_skb(rx_ring, rx_buffer, &xdp, rx_desc);
>                 }
>
>                 /* exit if we failed to retrieve a buffer */
>
John Fastabend March 4, 2017, 1:28 a.m. UTC | #2
On 17-03-03 04:29 PM, Alexander Duyck wrote:
> On Fri, Mar 3, 2017 at 1:04 PM, John Fastabend <john.fastabend@gmail.com> wrote:
>> Alex, is this what you are thinking w.r.t. pushing the xdp_buff
>> through the ixgbe skb build routines. It seems to look OK but
>> only lightly tested for now.
>>
>> I hvaen't decided if I want to push it into the first set of
>> patches or as a 4th patch.
> 
> Yeah, this is more or less what I was thinking.  Basically we just end
> up pulling most of the rx_buffer_info structure onto the stack and
> then process it there.  If we folded it into the other patches it
> might actually make them a bit smaller since this patch is having to
> go through and unto a number of things those patches are doing.
> 


Yeah, I'll fold it in Monday and address the couple other comments.
Then I think we are probably good.
diff mbox

Patch

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 49f7eb6..db89588 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2114,23 +2114,26 @@  static void ixgbe_put_rx_buffer(struct ixgbe_ring *rx_ring,
 
 static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
 					   struct ixgbe_rx_buffer *rx_buffer,
-					   union ixgbe_adv_rx_desc *rx_desc,
-					   unsigned int headroom,
-					   unsigned int size)
+					   struct xdp_buff *xdp,
+					   union ixgbe_adv_rx_desc *rx_desc)
 {
-	void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+	unsigned int size = xdp->data_end - xdp->data;
 #if (PAGE_SIZE < 8192)
 	unsigned int truesize = ixgbe_rx_pg_size(rx_ring) / 2;
 #else
 	unsigned int truesize = SKB_DATA_ALIGN(size);
 #endif
-	unsigned int off_page;
 	struct sk_buff *skb;
+#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
+	__u32 page_offset;
+#else
+	__u16 page_offset;
+#endif
 
 	/* prefetch first cache line of first page */
-	prefetch(va);
+	prefetch(xdp->data);
 #if L1_CACHE_BYTES < 128
-	prefetch(va + L1_CACHE_BYTES);
+	prefetch(xdp->data + L1_CACHE_BYTES);
 #endif
 
 	/* allocate a skb to store the frags */
@@ -2138,14 +2141,12 @@  static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
 	if (unlikely(!skb))
 		return NULL;
 
-	off_page = IXGBE_SKB_PAD - headroom;
-
 	if (size > IXGBE_RX_HDR_SIZE) {
 		if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
 			IXGBE_CB(skb)->dma = rx_buffer->dma;
 
-		skb_add_rx_frag(skb, 0, rx_buffer->page,
-				rx_buffer->page_offset - off_page,
+		page_offset = xdp->data - page_address(rx_buffer->page);
+		skb_add_rx_frag(skb, 0, rx_buffer->page, page_offset,
 				size, truesize);
 #if (PAGE_SIZE < 8192)
 		rx_buffer->page_offset ^= truesize;
@@ -2153,7 +2154,7 @@  static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
 		rx_buffer->page_offset += truesize;
 #endif
 	} else {
-		memcpy(__skb_put(skb, size), va - off_page,
+		memcpy(__skb_put(skb, size), xdp->data,
 		       ALIGN(size, sizeof(long)));
 		rx_buffer->pagecnt_bias++;
 	}
@@ -2163,11 +2164,9 @@  static struct sk_buff *ixgbe_construct_skb(struct ixgbe_ring *rx_ring,
 
 static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring,
 				       struct ixgbe_rx_buffer *rx_buffer,
-				       union ixgbe_adv_rx_desc *rx_desc,
-				       unsigned int headroom,
-				       unsigned int size)
+				       struct xdp_buff *xdp,
+				       union ixgbe_adv_rx_desc *rx_desc)
 {
-	void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
 #if (PAGE_SIZE < 8192)
 	unsigned int truesize = ixgbe_rx_pg_size(rx_ring) / 2;
 #else
@@ -2177,19 +2176,19 @@  static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring,
 	struct sk_buff *skb;
 
 	/* prefetch first cache line of first page */
-	prefetch(va);
+	prefetch(xdp->data);
 #if L1_CACHE_BYTES < 128
-	prefetch(va + L1_CACHE_BYTES);
+	prefetch(xdp->data + L1_CACHE_BYTES);
 #endif
 
 	/* build an skb to around the page buffer */
-	skb = build_skb(va - IXGBE_SKB_PAD, truesize);
+	skb = build_skb(xdp->data_hard_start, truesize);
 	if (unlikely(!skb))
 		return NULL;
 
 	/* update pointers within the skb to store the data */
-	skb_reserve(skb, headroom);
-	__skb_put(skb, size);
+	skb_reserve(skb, xdp->data - xdp->data_hard_start);
+	__skb_put(skb, xdp->data_end - xdp->data);
 
 	/* record DMA address if this is the start of a chain of buffers */
 	if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
@@ -2214,14 +2213,10 @@  static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
 
 static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
 				     struct ixgbe_ring  *rx_ring,
-				     struct ixgbe_rx_buffer *rx_buffer,
-				     unsigned int *headroom,
-				     unsigned int *size)
+				     struct xdp_buff *xdp)
 {
 	int result = IXGBE_XDP_PASS;
 	struct bpf_prog *xdp_prog;
-	struct xdp_buff xdp;
-	void *addr;
 	u32 act;
 
 	rcu_read_lock();
@@ -2230,30 +2225,12 @@  static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
 	if (!xdp_prog)
 		goto xdp_out;
 
-	addr = page_address(rx_buffer->page) + rx_buffer->page_offset;
-	xdp.data_hard_start = addr - *headroom;
-	xdp.data = addr;
-	xdp.data_end = addr + *size;
-
-	act = bpf_prog_run_xdp(xdp_prog, &xdp);
+	act = bpf_prog_run_xdp(xdp_prog, xdp);
 	switch (act) {
 	case XDP_PASS:
-		*headroom = xdp.data - xdp.data_hard_start;
-		*size = xdp.data_end - xdp.data;
 		return IXGBE_XDP_PASS;
 	case XDP_TX:
-		result = ixgbe_xmit_xdp_ring(adapter, &xdp);
-		if (result == IXGBE_XDP_TX) {
-#if (PAGE_SIZE < 8192)
-			rx_buffer->page_offset ^= ixgbe_rx_pg_size(rx_ring) / 2;
-#else
-			rx_buffer->page_offset += ring_uses_build_skb(rx_ring) ?
-					SKB_DATA_ALIGN(IXGBE_SKB_PAD + size) :
-					SKB_DATA_ALIGN(size);
-#endif
-		} else {
-			rx_buffer->pagecnt_bias++; /* give page back */
-		}
+		result = ixgbe_xmit_xdp_ring(adapter, xdp);
 		break;
 	default:
 		bpf_warn_invalid_xdp_action(act);
@@ -2261,7 +2238,6 @@  static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
 		trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
 		/* fallthrough -- handle aborts by dropping packet */
 	case XDP_DROP:
-		rx_buffer->pagecnt_bias++; /* give page back */
 		result = IXGBE_XDP_CONSUMED;
 		break;
 	}
@@ -2296,10 +2272,10 @@  static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
 
 	while (likely(total_rx_packets < budget)) {
-		unsigned int headroom = ixgbe_rx_offset(rx_ring);
 		union ixgbe_adv_rx_desc *rx_desc;
 		struct ixgbe_rx_buffer *rx_buffer;
 		struct sk_buff *skb;
+		struct xdp_buff xdp;
 		unsigned int size;
 
 		/* return some buffers to hardware, one at a time is too slow */
@@ -2320,20 +2296,31 @@  static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 		dma_rmb();
 
 		rx_buffer = ixgbe_get_rx_buffer(rx_ring, rx_desc, &skb, size);
+		xdp.data = page_address(rx_buffer->page) + rx_buffer->page_offset;
+		xdp.data_hard_start = xdp.data - ixgbe_rx_offset(rx_ring);
+		xdp.data_end = xdp.data + size;
 
-		skb = ixgbe_run_xdp(adapter, rx_ring, rx_buffer,
-				    &headroom, &size);
+		skb = ixgbe_run_xdp(adapter, rx_ring, &xdp);
 		if (IS_ERR(skb)) { /* XDP consumed buffer */
+			if (PTR_ERR(skb) == -IXGBE_XDP_TX) {
+#if (PAGE_SIZE < 8192)
+				rx_buffer->page_offset ^= ixgbe_rx_pg_size(rx_ring) / 2;
+#else
+				rx_buffer->page_offset += ring_uses_build_skb(rx_ring) ?
+						SKB_DATA_ALIGN(IXGBE_SKB_PAD + size) :
+						SKB_DATA_ALIGN(size);
+#endif
+			} else {
+				rx_buffer->pagecnt_bias++; /* give page back */
+			}
 			total_rx_packets++;
 			total_rx_bytes += size;
 		} else if (skb) {
 			ixgbe_add_rx_frag(rx_ring, rx_buffer, skb, size);
 		} else if (ring_uses_build_skb(rx_ring)) {
-			skb = ixgbe_build_skb(rx_ring, rx_buffer,
-					      rx_desc, headroom, size);
+			skb = ixgbe_build_skb(rx_ring, rx_buffer, &xdp, rx_desc);
 		} else {
-			skb = ixgbe_construct_skb(rx_ring, rx_buffer,
-						  rx_desc, headroom, size);
+			skb = ixgbe_construct_skb(rx_ring, rx_buffer, &xdp, rx_desc);
 		}
 
 		/* exit if we failed to retrieve a buffer */