Date: Tue, 10 Oct 2017 06:12:07 +0000 (UTC) From: Sepherosa Ziehau <sephe@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r324480 - stable/11/sys/dev/hyperv/netvsc Message-ID: <201710100612.v9A6C7ox012288@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: sephe Date: Tue Oct 10 06:12:07 2017 New Revision: 324480 URL: https://svnweb.freebsd.org/changeset/base/324480 Log: MFC 324049,324077 324049 hyperv/hn: Fix UDP checksum offload issue in Azure. UDP checksum offload does not work in Azure if following conditions are met: - sizeof(IP hdr + UDP hdr + payload) > 1420. - IP_DF is not set in IP hdr Use software checksum for UDP datagrams falling into this category. Add two tunables to disable UDP/IPv4 and UDP/IPv6 checksum offload, in case something unexpected happened. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D12429 324077 hyperv/hn: Unbreak i386 building. Reported by: cy Sponsored by: Microsoft Modified: stable/11/sys/dev/hyperv/netvsc/if_hn.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/hyperv/netvsc/if_hn.c ============================================================================== --- stable/11/sys/dev/hyperv/netvsc/if_hn.c Tue Oct 10 06:03:23 2017 (r324479) +++ stable/11/sys/dev/hyperv/netvsc/if_hn.c Tue Oct 10 06:12:07 2017 (r324480) @@ -61,7 +61,9 @@ __FBSDID("$FreeBSD$"); #include "opt_rss.h" #include <sys/param.h> +#include <sys/systm.h> #include <sys/bus.h> +#include <sys/counter.h> #include <sys/kernel.h> #include <sys/limits.h> #include <sys/malloc.h> @@ -76,7 +78,6 @@ __FBSDID("$FreeBSD$"); #include <sys/sockio.h> #include <sys/sx.h> #include <sys/sysctl.h> -#include <sys/systm.h> #include <sys/taskqueue.h> #include <sys/buf_ring.h> #include <sys/eventhandler.h> @@ -458,6 +459,35 @@ SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDT "Trust ip packet verification on host side, " "when csum info is missing (global setting)"); +/* + * Offload UDP/IPv4 checksum. + */ +static int hn_enable_udp4cs = 1; +SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp4cs, CTLFLAG_RDTUN, + &hn_enable_udp4cs, 0, "Offload UDP/IPv4 checksum"); + +/* + * Offload UDP/IPv6 checksum. + */ +static int hn_enable_udp6cs = 1; +SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp6cs, CTLFLAG_RDTUN, + &hn_enable_udp6cs, 0, "Offload UDP/IPv6 checksum"); + +/* Stats. */ +static counter_u64_t hn_udpcs_fixup; +SYSCTL_COUNTER_U64(_hw_hn, OID_AUTO, udpcs_fixup, CTLFLAG_RW, + &hn_udpcs_fixup, "# of UDP checksum fixup"); + +/* + * See hn_set_hlen(). + * + * This value is for Azure. For Hyper-V, set this above + * 65536 to disable UDP datagram checksum fixup. + */ +static int hn_udpcs_fixup_mtu = 1420; +SYSCTL_INT(_hw_hn, OID_AUTO, udpcs_fixup_mtu, CTLFLAG_RWTUN, + &hn_udpcs_fixup_mtu, 0, "UDP checksum fixup MTU threshold"); + /* Limit TSO burst size */ static int hn_tso_maxlen = IP_MAXPACKET; SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, @@ -797,6 +827,27 @@ hn_set_hlen(struct mbuf *m_head) ip = mtodo(m_head, ehlen); iphlen = ip->ip_hl << 2; m_head->m_pkthdr.l3hlen = iphlen; + + /* + * UDP checksum offload does not work in Azure, if the + * following conditions meet: + * - sizeof(IP hdr + UDP hdr + payload) > 1420. + * - IP_DF is not set in the IP hdr. + * + * Fallback to software checksum for these UDP datagrams. + */ + if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) && + m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen && + (ntohs(ip->ip_off) & IP_DF) == 0) { + uint16_t off = ehlen + iphlen; + + counter_u64_add(hn_udpcs_fixup, 1); + PULLUP_HDR(m_head, off + sizeof(struct udphdr)); + *(uint16_t *)(m_head->m_data + off + + m_head->m_pkthdr.csum_data) = in_cksum_skip( + m_head, m_head->m_pkthdr.len, off); + m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP; + } } #endif #if defined(INET6) && defined(INET) @@ -5475,11 +5526,11 @@ hn_fixup_tx_data(struct hn_softc *sc) csum_assist |= CSUM_IP; if (sc->hn_caps & HN_CAP_TCP4CS) csum_assist |= CSUM_IP_TCP; - if (sc->hn_caps & HN_CAP_UDP4CS) + if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs) csum_assist |= CSUM_IP_UDP; if (sc->hn_caps & HN_CAP_TCP6CS) csum_assist |= CSUM_IP6_TCP; - if (sc->hn_caps & HN_CAP_UDP6CS) + if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs) csum_assist |= CSUM_IP6_UDP; for (i = 0; i < sc->hn_tx_ring_cnt; ++i) sc->hn_tx_ring[i].hn_csum_assist = csum_assist; @@ -7332,6 +7383,8 @@ hn_sysinit(void *arg __unused) { int i; + hn_udpcs_fixup = counter_u64_alloc(M_WAITOK); + #ifdef HN_IFSTART_SUPPORT /* * Don't use ifnet.if_start if transparent VF mode is requested; @@ -7411,5 +7464,7 @@ hn_sysuninit(void *arg __unused) if (hn_vfmap != NULL) free(hn_vfmap, M_DEVBUF); rm_destroy(&hn_vfmap_lock); + + counter_u64_free(hn_udpcs_fixup); } SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201710100612.v9A6C7ox012288>