bpf, i40e: add meta data support

Add support for XDP meta data when using build skb variant of
the i40e driver. Implementation is analogous to the existing
ixgbe and ixgbevf support for meta data from 366a88fe2f ("bpf,
ixgbe: add meta data support") and be8333322e ("ixgbevf: Add
support for meta data"). With the build skb variant we get
192 bytes of extra headroom which can be used for encaps or
meta data.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Tested-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Daniel Borkmann 2018-05-28 11:07:20 +02:00 committed by Jeff Kirsher
parent e9c721837d
commit cc5b114dcf
1 changed files with 31 additions and 8 deletions

View File

@ -2032,6 +2032,21 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
#if L1_CACHE_BYTES < 128 #if L1_CACHE_BYTES < 128
prefetch(xdp->data + L1_CACHE_BYTES); prefetch(xdp->data + L1_CACHE_BYTES);
#endif #endif
/* Note, we get here by enabling legacy-rx via:
*
* ethtool --set-priv-flags <dev> legacy-rx on
*
* In this mode, we currently get 0 extra XDP headroom as
* opposed to having legacy-rx off, where we process XDP
* packets going to stack via i40e_build_skb(). The latter
* provides us currently with 192 bytes of headroom.
*
* For i40e_construct_skb() mode it means that the
* xdp->data_meta will always point to xdp->data, since
* the helper cannot expand the head. Should this ever
* change in future for legacy-rx mode on, then lets also
* add xdp->data_meta handling here.
*/
/* allocate a skb to store the frags */ /* allocate a skb to store the frags */
skb = __napi_alloc_skb(&rx_ring->q_vector->napi, skb = __napi_alloc_skb(&rx_ring->q_vector->napi,
@ -2083,19 +2098,25 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
struct i40e_rx_buffer *rx_buffer, struct i40e_rx_buffer *rx_buffer,
struct xdp_buff *xdp) struct xdp_buff *xdp)
{ {
unsigned int size = xdp->data_end - xdp->data; unsigned int metasize = xdp->data - xdp->data_meta;
#if (PAGE_SIZE < 8192) #if (PAGE_SIZE < 8192)
unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
#else #else
unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
SKB_DATA_ALIGN(I40E_SKB_PAD + size); SKB_DATA_ALIGN(I40E_SKB_PAD +
(xdp->data_end -
xdp->data_hard_start));
#endif #endif
struct sk_buff *skb; struct sk_buff *skb;
/* prefetch first cache line of first page */ /* Prefetch first cache line of first page. If xdp->data_meta
prefetch(xdp->data); * is unused, this points exactly as xdp->data, otherwise we
* likely have a consumer accessing first few bytes of meta
* data, and then actual data.
*/
prefetch(xdp->data_meta);
#if L1_CACHE_BYTES < 128 #if L1_CACHE_BYTES < 128
prefetch(xdp->data + L1_CACHE_BYTES); prefetch(xdp->data_meta + L1_CACHE_BYTES);
#endif #endif
/* build an skb around the page buffer */ /* build an skb around the page buffer */
skb = build_skb(xdp->data_hard_start, truesize); skb = build_skb(xdp->data_hard_start, truesize);
@ -2103,8 +2124,10 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
return NULL; return NULL;
/* update pointers within the skb to store the data */ /* update pointers within the skb to store the data */
skb_reserve(skb, I40E_SKB_PAD); skb_reserve(skb, I40E_SKB_PAD + (xdp->data - xdp->data_hard_start));
__skb_put(skb, size); __skb_put(skb, xdp->data_end - xdp->data);
if (metasize)
skb_metadata_set(skb, metasize);
/* buffer is used by skb, update page_offset */ /* buffer is used by skb, update page_offset */
#if (PAGE_SIZE < 8192) #if (PAGE_SIZE < 8192)
@ -2341,7 +2364,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
if (!skb) { if (!skb) {
xdp.data = page_address(rx_buffer->page) + xdp.data = page_address(rx_buffer->page) +
rx_buffer->page_offset; rx_buffer->page_offset;
xdp_set_data_meta_invalid(&xdp); xdp.data_meta = xdp.data;
xdp.data_hard_start = xdp.data - xdp.data_hard_start = xdp.data -
i40e_rx_offset(rx_ring); i40e_rx_offset(rx_ring);
xdp.data_end = xdp.data + size; xdp.data_end = xdp.data + size;