Download raw body.
vport/veb(4): use/fix checksum offload
Hi,
This diff enables checksum offload in vport(4) and fixes checksum
offload in veb(4) in some corner cases. If we get packages with
M_TCP_CSUM_OUT from an interface.
When we bridge two vio(4) interfaces via veb(4), we will lost the
VIRTIO_NET_HDR_F_NEEDS_CSUM flags, which is encodes in our mbuf via
M_TCP_CSUM_OUT flag.
In the case of bridging vio(4) with an physical interface (e.g. em(4),
we also have to M_TCP_CSUM_OUT flag. So, the hardware is able to
calculate the correct checksum. Or, when we bridge vio(4) with an
interface unable to calculate we have to do this here, before sending
the packet to the interface.
ok?
bye,
Jan
Index: net/if_veb.c
===================================================================
RCS file: /cvs/src/sys/net/if_veb.c,v
diff -u -p -r1.38 if_veb.c
--- net/if_veb.c 27 Jun 2025 09:25:57 -0000 1.38
+++ net/if_veb.c 27 Jun 2025 17:33:10 -0000
@@ -948,6 +948,9 @@ veb_ipsec_out(struct ifnet *ifp0, struct
static struct mbuf *
veb_offload(struct ifnet *ifp, struct ifnet *ifp0, struct mbuf *m)
{
+ struct ether_extracted ext;
+ int csum = 0;
+
#if NVLAN > 0
if (ISSET(m->m_flags, M_VLANTAG) &&
!ISSET(ifp0->if_capabilities, IFCAP_VLAN_HWTAGGING)) {
@@ -956,14 +959,56 @@ veb_offload(struct ifnet *ifp, struct if
* support, inject one in software.
*/
m = vlan_inject(m, ETHERTYPE_VLAN, m->m_pkthdr.ether_vtag);
- if (m == NULL) {
- counters_inc(ifp->if_counters, ifc_ierrors);
- return NULL;
- }
+ if (m == NULL)
+ goto drop;
}
#endif
+ if (ISSET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT) &&
+ !ISSET(ifp0->if_capabilities, IFCAP_CSUM_IPv4))
+ csum = 1;
+
+ if (ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT) &&
+ (!ISSET(ifp0->if_capabilities, IFCAP_CSUM_TCPv4) ||
+ !ISSET(ifp0->if_capabilities, IFCAP_CSUM_TCPv6)))
+ csum = 1;
+
+ if (ISSET(m->m_pkthdr.csum_flags, M_UDP_CSUM_OUT) &&
+ (!ISSET(ifp0->if_capabilities, IFCAP_CSUM_UDPv4) ||
+ !ISSET(ifp0->if_capabilities, IFCAP_CSUM_UDPv6)))
+ csum = 1;
+
+ if (csum) {
+ int adjlen;
+
+ ether_extract_headers(m, &ext);
+ if (ext.eh)
+ adjlen = sizeof *ext.eh;
+ else if (ext.evh)
+ adjlen = sizeof *ext.evh;
+ else
+ goto drop;
+
+ m_adj(m, adjlen);
+
+ if (ext.ip4) {
+ in_hdr_cksum_out(m, ifp0);
+ in_proto_cksum_out(m, ifp0);
+#ifdef INET6
+ } else if (ext.ip6) {
+ in6_proto_cksum_out(m, ifp0);
+#endif
+ }
+ m = m_prepend(m, adjlen, 0);
+ if (m == NULL)
+ goto drop;
+ }
+
return m;
+
+ drop:
+ counters_inc(ifp->if_counters, ifc_ierrors);
+ return NULL;
}
static void
@@ -2380,7 +2425,15 @@ vport_clone_create(struct if_clone *ifc,
ifp->if_qstart = vport_start;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
- ifp->if_capabilities = IFCAP_VLAN_HWTAGGING;
+
+ ifp->if_capabilities = 0;
+#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;
+
ether_fakeaddr(ifp);
if_counters_alloc(ifp);
vport/veb(4): use/fix checksum offload