@@ -3133,6 +3133,7 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
u32 __skb_get_poff(const struct sk_buff *skb);
+u32 eth_frame_headlen(void *data, unsigned int len);
/**
* skb_head_is_locked - Determine if the skb->head is locked down
@@ -343,6 +343,30 @@ u32 __skb_get_poff(const struct sk_buff *skb)
return poff;
}
+
+/* Helper to find length of headers in an ethernet frame.
+ * This can help drivers to pull exact amount of bytes into
+ * skb->head to get optimal GRO performance.
+ * TODO: Could also return rxhash while we do a complete flow dissection.
+ */
+u32 eth_frame_headlen(void *data, unsigned int len)
+{
+ const struct ethhdr *eth = data;
+ struct sk_buff skb;
+
+ if (unlikely(len < ETH_HLEN))
+ return len;
+
+ skb.protocol = eth->h_proto;
+ skb.head = data + ETH_HLEN;
+ skb.data = skb.head;
+ skb_reset_network_header(&skb);
+ skb.len = len - ETH_HLEN;
+ skb.data_len = 0;
+ return __skb_get_poff(&skb) + ETH_HLEN;
+}
+EXPORT_SYMBOL(eth_frame_headlen);
+
static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
{
#ifdef CONFIG_XPS