git: b836c229aa5a - main - ip6: leave room for link headers in UDP

From: Andrew Gallatin <gallatin_at_FreeBSD.org>
Date: Tue, 15 Apr 2025 23:45:36 UTC
The branch main has been updated by gallatin:

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

commit b836c229aa5ac345114f5986b6034ad3ed760da1
Author:     Andrew Gallatin <gallatin@FreeBSD.org>
AuthorDate: 2025-04-15 23:37:06 +0000
Commit:     Andrew Gallatin <gallatin@FreeBSD.org>
CommitDate: 2025-04-15 23:44:56 +0000

    ip6: leave room for link headers in UDP
    
    UDP over IPv6 was not leaving space for link headers,
    resulting in the ethernet header being placed in its own mbuf
    at the front of the mbuf chain sent down to the NIC driver.
    This is inefficient, in terms of allocating 2x as many
    header mbufs as needed, and its also confusing for drivers
    which may expect to find ether/ip/l4 headers together in the same
    mbuf.
    
    Reviewed by: glebius, rrs, tuexen
    Sponsored by: Netflix
    Differential Revision: https://reviews.freebsd.org/D49840
    
    This is a port of e6ccd7093618, which was done by Robert
    Watson in 2004 for IP4
---
 sys/netinet6/udp6_usrreq.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index c44510e3b65f..c8f91fff2b76 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -860,14 +860,18 @@ udp6_send(struct socket *so, int flags_arg, struct mbuf *m,
 	hlen = sizeof(struct ip6_hdr);
 
 	/*
-	 * Calculate data length and get a mbuf
-	 * for UDP and IP6 headers.
+	 * Calculate data length and get a mbuf for UDP, IP6, and possible
+	 * link-layer headers.  Immediate slide the data pointer back forward
+	 * since we won't use that space at this layer.
 	 */
-	M_PREPEND(m, hlen + sizeof(struct udphdr), M_NOWAIT);
+	M_PREPEND(m, hlen + sizeof(struct udphdr) + max_linkhdr, M_NOWAIT);
 	if (m == NULL) {
 		error = ENOBUFS;
 		goto release;
 	}
+	m->m_data += max_linkhdr;
+	m->m_len -= max_linkhdr;
+	m->m_pkthdr.len -= max_linkhdr;
 
 	/*
 	 * Stuff checksum and output datagram.