svn commit: r308166 - head/sys/dev/hyperv/netvsc

Sepherosa Ziehau sephe at FreeBSD.org
Tue Nov 1 07:41:27 UTC 2016


Author: sephe
Date: Tue Nov  1 07:41:26 2016
New Revision: 308166
URL: https://svnweb.freebsd.org/changeset/base/308166

Log:
  hyperv/hn: Move TSO packet fixup to an earlier place for if_transmit.
  
  While TSO packet header may be still cache-hot.
  
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D8393

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

Modified: head/sys/dev/hyperv/netvsc/if_hn.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hn.c	Tue Nov  1 07:15:39 2016	(r308165)
+++ head/sys/dev/hyperv/netvsc/if_hn.c	Tue Nov  1 07:41:26 2016	(r308166)
@@ -547,6 +547,80 @@ hn_chim_free(struct hn_softc *sc, uint32
 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
 }
 
+#if defined(INET6) || defined(INET)
+/*
+ * NOTE: If this function failed, the m_head would be freed.
+ */
+static __inline struct mbuf *
+hn_tso_fixup(struct mbuf *m_head)
+{
+	struct ether_vlan_header *evl;
+	struct tcphdr *th;
+	int ehlen;
+
+	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))
+		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
+	else
+		ehlen = ETHER_HDR_LEN;
+
+#ifdef INET
+	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
+		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);
+
+		ip->ip_len = 0;
+		ip->ip_sum = 0;
+		th->th_sum = in_pseudo(ip->ip_src.s_addr,
+		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
+	}
+#endif
+#if defined(INET6) && defined(INET)
+	else
+#endif
+#ifdef INET6
+	{
+		struct ip6_hdr *ip6;
+
+		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
+		ip6 = mtodo(m_head, ehlen);
+		if (ip6->ip6_nxt != IPPROTO_TCP) {
+			m_freem(m_head);
+			return (NULL);
+		}
+
+		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
+		th = mtodo(m_head, ehlen + sizeof(*ip6));
+
+		ip6->ip6_plen = 0;
+		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
+	}
+#endif
+	return (m_head);
+
+#undef PULLUP_HDR
+}
+#endif	/* INET6 || INET */
+
 static int
 hn_set_rxfilter(struct hn_softc *sc)
 {
@@ -1358,32 +1432,10 @@ hn_encap(struct hn_tx_ring *txr, struct 
 
 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
 #if defined(INET6) || defined(INET)
-		struct ether_vlan_header *eh;
-		int ether_len;
-
-		/*
-		 * XXX need m_pullup and use mtodo
-		 */
-		eh = mtod(m_head, struct ether_vlan_header*);
-		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN))
-			ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
-		else
-			ether_len = ETHER_HDR_LEN;
-
 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
 #ifdef INET
 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
-			struct ip *ip =
-			    (struct ip *)(m_head->m_data + ether_len);
-			unsigned long iph_len = ip->ip_hl << 2;
-			struct tcphdr *th =
-			    (struct tcphdr *)((caddr_t)ip + iph_len);
-
-			ip->ip_len = 0;
-			ip->ip_sum = 0;
-			th->th_sum = in_pseudo(ip->ip_src.s_addr,
-			    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
 			    m_head->m_pkthdr.tso_segsz);
 		}
@@ -1393,12 +1445,6 @@ hn_encap(struct hn_tx_ring *txr, struct 
 #endif
 #ifdef INET6
 		{
-			struct ip6_hdr *ip6 = (struct ip6_hdr *)
-			    (m_head->m_data + ether_len);
-			struct tcphdr *th = (struct tcphdr *)(ip6 + 1);
-
-			ip6->ip6_plen = 0;
-			th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
 			    m_head->m_pkthdr.tso_segsz);
 		}
@@ -3280,6 +3326,16 @@ hn_start_locked(struct hn_tx_ring *txr, 
 			return 1;
 		}
 
+#if defined(INET6) || defined(INET)
+		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
+			m_head = hn_tso_fixup(m_head);
+			if (__predict_false(m_head == NULL)) {
+				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+				continue;
+			}
+		}
+#endif
+
 		txd = hn_txdesc_get(txr);
 		if (txd == NULL) {
 			txr->hn_no_txdescs++;
@@ -3442,6 +3498,20 @@ hn_transmit(struct ifnet *ifp, struct mb
 	struct hn_tx_ring *txr;
 	int error, idx = 0;
 
+#if defined(INET6) || defined(INET)
+	/*
+	 * Perform TSO packet header fixup now, since the TSO
+	 * packet header 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;
+		}
+	}
+#endif
+
 	/*
 	 * Select the TX ring based on flowid
 	 */


More information about the svn-src-all mailing list