Index | Thread | Search

From:
David Gwynne <david@gwynne.id.au>
Subject:
Re: vport/veb(4): use/fix checksum offload
To:
Jan Klemkow <jan@openbsd.org>
Cc:
OpenBSD Tech <tech@openbsd.org>
Date:
Sun, 29 Jun 2025 21:48:34 +1000

Download raw body.

Thread

> On 28 Jun 2025, at 04:06, Jan Klemkow <jan@openbsd.org> wrote:
> 
> 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?

sure, 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);
>