summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2012-04-16 13:49:03 +0000
committerglebius <glebius@FreeBSD.org>2012-04-16 13:49:03 +0000
commit9297dd4c7e824aadeea6dae741d5f37f4882fda0 (patch)
treee28d7a410365611b09028480f37189613684135f /sys/netinet/tcp_input.c
parentb9ad5bf2361636dfc9d0a86b468fd194f8f63671 (diff)
downloadFreeBSD-src-9297dd4c7e824aadeea6dae741d5f37f4882fda0.zip
FreeBSD-src-9297dd4c7e824aadeea6dae741d5f37f4882fda0.tar.gz
When we receive an ICMP unreach need fragmentation datagram, we take
proposed MTU value from it and update the TCP host cache. Then tcp_mss_update() is called on the corresponding tcpcb. It finds the just allocated entry in the TCP host cache and updates MSS on the tcpcb. And then we do a fast retransmit of what we have in the tcp send buffer. This sequence gets broken if the TCP host cache is exausted. In this case allocation fails, and later called tcp_mss_update() finds nothing in cache. The fast retransmit is done with not reduced MSS and is immidiately replied by remote host with new ICMP datagrams and the cycle repeats. This ping-pong can go up to wirespeed. To fix this: - tcp_mss_update() gets new parameter - mtuoffer, that is like offer, but needs to have min_protoh subtracted. - tcp_mtudisc() as notification method renamed to tcp_mtudisc_notify(). - tcp_mtudisc() now accepts not a useless error argument, but proposed MTU value, that is passed to tcp_mss_update() as mtuoffer. Reported by: az Reported by: Andrey Zonov <andrey zonov.org> Reviewed by: andre (previous version of patch)
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 1a31c5e..7c8310f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -3288,22 +3288,19 @@ tcp_xmit_timer(struct tcpcb *tp, int rtt)
* are present. Store the upper limit of the length of options plus
* data in maxopd.
*
- * In case of T/TCP, we call this routine during implicit connection
- * setup as well (offer = -1), to initialize maxseg from the cached
- * MSS of our peer.
- *
* NOTE that this routine is only called when we process an incoming
- * segment. Outgoing SYN/ACK MSS settings are handled in tcp_mssopt().
+ * segment, or an ICMP need fragmentation datagram. Outgoing SYN/ACK MSS
+ * settings are handled in tcp_mssopt().
*/
void
-tcp_mss_update(struct tcpcb *tp, int offer,
+tcp_mss_update(struct tcpcb *tp, int offer, int mtuoffer,
struct hc_metrics_lite *metricptr, int *mtuflags)
{
int mss = 0;
u_long maxmtu = 0;
struct inpcb *inp = tp->t_inpcb;
struct hc_metrics_lite metrics;
- int origoffer = offer;
+ int origoffer;
#ifdef INET6
int isipv6 = ((inp->inp_vflag & INP_IPV6) != 0) ? 1 : 0;
size_t min_protoh = isipv6 ?
@@ -3315,6 +3312,12 @@ tcp_mss_update(struct tcpcb *tp, int offer,
INP_WLOCK_ASSERT(tp->t_inpcb);
+ if (mtuoffer != -1) {
+ KASSERT(offer == -1, ("%s: conflict", __func__));
+ offer = mtuoffer - min_protoh;
+ }
+ origoffer = offer;
+
/* Initialize. */
#ifdef INET6
if (isipv6) {
@@ -3473,7 +3476,7 @@ tcp_mss(struct tcpcb *tp, int offer)
KASSERT(tp != NULL, ("%s: tp == NULL", __func__));
- tcp_mss_update(tp, offer, &metrics, &mtuflags);
+ tcp_mss_update(tp, offer, -1, &metrics, &mtuflags);
mss = tp->t_maxseg;
inp = tp->t_inpcb;
OpenPOWER on IntegriCloud