Author: sephe Date: Tue Oct 10 03:40:38 2017 New Revision: 324468 URL: https://svnweb.freebsd.org/changeset/base/324468
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/10/sys/dev/hyperv/netvsc/if_hn.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/hyperv/netvsc/if_hn.c ============================================================================== --- stable/10/sys/dev/hyperv/netvsc/if_hn.c Tue Oct 10 03:35:24 2017 (r324467) +++ stable/10/sys/dev/hyperv/netvsc/if_hn.c Tue Oct 10 03:40:38 2017 (r324468) @@ -60,7 +60,9 @@ __FBSDID("$FreeBSD$"); #include "opt_hn.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> @@ -451,6 +452,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, @@ -788,6 +818,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) @@ -5463,11 +5514,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; @@ -7289,6 +7340,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; @@ -7368,5 +7421,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); _______________________________________________ svn-src-stable-10@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10 To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"