hyperv/hn: Use channel0, i.e. TX ring0, for TCP SYN/SYN|ACK.

Hyper-V hot channel effect:
Operation latency on hot channel is only _half_ of the operation
latency on cold channels.

This commit takes the advantage of the above Hyper-V host channel
effect, and can reduce more than 75% latency and more than 50%
latency stdev, i.e. lower and more stable/predictable latency,
for various types of web server workloads.

MFC after:	3 days
Sponsored by:	Microsoft
This commit is contained in:
Sepherosa Ziehau 2017-04-24 07:52:27 +00:00
parent c1c63967cb
commit cc0c6ebc14

View File

@ -622,6 +622,16 @@ hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
}
#if defined(INET6) || defined(INET)
#define PULLUP_HDR(m, len) \
do { \
if (__predict_false((m)->m_len < (len))) { \
(m) = m_pullup((m), (len)); \
if ((m) == NULL) \
return (NULL); \
} \
} while (0)
/*
* NOTE: If this function failed, the m_head would be freed.
*/
@ -634,15 +644,6 @@ hn_tso_fixup(struct mbuf *m_head)
KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
#define PULLUP_HDR(m, len) \
do { \
if (__predict_false((m)->m_len < (len))) { \
(m) = m_pullup((m), (len)); \
if ((m) == NULL) \
return (NULL); \
} \
} while (0)
PULLUP_HDR(m_head, sizeof(*evl));
evl = mtod(m_head, struct ether_vlan_header *);
if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
@ -691,8 +692,65 @@ do { \
#endif
return (m_head);
#undef PULLUP_HDR
}
/*
* NOTE: If this function failed, the m_head would be freed.
*/
static __inline struct mbuf *
hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
{
const struct ether_vlan_header *evl;
const struct tcphdr *th;
int ehlen;
*tcpsyn = 0;
PULLUP_HDR(m_head, sizeof(*evl));
evl = mtod(m_head, const struct ether_vlan_header *);
if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
else
ehlen = ETHER_HDR_LEN;
#ifdef INET
if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) {
const struct ip *ip;
int iphlen;
PULLUP_HDR(m_head, ehlen + sizeof(*ip));
ip = mtodo(m_head, ehlen);
iphlen = ip->ip_hl << 2;
PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
th = mtodo(m_head, ehlen + iphlen);
if (th->th_flags & TH_SYN)
*tcpsyn = 1;
}
#endif
#if defined(INET6) && defined(INET)
else
#endif
#ifdef INET6
{
const struct ip6_hdr *ip6;
PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
ip6 = mtodo(m_head, ehlen);
if (ip6->ip6_nxt != IPPROTO_TCP)
return (m_head);
PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
th = mtodo(m_head, ehlen + sizeof(*ip6));
if (th->th_flags & TH_SYN)
*tcpsyn = 1;
}
#endif
return (m_head);
}
#undef PULLUP_HDR
#endif /* INET6 || INET */
static int
@ -4369,7 +4427,29 @@ hn_transmit(struct ifnet *ifp, struct mbuf *m)
idx = bid % sc->hn_tx_ring_inuse;
else
#endif
idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
{
#if defined(INET6) || defined(INET)
int tcpsyn = 0;
if (m->m_pkthdr.len < 128 &&
(m->m_pkthdr.csum_flags &
(CSUM_IP_TCP | CSUM_IP6_TCP)) &&
(m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
m = hn_check_tcpsyn(m, &tcpsyn);
if (__predict_false(m == NULL)) {
if_inc_counter(ifp,
IFCOUNTER_OERRORS, 1);
return (EIO);
}
}
#else
const int tcpsyn = 0;
#endif
if (tcpsyn)
idx = 0;
else
idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
}
}
txr = &sc->hn_tx_ring[idx];