Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
bridge(4): use checksum offloading
To:
tech@openbsd.org
Date:
Tue, 16 Sep 2025 14:45:42 +0200

Download raw body.

Thread
Hi,

Similar to veb(4) this diff adds checksum offloading to bridge(4) and
vether(4).  This diff is the last requirement for my vmd+offloading
diff[1].  Otherwise, vmd+bridge would break.

ok?

bye,
Jan

[1]: https://marc.info/?t=174779131200001&r=1&w=2

Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
diff -u -p -r1.377 if_bridge.c
--- net/if_bridge.c	16 Sep 2025 09:07:00 -0000	1.377
+++ net/if_bridge.c	16 Sep 2025 11:36:09 -0000
@@ -799,8 +799,11 @@ bridge_stop(struct bridge_softc *sc)
 }
 
 struct mbuf *
-bridge_offload(struct ifnet *ifp, struct mbuf *m)
+bridge_offload(struct ifnet *brifp, struct ifnet *ifp, struct mbuf *m)
 {
+	struct ether_extracted ext;
+	int csum = 0;
+
 #if NVLAN > 0
 	/*
 	 * If the underlying interface has no VLAN hardware tagging support,
@@ -813,7 +816,63 @@ bridge_offload(struct ifnet *ifp, struct
 			return NULL;
 	}
 #endif
+
+	if (ISSET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT) &&
+	    !ISSET(ifp->if_capabilities, IFCAP_CSUM_IPv4))
+		csum = 1;
+
+	if (ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT) &&
+	    (!ISSET(ifp->if_capabilities, IFCAP_CSUM_TCPv4) ||
+	     !ISSET(ifp->if_capabilities, IFCAP_CSUM_TCPv6)))
+		csum = 1;
+
+	if (ISSET(m->m_pkthdr.csum_flags, M_UDP_CSUM_OUT) &&
+	    (!ISSET(ifp->if_capabilities, IFCAP_CSUM_UDPv4) ||
+	     !ISSET(ifp->if_capabilities, IFCAP_CSUM_UDPv6)))
+		csum = 1;
+
+	if (csum) {
+		int ethlen;
+		int hlen;
+
+		ether_extract_headers(m, &ext);
+
+		ethlen = sizeof *ext.eh;
+		if (ext.evh)
+			ethlen = sizeof *ext.evh;
+
+		hlen = m->m_pkthdr.len - ext.paylen;
+
+		if (m->m_len < hlen) {
+			m = m_pullup(m, hlen);
+			if (m == NULL)
+				goto err;
+		}
+
+		/* hide ethernet header */
+		m->m_data += ethlen;
+		m->m_len -= ethlen;
+		m->m_pkthdr.len -= ethlen;
+
+		if (ext.ip4) {
+			in_hdr_cksum_out(m, ifp);
+			in_proto_cksum_out(m, ifp);
+#ifdef INET6
+		} else if (ext.ip6) {
+			in6_proto_cksum_out(m, ifp);
+#endif
+		}
+
+		/* show ethernet header again */
+		m->m_data -= ethlen;
+		m->m_len += ethlen;
+		m->m_pkthdr.len += ethlen;
+	}
+
 	return m;
+err:
+	counters_inc(brifp->if_counters, ifc_ierrors);
+	return NULL;
 }
 
 /*
@@ -1921,7 +1980,7 @@ bridge_ifenqueue(struct ifnet *brifp, st
 {
 	int error, len;
 
-	if ((m = bridge_offload(ifp, m)) == NULL) {
+	if ((m = bridge_offload(brifp, ifp, m)) == NULL) {
 		error = ENOBUFS;
 		goto err;
 	}
Index: net/if_vether.c
===================================================================
RCS file: /cvs/src/sys/net/if_vether.c,v
diff -u -p -r1.38 if_vether.c
--- net/if_vether.c	16 Sep 2025 09:07:00 -0000	1.38
+++ net/if_vether.c	16 Sep 2025 11:38:14 -0000
@@ -89,6 +89,9 @@ vether_clone_create(struct if_clone *ifc
 #if NVLAN > 0
 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
 #endif
+	ifp->if_capabilities |= IFCAP_CSUM_IPv4;
+	ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
+	ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
 	ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
 
 	ifmedia_init(&sc->sc_media, 0, vether_media_change,