Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net...
[linux-2.6-microblaze.git] / drivers / net / virtio_net.c
index 87838cb..cbba9d2 100644 (file)
@@ -1005,6 +1005,24 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                         * xdp.data_meta were adjusted
                         */
                        len = xdp.data_end - xdp.data + vi->hdr_len + metasize;
+
+                       /* recalculate headroom if xdp.data or xdp_data_meta
+                        * were adjusted, note that offset should always point
+                        * to the start of the reserved bytes for virtio_net
+                        * header which are followed by xdp.data, that means
+                        * that offset is equal to the headroom (when buf is
+                        * starting at the beginning of the page, otherwise
+                        * there is a base offset inside the page) but it's used
+                        * with a different starting point (buf start) than
+                        * xdp.data (buf start + vnet hdr size). If xdp.data or
+                        * data_meta were adjusted by the xdp prog then the
+                        * headroom size has changed and so has the offset, we
+                        * can use data_hard_start, which points at buf start +
+                        * vnet hdr size, to calculate the new headroom and use
+                        * it later to compute buf start in page_to_skb()
+                        */
+                       headroom = xdp.data - xdp.data_hard_start - metasize;
+
                        /* We can only create skb based on xdp_page. */
                        if (unlikely(xdp_page != page)) {
                                rcu_read_unlock();
@@ -1012,7 +1030,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                                head_skb = page_to_skb(vi, rq, xdp_page, offset,
                                                       len, PAGE_SIZE, false,
                                                       metasize,
-                                                      VIRTIO_XDP_HEADROOM);
+                                                      headroom);
                                return head_skb;
                        }
                        break;