From: jan@openbsd.org Subject: Re: vmx(4): TCP/UDP checksum offloading To: Jonathan Matthew Cc: tech@openbsd.org Date: Thu, 15 Feb 2024 10:46:18 +0100 On Thu, Feb 15, 2024 at 01:12:18PM +1000, Jonathan Matthew wrote: > On Fri, Feb 09, 2024 at 10:04:37PM +0100, jan@openbsd.org wrote: > > Hi, > > > > This diff implements the TCP/UDP checksum offloading for vmx(4). > > I tested it on ESXi 8.0 with OpenBSD and Linux guests. > > > > ok? > > This looks better than the diff I was working on. > ok jmatthew@ Thanks for your review. I adjust the diff with bluhm's ext.iphlen feature from yesterday and remove the include of ip6.h. ok? Thanks, Jan Index: dev/pci/if_vmx.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_vmx.c,v diff -u -p -r1.80 if_vmx.c --- dev/pci/if_vmx.c 9 Feb 2024 15:22:41 -0000 1.80 +++ dev/pci/if_vmx.c 15 Feb 2024 09:36:49 -0000 @@ -400,10 +400,12 @@ vmxnet3_attach(struct device *parent, st ifp->if_watchdog = vmxnet3_watchdog; ifp->if_hardmtu = VMXNET3_MAX_MTU; ifp->if_capabilities = IFCAP_VLAN_MTU; -#if 0 - if (sc->sc_ds->upt_features & UPT1_F_CSUM) + + if (sc->sc_ds->upt_features & UPT1_F_CSUM) { ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; -#endif + ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6; + } + #if NVLAN > 0 if (sc->sc_ds->upt_features & UPT1_F_VLAN) ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; @@ -1398,6 +1400,55 @@ vmx_load_mbuf(bus_dma_tag_t dmat, bus_dm } void +vmxnet3_tx_offload(struct vmxnet3_txdesc *sop, struct mbuf *m) +{ + struct ether_extracted ext; + uint32_t offset = 0; + uint32_t hdrlen; + + /* + * VLAN Offload + */ + +#if NVLAN > 0 + if (ISSET(m->m_flags, M_VLANTAG)) { + sop->tx_word3 |= htole32(VMXNET3_TX_VTAG_MODE); + sop->tx_word3 |= htole32((m->m_pkthdr.ether_vtag & + VMXNET3_TX_VLANTAG_M) << VMXNET3_TX_VLANTAG_S); + } +#endif + + /* + * Checksum Offload + */ + + if (!ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT) && + !ISSET(m->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) + return; + + ether_extract_headers(m, &ext); + + hdrlen = sizeof(*ext.eh); + if (ext.evh) + hdrlen = sizeof(*ext.evh); + + if (ext.ip4 || ext.ip6) + hdrlen += ext.iphlen; + + if (ext.tcp) + offset = hdrlen + offsetof(struct tcphdr, th_sum); + else if (ext.udp) + offset = hdrlen + offsetof(struct udphdr, uh_sum); + + hdrlen &= VMXNET3_TX_HLEN_M; + offset &= VMXNET3_TX_OP_M; + + sop->tx_word3 |= htole32(VMXNET3_OM_CSUM << VMXNET3_TX_OM_S); + sop->tx_word3 |= htole32(hdrlen << VMXNET3_TX_HLEN_S); + sop->tx_word2 |= htole32(offset << VMXNET3_TX_OP_S); +} + +void vmxnet3_start(struct ifqueue *ifq) { struct ifnet *ifp = ifq->ifq_if; @@ -1469,13 +1520,7 @@ vmxnet3_start(struct ifqueue *ifq) } txd->tx_word3 = htole32(VMXNET3_TX_EOP | VMXNET3_TX_COMPREQ); -#if NVLAN > 0 - if (ISSET(m->m_flags, M_VLANTAG)) { - sop->tx_word3 |= htole32(VMXNET3_TX_VTAG_MODE); - sop->tx_word3 |= htole32((m->m_pkthdr.ether_vtag & - VMXNET3_TX_VLANTAG_M) << VMXNET3_TX_VLANTAG_S); - } -#endif + vmxnet3_tx_offload(sop, m); ring->prod = prod; /* Change the ownership by flipping the "generation" bit */