summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorRichard Scheffenegger <rscheff@FreeBSD.org>2020-09-25 10:38:19 +0000
committerRichard Scheffenegger <rscheff@FreeBSD.org>2020-09-25 10:38:19 +0000
commite39956612370981605b903fd7609dca0db81a65c (patch)
treef5ec0e7d99f4acc123a8ce6941579e262b576e16 /sys/netinet
parent1567c937e2cb709355b1cc3b62c8438147d6e05b (diff)
downloadsrc-test2-e39956612370981605b903fd7609dca0db81a65c.tar.gz
src-test2-e39956612370981605b903fd7609dca0db81a65c.zip
TCP: send full initial window when timestamps are in use
The fastpath in tcp_output tries to send out full segments, and avoid sending partial segments by comparing against the static t_maxseg variable. That value does not consider tcp options like timestamps, while the initial window calculation is using the correct dynamic tcp_maxseg() function. Due to this interaction, the last, full size segment is considered too short and not sent out immediately. Reviewed by: tuexen MFC after: 2 weeks Sponsored by: NetApp, Inc. Differential Revision: https://reviews.freebsd.org/D26478
Notes
Notes: svn path=/head/; revision=366150
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp.h2
-rw-r--r--sys/netinet/tcp_output.c14
-rw-r--r--sys/netinet/tcp_subr.c13
3 files changed, 22 insertions, 7 deletions
diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h
index 0a5226836f0f..faf142959375 100644
--- a/sys/netinet/tcp.h
+++ b/sys/netinet/tcp.h
@@ -80,6 +80,8 @@ struct tcphdr {
u_short th_urp; /* urgent pointer */
};
+#define PADTCPOLEN(len) ((((len) / 4) + !!((len) % 4)) * 4)
+
#define TCPOPT_EOL 0
#define TCPOLEN_EOL 1
#define TCPOPT_PAD 0 /* padding after EOL */
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 2485651df6e7..a7611ceb66f7 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -591,6 +591,20 @@ after_sack_rexmit:
if (len >= tp->t_maxseg)
goto send;
/*
+ * As the TCP header options are now
+ * considered when setting up the initial
+ * window, we would not send the last segment
+ * if we skip considering the option length here.
+ * Note: this may not work when tcp headers change
+ * very dynamically in the future.
+ */
+ if ((((tp->t_flags & TF_SIGNATURE) ?
+ PADTCPOLEN(TCPOLEN_SIGNATURE) : 0) +
+ ((tp->t_flags & TF_RCVD_TSTMP) ?
+ PADTCPOLEN(TCPOLEN_TIMESTAMP) : 0) +
+ len) >= tp->t_maxseg)
+ goto send;
+ /*
* NOTE! on localhost connections an 'ack' from the remote
* end may occur synchronously with the output and cause
* us to flush a buffer queued with moretocome. XXX
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index fcd8e475e066..a99898b8081e 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -3013,7 +3013,6 @@ tcp_maxseg(const struct tcpcb *tp)
* but this is harmless, since result of tcp_maxseg() is used
* only in cwnd and ssthresh estimations.
*/
-#define PAD(len) ((((len) / 4) + !!((len) % 4)) * 4)
if (TCPS_HAVEESTABLISHED(tp->t_state)) {
if (tp->t_flags & TF_RCVD_TSTMP)
optlen = TCPOLEN_TSTAMP_APPA;
@@ -3021,26 +3020,26 @@ tcp_maxseg(const struct tcpcb *tp)
optlen = 0;
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
if (tp->t_flags & TF_SIGNATURE)
- optlen += PAD(TCPOLEN_SIGNATURE);
+ optlen += PADTCPOLEN(TCPOLEN_SIGNATURE);
#endif
if ((tp->t_flags & TF_SACK_PERMIT) && tp->rcv_numsacks > 0) {
optlen += TCPOLEN_SACKHDR;
optlen += tp->rcv_numsacks * TCPOLEN_SACK;
- optlen = PAD(optlen);
+ optlen = PADTCPOLEN(optlen);
}
} else {
if (tp->t_flags & TF_REQ_TSTMP)
optlen = TCPOLEN_TSTAMP_APPA;
else
- optlen = PAD(TCPOLEN_MAXSEG);
+ optlen = PADTCPOLEN(TCPOLEN_MAXSEG);
if (tp->t_flags & TF_REQ_SCALE)
- optlen += PAD(TCPOLEN_WINDOW);
+ optlen += PADTCPOLEN(TCPOLEN_WINDOW);
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
if (tp->t_flags & TF_SIGNATURE)
- optlen += PAD(TCPOLEN_SIGNATURE);
+ optlen += PADTCPOLEN(TCPOLEN_SIGNATURE);
#endif
if (tp->t_flags & TF_SACK_PERMIT)
- optlen += PAD(TCPOLEN_SACK_PERMITTED);
+ optlen += PADTCPOLEN(TCPOLEN_SACK_PERMITTED);
}
#undef PAD
optlen = min(optlen, TCP_MAXOLEN);