Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/if_hn.c
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
#include "opt_hn.h" | #include "opt_hn.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_rss.h" | #include "opt_rss.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/counter.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/rmlock.h> | #include <sys/rmlock.h> | ||||
▲ Show 20 Lines • Show All 382 Lines • ▼ Show 20 Lines | |||||
/* Trust ip packets verification on host side. */ | /* Trust ip packets verification on host side. */ | ||||
static int hn_trust_hostip = 1; | static int hn_trust_hostip = 1; | ||||
SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, | ||||
&hn_trust_hostip, 0, | &hn_trust_hostip, 0, | ||||
"Trust ip packet verification on host side, " | "Trust ip packet verification on host side, " | ||||
"when csum info is missing (global setting)"); | "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 */ | /* Limit TSO burst size */ | ||||
static int hn_tso_maxlen = IP_MAXPACKET; | static int hn_tso_maxlen = IP_MAXPACKET; | ||||
SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, | ||||
&hn_tso_maxlen, 0, "TSO burst limit"); | &hn_tso_maxlen, 0, "TSO burst limit"); | ||||
/* Limit chimney send size */ | /* Limit chimney send size */ | ||||
static int hn_tx_chimney_size = 0; | static int hn_tx_chimney_size = 0; | ||||
SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, | ||||
▲ Show 20 Lines • Show All 323 Lines • ▼ Show 20 Lines | #ifdef INET | ||||
if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) { | if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) { | ||||
const struct ip *ip; | const struct ip *ip; | ||||
int iphlen; | int iphlen; | ||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip)); | PULLUP_HDR(m_head, ehlen + sizeof(*ip)); | ||||
ip = mtodo(m_head, ehlen); | ip = mtodo(m_head, ehlen); | ||||
iphlen = ip->ip_hl << 2; | iphlen = ip->ip_hl << 2; | ||||
m_head->m_pkthdr.l3hlen = iphlen; | 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 | #endif | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
{ | { | ||||
const struct ip6_hdr *ip6; | const struct ip6_hdr *ip6; | ||||
▲ Show 20 Lines • Show All 4,663 Lines • ▼ Show 20 Lines | if (hn_tx_chimney_size > 0 && | ||||
hn_tx_chimney_size < sc->hn_chim_szmax) | hn_tx_chimney_size < sc->hn_chim_szmax) | ||||
hn_set_chim_size(sc, hn_tx_chimney_size); | hn_set_chim_size(sc, hn_tx_chimney_size); | ||||
csum_assist = 0; | csum_assist = 0; | ||||
if (sc->hn_caps & HN_CAP_IPCS) | if (sc->hn_caps & HN_CAP_IPCS) | ||||
csum_assist |= CSUM_IP; | csum_assist |= CSUM_IP; | ||||
if (sc->hn_caps & HN_CAP_TCP4CS) | if (sc->hn_caps & HN_CAP_TCP4CS) | ||||
csum_assist |= CSUM_IP_TCP; | 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; | csum_assist |= CSUM_IP_UDP; | ||||
if (sc->hn_caps & HN_CAP_TCP6CS) | if (sc->hn_caps & HN_CAP_TCP6CS) | ||||
csum_assist |= CSUM_IP6_TCP; | 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; | csum_assist |= CSUM_IP6_UDP; | ||||
for (i = 0; i < sc->hn_tx_ring_cnt; ++i) | for (i = 0; i < sc->hn_tx_ring_cnt; ++i) | ||||
sc->hn_tx_ring[i].hn_csum_assist = csum_assist; | sc->hn_tx_ring[i].hn_csum_assist = csum_assist; | ||||
if (sc->hn_caps & HN_CAP_HASHVAL) { | if (sc->hn_caps & HN_CAP_HASHVAL) { | ||||
/* | /* | ||||
* Support HASHVAL pktinfo on TX path. | * Support HASHVAL pktinfo on TX path. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,836 Lines • ▼ Show 20 Lines | hn_chan_callback(struct vmbus_channel *chan, void *xrxr) | ||||
hn_chan_rollup(rxr, rxr->hn_txr); | hn_chan_rollup(rxr, rxr->hn_txr); | ||||
} | } | ||||
static void | static void | ||||
hn_sysinit(void *arg __unused) | hn_sysinit(void *arg __unused) | ||||
{ | { | ||||
int i; | int i; | ||||
hn_udpcs_fixup = counter_u64_alloc(M_WAITOK); | |||||
#ifdef HN_IFSTART_SUPPORT | #ifdef HN_IFSTART_SUPPORT | ||||
/* | /* | ||||
* Don't use ifnet.if_start if transparent VF mode is requested; | * Don't use ifnet.if_start if transparent VF mode is requested; | ||||
* mainly due to the IFF_DRV_OACTIVE flag. | * mainly due to the IFF_DRV_OACTIVE flag. | ||||
*/ | */ | ||||
if (hn_xpnt_vf && hn_use_if_start) { | if (hn_xpnt_vf && hn_use_if_start) { | ||||
hn_use_if_start = 0; | hn_use_if_start = 0; | ||||
printf("hn: tranparent VF mode, if_transmit will be used, " | printf("hn: tranparent VF mode, if_transmit will be used, " | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if (hn_tx_taskque != NULL) { | ||||
for (i = 0; i < hn_tx_taskq_cnt; ++i) | for (i = 0; i < hn_tx_taskq_cnt; ++i) | ||||
taskqueue_free(hn_tx_taskque[i]); | taskqueue_free(hn_tx_taskque[i]); | ||||
free(hn_tx_taskque, M_DEVBUF); | free(hn_tx_taskque, M_DEVBUF); | ||||
} | } | ||||
if (hn_vfmap != NULL) | if (hn_vfmap != NULL) | ||||
free(hn_vfmap, M_DEVBUF); | free(hn_vfmap, M_DEVBUF); | ||||
rm_destroy(&hn_vfmap_lock); | rm_destroy(&hn_vfmap_lock); | ||||
counter_u64_free(hn_udpcs_fixup); | |||||
} | } | ||||
SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); | SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); |