Download raw body.
vport/veb(4): use/fix checksum offload
On Fri, Aug 01, 2025 at 03:02:37PM +0200, Jan Klemkow wrote:
> On Sun, Jun 29, 2025 at 07:57:15PM +0200, Alexander Bluhm wrote:
> > On Fri, Jun 27, 2025 at 08:06:42PM +0200, Jan Klemkow wrote:
> > > 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.
> > >
> > Crashes in my veb(4) test with vio(4)
>
> Fix it and improved error handling.
bluhm pointed out several bugs. So, here is a fixes version:
ok?
Thanks,
Jan
Index: net/if_veb.c
===================================================================
RCS file: /cvs/src/sys/net/if_veb.c,v
diff -u -p -r1.41 if_veb.c
--- net/if_veb.c 7 Jul 2025 02:28:50 -0000 1.41
+++ net/if_veb.c 1 Aug 2025 15:33:03 -0000
@@ -940,6 +940,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)) {
@@ -948,13 +951,63 @@ 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)
+ return (NULL);
}
#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 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)
+ return NULL;
+ }
+
+ /* hide ethernet header */
+ m->m_data += ethlen;
+ m->m_len -= ethlen;
+ m->m_pkthdr.len -= ethlen;
+
+ 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
+ }
+
+ /* show ethernet header again */
+ m->m_data -= ethlen;
+ m->m_len += ethlen;
+ m->m_pkthdr.len += ethlen;
+ }
+
return m;
}
@@ -1027,8 +1080,10 @@ veb_broadcast(struct veb_softc *sc, stru
if (veb_rule_filter(tp, VEB_RULE_LIST_OUT, m0, src, dst))
continue;
- if ((m0 = veb_offload(ifp, ifp0, m0)) == NULL)
- goto done;
+ if ((m0 = veb_offload(ifp, ifp0, m0)) == NULL) {
+ counters_inc(ifp->if_counters, ifc_ierrors);
+ return;
+ }
m = m_dup_pkt(m0, max_linkhdr + ETHER_ALIGN, M_NOWAIT);
if (m == NULL) {
@@ -1082,8 +1137,10 @@ veb_transmit(struct veb_softc *sc, struc
counters_pkt(ifp->if_counters, ifc_opackets, ifc_obytes,
m->m_pkthdr.len);
- if ((m = veb_offload(ifp, ifp0, m)) == NULL)
- goto drop;
+ if ((m = veb_offload(ifp, ifp0, m)) == NULL) {
+ counters_inc(ifp->if_counters, ifc_ierrors);
+ return (NULL);
+ }
(*tp->p_enqueue)(ifp0, m); /* XXX count error */
@@ -2372,7 +2429,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