aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/hyperv/netvsc
diff options
context:
space:
mode:
authorSepherosa Ziehau <sephe@FreeBSD.org>2017-09-27 05:44:50 +0000
committerSepherosa Ziehau <sephe@FreeBSD.org>2017-09-27 05:44:50 +0000
commit2be266caf27d62f59031d04ac677d3692badef11 (patch)
treeee141de2e4fae59672458d196b26f16faa8affbb /sys/dev/hyperv/netvsc
parentc49d47daf37f7cddef07e456565ad6f2270de773 (diff)
downloadsrc-2be266caf27d62f59031d04ac677d3692badef11.tar.gz
src-2be266caf27d62f59031d04ac677d3692badef11.zip
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. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D12429
Notes
Notes: svn path=/head/; revision=324049
Diffstat (limited to 'sys/dev/hyperv/netvsc')
-rw-r--r--sys/dev/hyperv/netvsc/if_hn.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c
index 2a1624d05223..cfdb7a556fc7 100644
--- a/sys/dev/hyperv/netvsc/if_hn.c
+++ b/sys/dev/hyperv/netvsc/if_hn.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
+#include <sys/counter.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/malloc.h>
@@ -460,6 +461,35 @@ SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
"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,
@@ -799,6 +829,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)
@@ -5479,11 +5530,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;
@@ -7336,6 +7387,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;
@@ -7415,5 +7468,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);