svn commit: r291584 - head/sys/dev/sfxge

Andrew Rybchenko arybchik at FreeBSD.org
Tue Dec 1 14:55:26 UTC 2015


Author: arybchik
Date: Tue Dec  1 14:55:24 2015
New Revision: 291584
URL: https://svnweb.freebsd.org/changeset/base/291584

Log:
  sfxge: parse packets for TSO early in if_transmit
  
  Submitted by:   Artem V. Andreev <Artem.Andreev at oktetlabs.ru>
  Sponsored by:   Solarflare Communications, Inc.
  MFC after:      1 week
  Differential Revision: https://reviews.freebsd.org/D4309

Modified:
  head/sys/dev/sfxge/sfxge_tx.c
  head/sys/dev/sfxge/sfxge_tx.h

Modified: head/sys/dev/sfxge/sfxge_tx.c
==============================================================================
--- head/sys/dev/sfxge/sfxge_tx.c	Tue Dec  1 14:02:14 2015	(r291583)
+++ head/sys/dev/sfxge/sfxge_tx.c	Tue Dec  1 14:55:24 2015	(r291584)
@@ -710,6 +710,84 @@ sfxge_if_qflush(struct ifnet *ifp)
 		sfxge_tx_qdpl_flush(sc->txq[i]);
 }
 
+#if SFXGE_TX_PARSE_EARLY
+
+/* There is little space for user data in mbuf pkthdr, so we
+ * use l*hlen fields which are not used by the driver otherwise
+ * to store header offsets.
+ * The fields are 8-bit, but it's ok, no header may be longer than 255 bytes.
+ */
+
+
+#define TSO_MBUF_PROTO(_mbuf)    ((_mbuf)->m_pkthdr.PH_loc.sixteen[0])
+/* We abuse l5hlen here because PH_loc can hold only 64 bits of data */
+#define TSO_MBUF_FLAGS(_mbuf)    ((_mbuf)->m_pkthdr.l5hlen)
+#define TSO_MBUF_PACKETID(_mbuf) ((_mbuf)->m_pkthdr.PH_loc.sixteen[1])
+#define TSO_MBUF_SEQNUM(_mbuf)   ((_mbuf)->m_pkthdr.PH_loc.thirtytwo[1])
+
+static void sfxge_parse_tx_packet(struct mbuf *mbuf)
+{
+	struct ether_header *eh = mtod(mbuf, struct ether_header *);
+	const struct tcphdr *th;
+	struct tcphdr th_copy;
+
+	/* Find network protocol and header */
+	TSO_MBUF_PROTO(mbuf) = eh->ether_type;
+	if (TSO_MBUF_PROTO(mbuf) == htons(ETHERTYPE_VLAN)) {
+		struct ether_vlan_header *veh =
+			mtod(mbuf, struct ether_vlan_header *);
+		TSO_MBUF_PROTO(mbuf) = veh->evl_proto;
+		mbuf->m_pkthdr.l2hlen = sizeof(*veh);
+	} else {
+		mbuf->m_pkthdr.l2hlen = sizeof(*eh);
+	}
+
+	/* Find TCP header */
+	if (TSO_MBUF_PROTO(mbuf) == htons(ETHERTYPE_IP)) {
+		const struct ip *iph = (const struct ip *)mtodo(mbuf, mbuf->m_pkthdr.l2hlen);
+
+		KASSERT(iph->ip_p == IPPROTO_TCP,
+			("TSO required on non-TCP packet"));
+		mbuf->m_pkthdr.l3hlen = mbuf->m_pkthdr.l2hlen + 4 * iph->ip_hl;
+		TSO_MBUF_PACKETID(mbuf) = iph->ip_id;
+	} else {
+		KASSERT(TSO_MBUF_PROTO(mbuf) == htons(ETHERTYPE_IPV6),
+			("TSO required on non-IP packet"));
+		KASSERT(((const struct ip6_hdr *)mtodo(mbuf, mbuf->m_pkthdr.l2hlen))->ip6_nxt ==
+			IPPROTO_TCP,
+			("TSO required on non-TCP packet"));
+		mbuf->m_pkthdr.l3hlen = mbuf->m_pkthdr.l2hlen + sizeof(struct ip6_hdr);
+		TSO_MBUF_PACKETID(mbuf) = 0;
+	}
+
+	KASSERT(mbuf->m_len >= mbuf->m_pkthdr.l3hlen,
+		("network header is fragmented in mbuf"));
+
+	/* We need TCP header including flags (window is the next) */
+	if (mbuf->m_len < mbuf->m_pkthdr.l3hlen + offsetof(struct tcphdr, th_win)) {
+		m_copydata(mbuf, mbuf->m_pkthdr.l3hlen, sizeof(th_copy),
+			   (caddr_t)&th_copy);
+		th = &th_copy;
+	} else {
+		th = (const struct tcphdr *)mtodo(mbuf, mbuf->m_pkthdr.l3hlen);
+	}
+
+	mbuf->m_pkthdr.l4hlen = mbuf->m_pkthdr.l3hlen + 4 * th->th_off;
+	TSO_MBUF_SEQNUM(mbuf) = ntohl(th->th_seq);
+
+	/* These flags must not be duplicated */
+	/*
+	 * RST should not be duplicated as well, but FreeBSD kernel
+	 * generates TSO packets with RST flag. So, do not assert
+	 * its absence.
+	 */
+	KASSERT(!(th->th_flags & (TH_URG | TH_SYN)),
+		("incompatible TCP flag 0x%x on TSO packet",
+		 th->th_flags & (TH_URG | TH_SYN)));
+	TSO_MBUF_FLAGS(mbuf) = th->th_flags;
+}
+#endif
+
 /*
  * TX start -- called by the stack.
  */
@@ -744,6 +822,10 @@ sfxge_if_transmit(struct ifnet *ifp, str
 
 			index = sc->rx_indir_table[hash % SFXGE_RX_SCALE_MAX];
 		}
+#if SFXGE_TX_PARSE_EARLY
+		if (m->m_pkthdr.csum_flags & CSUM_TSO)
+			sfxge_parse_tx_packet(m);
+#endif
 		txq = sc->txq[SFXGE_TXQ_IP_TCP_UDP_CKSUM + index];
 	} else if (m->m_pkthdr.csum_flags & CSUM_DELAY_IP) {
 		txq = sc->txq[SFXGE_TXQ_IP_CKSUM];
@@ -781,26 +863,32 @@ struct sfxge_tso_state {
 	unsigned seg_size;	/* TCP segment size */
 	int fw_assisted;	/* Use FW-assisted TSO */
 	u_short packet_id;	/* IPv4 packet ID from the original packet */
+	uint8_t tcp_flags;	/* TCP flags */
 	efx_desc_t header_desc; /* Precomputed header descriptor for
 				 * FW-assisted TSO */
 };
 
+#if !SFXGE_TX_PARSE_EARLY
 static const struct ip *tso_iph(const struct sfxge_tso_state *tso)
 {
 	KASSERT(tso->protocol == htons(ETHERTYPE_IP),
 		("tso_iph() in non-IPv4 state"));
 	return (const struct ip *)(tso->mbuf->m_data + tso->nh_off);
 }
+
 static __unused const struct ip6_hdr *tso_ip6h(const struct sfxge_tso_state *tso)
 {
 	KASSERT(tso->protocol == htons(ETHERTYPE_IPV6),
 		("tso_ip6h() in non-IPv6 state"));
 	return (const struct ip6_hdr *)(tso->mbuf->m_data + tso->nh_off);
 }
+
 static const struct tcphdr *tso_tcph(const struct sfxge_tso_state *tso)
 {
 	return (const struct tcphdr *)(tso->mbuf->m_data + tso->tcph_off);
 }
+#endif
+
 
 /* Size of preallocated TSO header buffers.  Larger blocks must be
  * allocated from the heap.
@@ -857,15 +945,18 @@ static void tso_start(struct sfxge_txq *
 		      const bus_dma_segment_t *hdr_dma_seg,
 		      struct mbuf *mbuf)
 {
-	struct ether_header *eh = mtod(mbuf, struct ether_header *);
 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(txq->sc->enp);
+#if !SFXGE_TX_PARSE_EARLY
+	struct ether_header *eh = mtod(mbuf, struct ether_header *);
 	const struct tcphdr *th;
 	struct tcphdr th_copy;
+#endif
 
 	tso->fw_assisted = txq->sc->tso_fw_assisted;
 	tso->mbuf = mbuf;
 
 	/* Find network protocol and header */
+#if !SFXGE_TX_PARSE_EARLY
 	tso->protocol = eh->ether_type;
 	if (tso->protocol == htons(ETHERTYPE_VLAN)) {
 		struct ether_vlan_header *veh =
@@ -875,7 +966,14 @@ static void tso_start(struct sfxge_txq *
 	} else {
 		tso->nh_off = sizeof(*eh);
 	}
+#else
+	tso->protocol = TSO_MBUF_PROTO(mbuf);
+	tso->nh_off = mbuf->m_pkthdr.l2hlen;
+	tso->tcph_off = mbuf->m_pkthdr.l3hlen;
+	tso->packet_id = TSO_MBUF_PACKETID(mbuf);
+#endif
 
+#if !SFXGE_TX_PARSE_EARLY
 	/* Find TCP header */
 	if (tso->protocol == htons(ETHERTYPE_IP)) {
 		KASSERT(tso_iph(tso)->ip_p == IPPROTO_TCP,
@@ -890,12 +988,17 @@ static void tso_start(struct sfxge_txq *
 		tso->tcph_off = tso->nh_off + sizeof(struct ip6_hdr);
 		tso->packet_id = 0;
 	}
+#endif
+
+
 	if (tso->fw_assisted &&
 	    __predict_false(tso->tcph_off >
 			    encp->enc_tx_tso_tcp_header_offset_limit)) {
 		tso->fw_assisted = 0;
 	}
 
+
+#if !SFXGE_TX_PARSE_EARLY
 	KASSERT(mbuf->m_len >= tso->tcph_off,
 		("network header is fragmented in mbuf"));
 	/* We need TCP header including flags (window is the next) */
@@ -906,10 +1009,13 @@ static void tso_start(struct sfxge_txq *
 	} else {
 		th = tso_tcph(tso);
 	}
-
 	tso->header_len = tso->tcph_off + 4 * th->th_off;
+#else
+	tso->header_len = mbuf->m_pkthdr.l4hlen;
+#endif
 	tso->seg_size = mbuf->m_pkthdr.tso_segsz;
 
+#if !SFXGE_TX_PARSE_EARLY
 	tso->seqnum = ntohl(th->th_seq);
 
 	/* These flags must not be duplicated */
@@ -921,6 +1027,11 @@ static void tso_start(struct sfxge_txq *
 	KASSERT(!(th->th_flags & (TH_URG | TH_SYN)),
 		("incompatible TCP flag 0x%x on TSO packet",
 		 th->th_flags & (TH_URG | TH_SYN)));
+	tso->tcp_flags = th->th_flags;
+#else
+	tso->seqnum = TSO_MBUF_SEQNUM(mbuf);
+	tso->tcp_flags = TSO_MBUF_FLAGS(mbuf);
+#endif
 
 	tso->out_len = mbuf->m_pkthdr.len - tso->header_len;
 
@@ -1001,7 +1112,7 @@ static int tso_start_new_packet(struct s
 	int rc;
 
 	if (tso->fw_assisted) {
-		uint8_t tcp_flags = tso_tcph(tso)->th_flags;
+		uint8_t tcp_flags = tso->tcp_flags;
 
 		if (tso->out_len > tso->seg_size)
 			tcp_flags &= ~(TH_FIN | TH_PUSH);

Modified: head/sys/dev/sfxge/sfxge_tx.h
==============================================================================
--- head/sys/dev/sfxge/sfxge_tx.h	Tue Dec  1 14:02:14 2015	(r291583)
+++ head/sys/dev/sfxge/sfxge_tx.h	Tue Dec  1 14:55:24 2015	(r291584)
@@ -40,6 +40,11 @@
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
 
+/* If defined, parse TX packets directly in if_transmit
+ * for better cache locality and reduced time under TX lock
+ */
+#define SFXGE_TX_PARSE_EARLY 1
+
 /* Maximum size of TSO packet */
 #define	SFXGE_TSO_MAX_SIZE		(65535)
 


More information about the svn-src-head mailing list