Author: sephe
Date: Thu Apr 27 02:17:45 2017
New Revision: 317482
URL: https://svnweb.freebsd.org/changeset/base/317482

Log:
  MFC 317353
  
      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.
  
      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     Thu Apr 27 01:58:20 2017        
(r317481)
+++ stable/10/sys/dev/hyperv/netvsc/if_hn.c     Thu Apr 27 02:17:45 2017        
(r317482)
@@ -611,6 +611,16 @@ hn_chim_free(struct hn_softc *sc, uint32
 }
 
 #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.
  */
@@ -623,15 +633,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))
@@ -680,8 +681,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
@@ -4343,8 +4401,28 @@ hn_transmit(struct ifnet *ifp, struct mb
        /*
         * Select the TX ring based on flowid
         */
-       if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
-               idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
+       if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
+#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];
 
        error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
_______________________________________________
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"

Reply via email to