Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Sep 2012 11:43:29 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r240307 - stable/9/sys/netinet
Message-ID:  <201209101143.q8ABhTVY047020@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Mon Sep 10 11:43:28 2012
New Revision: 240307
URL: http://svn.freebsd.org/changeset/base/240307

Log:
  Merge r238516 from head:
    If ip_output() returns EMSGSIZE to tcp_output(), then the latter calls
    tcp_mtudisc(), which in its turn may call tcp_output(). Under certain
    conditions (must admit they are very special) an infinite recursion can
    happen.
  
    To avoid recursion we can pass struct route to ip_output() and obtain
    correct mtu. This allows us not to use tcp_mtudisc() but call tcp_mss_update()
    directly.
  
    PR:		kern/155585
    Submitted by:	zont

Modified:
  stable/9/sys/netinet/tcp_output.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/netinet/tcp_output.c
==============================================================================
--- stable/9/sys/netinet/tcp_output.c	Mon Sep 10 11:38:55 2012	(r240306)
+++ stable/9/sys/netinet/tcp_output.c	Mon Sep 10 11:43:28 2012	(r240307)
@@ -182,7 +182,7 @@ tcp_output(struct tcpcb *tp)
 	int idle, sendalot;
 	int sack_rxmit, sack_bytes_rxmt;
 	struct sackhole *p;
-	int tso;
+	int tso, mtu;
 	struct tcpopt to;
 #if 0
 	int maxburst = TCP_MAXBURST;
@@ -223,6 +223,7 @@ again:
 		tcp_sack_adjust(tp);
 	sendalot = 0;
 	tso = 0;
+	mtu = 0;
 	off = tp->snd_nxt - tp->snd_una;
 	sendwin = min(tp->snd_wnd, tp->snd_cwnd);
 
@@ -1206,6 +1207,9 @@ timer:
 	 */
 #ifdef INET6
 	if (isipv6) {
+		struct route_in6 ro;
+
+		bzero(&ro, sizeof(ro));
 		/*
 		 * we separately set hoplimit for every segment, since the
 		 * user might want to change the value via setsockopt.
@@ -1215,10 +1219,13 @@ timer:
 		ip6->ip6_hlim = in6_selecthlim(tp->t_inpcb, NULL);
 
 		/* TODO: IPv6 IP6TOS_ECT bit on */
-		error = ip6_output(m,
-			    tp->t_inpcb->in6p_outputopts, NULL,
-			    ((so->so_options & SO_DONTROUTE) ?
-			    IP_ROUTETOIF : 0), NULL, NULL, tp->t_inpcb);
+		error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &ro,
+		    ((so->so_options & SO_DONTROUTE) ?  IP_ROUTETOIF : 0),
+		    NULL, NULL, tp->t_inpcb);
+
+		if (error == EMSGSIZE && ro.ro_rt != NULL)
+			mtu = ro.ro_rt->rt_rmx.rmx_mtu;
+		RO_RTFREE(&ro);
 	}
 #endif /* INET6 */
 #if defined(INET) && defined(INET6)
@@ -1226,6 +1233,9 @@ timer:
 #endif
 #ifdef INET
     {
+	struct route ro;
+
+	bzero(&ro, sizeof(ro));
 	ip->ip_len = m->m_pkthdr.len;
 #ifdef INET6
 	if (tp->t_inpcb->inp_vflag & INP_IPV6PROTO)
@@ -1242,9 +1252,13 @@ timer:
 	if (V_path_mtu_discovery && tp->t_maxopd > V_tcp_minmss)
 		ip->ip_off |= IP_DF;
 
-	error = ip_output(m, tp->t_inpcb->inp_options, NULL,
+	error = ip_output(m, tp->t_inpcb->inp_options, &ro,
 	    ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0,
 	    tp->t_inpcb);
+
+	if (error == EMSGSIZE && ro.ro_rt != NULL)
+		mtu = ro.ro_rt->rt_rmx.rmx_mtu;
+	RO_RTFREE(&ro);
     }
 #endif /* INET */
 	if (error) {
@@ -1291,21 +1305,18 @@ out:
 			 * For some reason the interface we used initially
 			 * to send segments changed to another or lowered
 			 * its MTU.
-			 *
-			 * tcp_mtudisc() will find out the new MTU and as
-			 * its last action, initiate retransmission, so it
-			 * is important to not do so here.
-			 *
 			 * If TSO was active we either got an interface
 			 * without TSO capabilits or TSO was turned off.
-			 * Disable it for this connection as too and
-			 * immediatly retry with MSS sized segments generated
-			 * by this function.
+			 * If we obtained mtu from ip_output() then update
+			 * it and try again.
 			 */
 			if (tso)
 				tp->t_flags &= ~TF_TSO;
-			tcp_mtudisc(tp->t_inpcb, -1);
-			return (0);
+			if (mtu != 0) {
+				tcp_mss_update(tp, -1, mtu, NULL, NULL);
+				goto again;
+			}
+			return (error);
 		case EHOSTDOWN:
 		case EHOSTUNREACH:
 		case ENETDOWN:



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