Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Jun 2013 12:55:13 +0000 (UTC)
From:      Andre Oppermann <andre@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r251296 - in head/sys: net netinet
Message-ID:  <201306031255.r53CtDYw089624@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andre
Date: Mon Jun  3 12:55:13 2013
New Revision: 251296
URL: http://svnweb.freebsd.org/changeset/base/251296

Log:
  Allow drivers to specify a maximum TSO length in bytes if they are
  limited in the amount of data they can handle at once.
  
  Drivers can set ifp->if_hw_tsomax before calling ether_ifattach() to
  change the limit.
  
  The lowest allowable size is IP_MAXPACKET / 8 (8192 bytes) as anything
  less wouldn't be very useful anymore.  The upper limit is still at
  IP_MAXPACKET (65536 bytes).  Raising it requires further auditing of
  the IPv4/v6 code path's as the length field in the IP header would
  overflow leading to confusion in firewalls and others packet handler on
  the real size of the packet.
  
  The placement into "struct ifnet" is a bit hackish but the best place
  that was found.  When the stack/driver boundary is updated it should
  be handled in a better way.
  
  Submitted by:	cperciva (earlier version)
  Reviewed by:	cperciva
  Tested by:	cperciva
  MFC after:	1 week (using spare struct members to preserve ABI)

Modified:
  head/sys/net/if.c
  head/sys/net/if_var.h
  head/sys/netinet/tcp_input.c
  head/sys/netinet/tcp_output.c
  head/sys/netinet/tcp_subr.c
  head/sys/netinet/tcp_var.h

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Mon Jun  3 12:43:09 2013	(r251295)
+++ head/sys/net/if.c	Mon Jun  3 12:55:13 2013	(r251296)
@@ -74,18 +74,18 @@
 #include <net/vnet.h>
 
 #if defined(INET) || defined(INET6)
-/*XXX*/
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#include <netinet/ip.h>
 #include <netinet/ip_carp.h>
+#ifdef INET
+#include <netinet/if_ether.h>
+#endif /* INET */
 #ifdef INET6
 #include <netinet6/in6_var.h>
 #include <netinet6/in6_ifattach.h>
-#endif
-#endif
-#ifdef INET
-#include <netinet/if_ether.h>
-#endif
+#endif /* INET6 */
+#endif /* INET || INET6 */
 
 #include <security/mac/mac_framework.h>
 
@@ -653,6 +653,13 @@ if_attach_internal(struct ifnet *ifp, in
 		TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
 		/* Reliably crash if used uninitialized. */
 		ifp->if_broadcastaddr = NULL;
+
+		/* Initialize to max value. */
+		if (ifp->if_hw_tsomax == 0)
+			ifp->if_hw_tsomax = IP_MAXPACKET;
+		KASSERT(ifp->if_hw_tsomax <= IP_MAXPACKET &&
+		    ifp->if_hw_tsomax >= IP_MAXPACKET / 8,
+		    ("%s: tsomax outside of range", __func__));
 	}
 #ifdef VIMAGE
 	else {

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h	Mon Jun  3 12:43:09 2013	(r251295)
+++ head/sys/net/if_var.h	Mon Jun  3 12:55:13 2013	(r251296)
@@ -204,6 +204,11 @@ struct ifnet {
 	u_int	if_fib;			/* interface FIB */
 	u_char	if_alloctype;		/* if_type at time of allocation */
 
+	u_int	if_hw_tsomax;		/* tso burst length limit, the minmum
+					 * is (IP_MAXPACKET / 8).
+					 * XXXAO: Have to find a better place
+					 * for it eventually. */
+
 	/*
 	 * Spare fields are added so that we can modify sensitive data
 	 * structures without changing the kernel binary interface, and must

Modified: head/sys/netinet/tcp_input.c
==============================================================================
--- head/sys/netinet/tcp_input.c	Mon Jun  3 12:43:09 2013	(r251295)
+++ head/sys/netinet/tcp_input.c	Mon Jun  3 12:55:13 2013	(r251296)
@@ -3434,7 +3434,7 @@ tcp_xmit_timer(struct tcpcb *tp, int rtt
  */
 void
 tcp_mss_update(struct tcpcb *tp, int offer, int mtuoffer,
-    struct hc_metrics_lite *metricptr, int *mtuflags)
+    struct hc_metrics_lite *metricptr, struct tcp_ifcap *cap)
 {
 	int mss = 0;
 	u_long maxmtu = 0;
@@ -3461,7 +3461,7 @@ tcp_mss_update(struct tcpcb *tp, int off
 	/* Initialize. */
 #ifdef INET6
 	if (isipv6) {
-		maxmtu = tcp_maxmtu6(&inp->inp_inc, mtuflags);
+		maxmtu = tcp_maxmtu6(&inp->inp_inc, cap);
 		tp->t_maxopd = tp->t_maxseg = V_tcp_v6mssdflt;
 	}
 #endif
@@ -3470,7 +3470,7 @@ tcp_mss_update(struct tcpcb *tp, int off
 #endif
 #ifdef INET
 	{
-		maxmtu = tcp_maxmtu(&inp->inp_inc, mtuflags);
+		maxmtu = tcp_maxmtu(&inp->inp_inc, cap);
 		tp->t_maxopd = tp->t_maxseg = V_tcp_mssdflt;
 	}
 #endif
@@ -3605,11 +3605,12 @@ tcp_mss(struct tcpcb *tp, int offer)
 	struct inpcb *inp;
 	struct socket *so;
 	struct hc_metrics_lite metrics;
-	int mtuflags = 0;
+	struct tcp_ifcap cap;
 
 	KASSERT(tp != NULL, ("%s: tp == NULL", __func__));
-	
-	tcp_mss_update(tp, offer, -1, &metrics, &mtuflags);
+
+	bzero(&cap, sizeof(cap));
+	tcp_mss_update(tp, offer, -1, &metrics, &cap);
 
 	mss = tp->t_maxseg;
 	inp = tp->t_inpcb;
@@ -3654,8 +3655,10 @@ tcp_mss(struct tcpcb *tp, int offer)
 	SOCKBUF_UNLOCK(&so->so_rcv);
 
 	/* Check the interface for TSO capabilities. */
-	if (mtuflags & CSUM_TSO)
+	if (cap.ifcap & CSUM_TSO) {
 		tp->t_flags |= TF_TSO;
+		tp->t_tsomax = cap.tsomax;
+	}
 }
 
 /*

Modified: head/sys/netinet/tcp_output.c
==============================================================================
--- head/sys/netinet/tcp_output.c	Mon Jun  3 12:43:09 2013	(r251295)
+++ head/sys/netinet/tcp_output.c	Mon Jun  3 12:55:13 2013	(r251296)
@@ -769,12 +769,13 @@ send:
 			    ("%s: TSO can't do IP options", __func__));
 
 			/*
-			 * Limit a burst to IP_MAXPACKET minus IP,
+			 * Limit a burst to t_tsomax minus IP,
 			 * TCP and options length to keep ip->ip_len
-			 * from overflowing.
+			 * from overflowing or exceeding the maximum
+			 * length allowed by the network interface.
 			 */
-			if (len > IP_MAXPACKET - hdrlen) {
-				len = IP_MAXPACKET - hdrlen;
+			if (len > tp->t_tsomax - hdrlen) {
+				len = tp->t_tsomax - hdrlen;
 				sendalot = 1;
 			}
 

Modified: head/sys/netinet/tcp_subr.c
==============================================================================
--- head/sys/netinet/tcp_subr.c	Mon Jun  3 12:43:09 2013	(r251295)
+++ head/sys/netinet/tcp_subr.c	Mon Jun  3 12:55:13 2013	(r251296)
@@ -1770,7 +1770,7 @@ tcp_mtudisc(struct inpcb *inp, int mtuof
  * tcp_mss_update to get the peer/interface MTU.
  */
 u_long
-tcp_maxmtu(struct in_conninfo *inc, int *flags)
+tcp_maxmtu(struct in_conninfo *inc, struct tcp_ifcap *cap)
 {
 	struct route sro;
 	struct sockaddr_in *dst;
@@ -1795,10 +1795,11 @@ tcp_maxmtu(struct in_conninfo *inc, int 
 			maxmtu = min(sro.ro_rt->rt_rmx.rmx_mtu, ifp->if_mtu);
 
 		/* Report additional interface capabilities. */
-		if (flags != NULL) {
+		if (cap != NULL) {
 			if (ifp->if_capenable & IFCAP_TSO4 &&
 			    ifp->if_hwassist & CSUM_TSO)
-				*flags |= CSUM_TSO;
+				cap->ifcap |= CSUM_TSO;
+				cap->tsomax = ifp->if_hw_tsomax;
 		}
 		RTFREE(sro.ro_rt);
 	}
@@ -1808,7 +1809,7 @@ tcp_maxmtu(struct in_conninfo *inc, int 
 
 #ifdef INET6
 u_long
-tcp_maxmtu6(struct in_conninfo *inc, int *flags)
+tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap)
 {
 	struct route_in6 sro6;
 	struct ifnet *ifp;
@@ -1832,10 +1833,11 @@ tcp_maxmtu6(struct in_conninfo *inc, int
 				     IN6_LINKMTU(sro6.ro_rt->rt_ifp));
 
 		/* Report additional interface capabilities. */
-		if (flags != NULL) {
+		if (cap != NULL) {
 			if (ifp->if_capenable & IFCAP_TSO6 &&
 			    ifp->if_hwassist & CSUM_TSO)
-				*flags |= CSUM_TSO;
+				cap->ifcap |= CSUM_TSO;
+				cap->tsomax = ifp->if_hw_tsomax;
 		}
 		RTFREE(sro6.ro_rt);
 	}

Modified: head/sys/netinet/tcp_var.h
==============================================================================
--- head/sys/netinet/tcp_var.h	Mon Jun  3 12:43:09 2013	(r251295)
+++ head/sys/netinet/tcp_var.h	Mon Jun  3 12:55:13 2013	(r251296)
@@ -208,6 +208,8 @@ struct tcpcb {
 	u_int	t_keepintvl;		/* interval between keepalives */
 	u_int	t_keepcnt;		/* number of keepalives before close */
 
+	u_int	t_tsomax;		/* tso burst length limit */
+
 	uint32_t t_ispare[8];		/* 5 UTO, 3 TBD */
 	void	*t_pspare2[4];		/* 4 TBD */
 	uint64_t _pad[6];		/* 6 TBD (1-2 CC/RTT?) */
@@ -324,6 +326,15 @@ struct hc_metrics_lite {	/* must stay in
 	u_long	rmx_recvpipe;   /* inbound delay-bandwidth product */
 };
 
+/*
+ * Used by tcp_maxmtu() to communicate interface specific features
+ * and limits at the time of connection setup.
+ */
+struct tcp_ifcap {
+	int	ifcap;
+	u_int	tsomax;
+};
+
 #ifndef _NETINET_IN_PCB_H_
 struct in_conninfo;
 #endif /* _NETINET_IN_PCB_H_ */
@@ -782,10 +793,10 @@ void	 tcp_reass_flush(struct tcpcb *);
 void	 tcp_reass_destroy(void);
 #endif
 void	 tcp_input(struct mbuf *, int);
-u_long	 tcp_maxmtu(struct in_conninfo *, int *);
-u_long	 tcp_maxmtu6(struct in_conninfo *, int *);
+u_long	 tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
+u_long	 tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *);
 void	 tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *,
-	    int *);
+	    struct tcp_ifcap *);
 void	 tcp_mss(struct tcpcb *, int);
 int	 tcp_mssopt(struct in_conninfo *);
 struct inpcb *



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201306031255.r53CtDYw089624>