git: d9e0e4262761 - main - vtnet: Account for the padding when selecting allocation size

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 05 Feb 2024 05:45:33 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=d9e0e42627613b56abf0f8fa1ad601e5690d775c

commit d9e0e42627613b56abf0f8fa1ad601e5690d775c
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2024-02-05 05:43:39 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-02-05 05:43:39 +0000

    vtnet: Account for the padding when selecting allocation size
    
    While we account for the padding in the length of the mbuf we use, we do
    not account for it when we 'guess' the size of the mbuf to allocate
    based in the MTU of the device. This leads to a situation where we might
    fail if the mtu is close to a bucket size (say 2018) such that the added
    padding would push us over the edge for a full-sized packet. mtu of 2018
    is super rare (2016 and 2020 would both work), but fix it none-the-less.
    It's a shame we can't just set VTNET_RX_HEADER_PAD to 2 in this case. The 4
    seems hard-coded somewhere I've not found documented (I think it's in the
    protocol given the comments about VIRTIO_F_ANY_LAYOUT).
    
    Sponsored by:           Netflix
    Reviewed by:            bz
    Differential Revision:  https://reviews.freebsd.org/D43656
---
 sys/dev/virtio/network/if_vtnet.c    | 9 +++++++++
 sys/dev/virtio/network/if_vtnetvar.h | 8 +++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index 11c640bccdeb..3d85fee122c7 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -1223,6 +1223,15 @@ vtnet_rx_cluster_size(struct vtnet_softc *sc, int mtu)
 	} else
 		framesz = sizeof(struct vtnet_rx_header);
 	framesz += sizeof(struct ether_vlan_header) + mtu;
+#ifndef __NO_STRICT_ALIGNMENT
+	/*
+	 * Account for the offsetting we'll do elsewhere so we allocate the
+	 * right size for the mtu.
+	 */
+	if (sc->vtnet_hdr_size % 4 == 0) {
+		framesz += ETHER_ALIGN;
+	}
+#endif
 
 	if (framesz <= MCLBYTES)
 		return (MCLBYTES);
diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/network/if_vtnetvar.h
index 6c2e6e90107a..d690ad3bf63c 100644
--- a/sys/dev/virtio/network/if_vtnetvar.h
+++ b/sys/dev/virtio/network/if_vtnetvar.h
@@ -232,7 +232,13 @@ vtnet_software_lro(struct vtnet_softc *sc)
  */
 #define VTNET_VLAN_FILTER_NWORDS	(4096 / 32)
 
-/* We depend on these being the same size (and same layout). */
+/*
+ * We depend on all of the hdr structures being even, and matching the standard
+ * length. As well, we depend on two being identally sized (with the same
+ * layout).
+ */
+CTASSERT(sizeof(struct virtio_net_hdr_v1) == 12);
+CTASSERT(sizeof(struct virtio_net_hdr) == 10);
 CTASSERT(sizeof(struct virtio_net_hdr_mrg_rxbuf) ==
     sizeof(struct virtio_net_hdr_v1));