Author: sephe
Date: Wed Sep 27 04:42:40 2017
New Revision: 324048
URL: https://svnweb.freebsd.org/changeset/base/324048

Log:
  hyperv/hn: Set tcp header offset for CSUM/LSO offloading.
  
  No observable effect; better safe than sorry.
  
  MFC after:    1 week
  Sponsored by: Microsoft
  Differential Revision:        https://reviews.freebsd.org/D12417

Modified:
  head/sys/dev/hyperv/netvsc/if_hn.c
  head/sys/dev/hyperv/netvsc/ndis.h

Modified: head/sys/dev/hyperv/netvsc/if_hn.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hn.c  Wed Sep 27 01:47:54 2017        
(r324047)
+++ head/sys/dev/hyperv/netvsc/if_hn.c  Wed Sep 27 04:42:40 2017        
(r324048)
@@ -727,6 +727,7 @@ hn_tso_fixup(struct mbuf *m_head)
                ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
        else
                ehlen = ETHER_HDR_LEN;
+       m_head->m_pkthdr.l2hlen = ehlen;
 
 #ifdef INET
        if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
@@ -736,6 +737,7 @@ hn_tso_fixup(struct mbuf *m_head)
                PULLUP_HDR(m_head, ehlen + sizeof(*ip));
                ip = mtodo(m_head, ehlen);
                iphlen = ip->ip_hl << 2;
+               m_head->m_pkthdr.l3hlen = iphlen;
 
                PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
                th = mtodo(m_head, ehlen + iphlen);
@@ -759,6 +761,7 @@ hn_tso_fixup(struct mbuf *m_head)
                        m_freem(m_head);
                        return (NULL);
                }
+               m_head->m_pkthdr.l3hlen = sizeof(*ip6);
 
                PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
                th = mtodo(m_head, ehlen + sizeof(*ip6));
@@ -768,41 +771,34 @@ hn_tso_fixup(struct mbuf *m_head)
        }
 #endif
        return (m_head);
-
 }
 
 /*
  * NOTE: If this function failed, the m_head would be freed.
  */
 static __inline struct mbuf *
-hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
+hn_set_hlen(struct mbuf *m_head)
 {
        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;
+       m_head->m_pkthdr.l2hlen = ehlen;
 
 #ifdef INET
-       if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) {
+       if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
                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;
+               m_head->m_pkthdr.l3hlen = iphlen;
        }
 #endif
 #if defined(INET6) && defined(INET)
@@ -814,18 +810,36 @@ hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
 
                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;
+               if (ip6->ip6_nxt != IPPROTO_TCP) {
+                       m_freem(m_head);
+                       return (NULL);
+               }
+               m_head->m_pkthdr.l3hlen = sizeof(*ip6);
        }
 #endif
        return (m_head);
 }
 
+/*
+ * 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 tcphdr *th;
+       int ehlen, iphlen;
+
+       *tcpsyn = 0;
+       ehlen = m_head->m_pkthdr.l2hlen;
+       iphlen = m_head->m_pkthdr.l3hlen;
+
+       PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
+       th = mtodo(m_head, ehlen + iphlen);
+       if (th->th_flags & TH_SYN)
+               *tcpsyn = 1;
+       return (m_head);
+}
+
 #undef PULLUP_HDR
 
 #endif /* INET6 || INET */
@@ -3010,7 +3024,8 @@ hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, st
                    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
 #ifdef INET
                if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
-                       *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
+                       *pi_data = NDIS_LSO2_INFO_MAKEIPV4(
+                           m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
                            m_head->m_pkthdr.tso_segsz);
                }
 #endif
@@ -3019,7 +3034,8 @@ hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, st
 #endif
 #ifdef INET6
                {
-                       *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
+                       *pi_data = NDIS_LSO2_INFO_MAKEIPV6(
+                           m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
                            m_head->m_pkthdr.tso_segsz);
                }
 #endif
@@ -3036,11 +3052,15 @@ hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, st
                                *pi_data |= NDIS_TXCSUM_INFO_IPCS;
                }
 
-               if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
-                       *pi_data |= NDIS_TXCSUM_INFO_TCPCS;
-               else if (m_head->m_pkthdr.csum_flags &
-                   (CSUM_IP_UDP | CSUM_IP6_UDP))
-                       *pi_data |= NDIS_TXCSUM_INFO_UDPCS;
+               if (m_head->m_pkthdr.csum_flags &
+                   (CSUM_IP_TCP | CSUM_IP6_TCP)) {
+                       *pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
+                           m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
+               } else if (m_head->m_pkthdr.csum_flags &
+                   (CSUM_IP_UDP | CSUM_IP6_UDP)) {
+                       *pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
+                           m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
+               }
        }
 
        pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
@@ -5566,6 +5586,13 @@ hn_start_locked(struct hn_tx_ring *txr, int len)
                                if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
                                continue;
                        }
+               } else if (m_head->m_pkthdr.csum_flags &
+                   (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
+                       m_head = hn_set_hlen(m_head);
+                       if (__predict_false(m_head == NULL)) {
+                               if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+                               continue;
+                       }
                }
 #endif
 
@@ -5846,11 +5873,18 @@ hn_transmit(struct ifnet *ifp, struct mbuf *m)
 
 #if defined(INET6) || defined(INET)
        /*
-        * Perform TSO packet header fixup now, since the TSO
-        * packet header should be cache-hot.
+        * Perform TSO packet header fixup or get l2/l3 header length now,
+        * since packet headers should be cache-hot.
         */
        if (m->m_pkthdr.csum_flags & CSUM_TSO) {
                m = hn_tso_fixup(m);
+               if (__predict_false(m == NULL)) {
+                       if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+                       return EIO;
+               }
+       } else if (m->m_pkthdr.csum_flags &
+           (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
+               m = hn_set_hlen(m);
                if (__predict_false(m == NULL)) {
                        if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
                        return EIO;

Modified: head/sys/dev/hyperv/netvsc/ndis.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/ndis.h   Wed Sep 27 01:47:54 2017        
(r324047)
+++ head/sys/dev/hyperv/netvsc/ndis.h   Wed Sep 27 04:42:40 2017        
(r324048)
@@ -402,4 +402,13 @@ struct ndis_offload {
 #define        NDIS_TXCSUM_INFO_IPCS           0x00000010
 #define        NDIS_TXCSUM_INFO_THOFF          0x03ff0000
 
+#define        NDIS_TXCSUM_INFO_MKL4CS(thoff, flag)                    \
+       ((((uint32_t)(thoff)) << 16) | (flag))
+
+#define        NDIS_TXCSUM_INFO_MKTCPCS(thoff)                         \
+       NDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_TCPCS)
+
+#define        NDIS_TXCSUM_INFO_MKUDPCS(thoff)                         \
+       NDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_UDPCS)
+
 #endif /* !_NET_NDIS_H_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to