bpf, i40e: add meta data support
authorDaniel Borkmann <daniel@iogearbox.net>
Mon, 28 May 2018 09:07:20 +0000 (11:07 +0200)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Mon, 4 Jun 2018 17:23:58 +0000 (10:23 -0700)
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 366a88fe2f40 ("bpf,
ixgbe: add meta data support") and be8333322eff ("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>
drivers/net/ethernet/intel/i40e/i40e_txrx.c

index 9b698c5acd0502cad23b3172ebdae458c2a3e028..105a26f447c074372062f7d56389e42b5db6a8a8 100644 (file)
@@ -2032,6 +2032,21 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
 #if L1_CACHE_BYTES < 128
        prefetch(xdp->data + L1_CACHE_BYTES);
 #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 */
        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 xdp_buff *xdp)
 {
-       unsigned int size = xdp->data_end - xdp->data;
+       unsigned int metasize = xdp->data - xdp->data_meta;
 #if (PAGE_SIZE < 8192)
        unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
 #else
        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
        struct sk_buff *skb;
 
-       /* prefetch first cache line of first page */
-       prefetch(xdp->data);
+       /* Prefetch first cache line of first page. If xdp->data_meta
+        * 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
-       prefetch(xdp->data + L1_CACHE_BYTES);
+       prefetch(xdp->data_meta + L1_CACHE_BYTES);
 #endif
        /* build an skb around the page buffer */
        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;
 
        /* update pointers within the skb to store the data */
-       skb_reserve(skb, I40E_SKB_PAD);
-       __skb_put(skb, size);
+       skb_reserve(skb, I40E_SKB_PAD + (xdp->data - xdp->data_hard_start));
+       __skb_put(skb, xdp->data_end - xdp->data);
+       if (metasize)
+               skb_metadata_set(skb, metasize);
 
        /* buffer is used by skb, update page_offset */
 #if (PAGE_SIZE < 8192)
@@ -2341,7 +2364,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                if (!skb) {
                        xdp.data = page_address(rx_buffer->page) +
                                   rx_buffer->page_offset;
-                       xdp_set_data_meta_invalid(&xdp);
+                       xdp.data_meta = xdp.data;
                        xdp.data_hard_start = xdp.data -
                                              i40e_rx_offset(rx_ring);
                        xdp.data_end = xdp.data + size;