summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_subr.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2016-01-07 00:14:42 +0000
committerglebius <glebius@FreeBSD.org>2016-01-07 00:14:42 +0000
commit7e3646578b54b2efa2501b7025e79f74ae12ea0a (patch)
tree3e84c070bf3f77cacff7c73e3720b9e5294f53f2 /sys/netinet/tcp_subr.c
parent22ac5b2c8b8f8bd18db4870b59f5606a3a7b7d39 (diff)
downloadFreeBSD-src-7e3646578b54b2efa2501b7025e79f74ae12ea0a.zip
FreeBSD-src-7e3646578b54b2efa2501b7025e79f74ae12ea0a.tar.gz
Historically we have two fields in tcpcb to describe sender MSS: t_maxopd,
and t_maxseg. This dualism emerged with T/TCP, but was not properly cleaned up after T/TCP removal. After all permutations over the years the result is that t_maxopd stores a minimum of peer offered MSS and MTU reduced by minimum protocol header. And t_maxseg stores (t_maxopd - TCPOLEN_TSTAMP_APPA) if timestamps are in action, or is equal to t_maxopd otherwise. That's a very rough estimate of MSS reduced by options length. Throughout the code it was used in places, where preciseness was not important, like cwnd or ssthresh calculations. With this change: - t_maxopd goes away. - t_maxseg now stores MSS not adjusted by options. - new function tcp_maxseg() is provided, that calculates MSS reduced by options length. The functions gives a better estimate, since it takes into account SACK state as well. Reviewed by: jtl Differential Revision: https://reviews.freebsd.org/D3593
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r--sys/netinet/tcp_subr.c57
1 files changed, 55 insertions, 2 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index c2e0696..9f21f11 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1087,7 +1087,7 @@ tcp_newtcpcb(struct inpcb *inp)
#endif
tp->t_timers = &tm->tt;
/* LIST_INIT(&tp->t_segq); */ /* XXX covered by M_ZERO */
- tp->t_maxseg = tp->t_maxopd =
+ tp->t_maxseg =
#ifdef INET6
isipv6 ? V_tcp_v6mssdflt :
#endif /* INET6 */
@@ -1901,7 +1901,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
* Only process the offered MTU if it
* is smaller than the current one.
*/
- if (mtu < tp->t_maxopd +
+ if (mtu < tp->t_maxseg +
sizeof(struct tcpiphdr)) {
bzero(&inc, sizeof(inc));
inc.inc_faddr = faddr;
@@ -2283,6 +2283,59 @@ tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap)
}
#endif /* INET6 */
+/*
+ * Calculate effective SMSS per RFC5681 definition for a given TCP
+ * connection at its current state, taking into account SACK and etc.
+ */
+u_int
+tcp_maxseg(const struct tcpcb *tp)
+{
+ u_int optlen;
+
+ if (tp->t_flags & TF_NOOPT)
+ return (tp->t_maxseg);
+
+ /*
+ * Here we have a simplified code from tcp_addoptions(),
+ * without a proper loop, and having most of paddings hardcoded.
+ * We might make mistakes with padding here in some edge cases,
+ * 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;
+ else
+ optlen = 0;
+#ifdef TCP_SIGNATURE
+ if (tp->t_flags & TF_SIGNATURE)
+ optlen += PAD(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);
+ }
+ } else {
+ if (tp->t_flags & TF_REQ_TSTMP)
+ optlen = TCPOLEN_TSTAMP_APPA;
+ else
+ optlen = PAD(TCPOLEN_MAXSEG);
+ if (tp->t_flags & TF_REQ_SCALE)
+ optlen += PAD(TCPOLEN_WINDOW);
+#ifdef TCP_SIGNATURE
+ if (tp->t_flags & TF_SIGNATURE)
+ optlen += PAD(TCPOLEN_SIGNATURE);
+#endif
+ if (tp->t_flags & TF_SACK_PERMIT)
+ optlen += PAD(TCPOLEN_SACK_PERMITTED);
+ }
+#undef PAD
+ optlen = min(optlen, TCP_MAXOLEN);
+ return (tp->t_maxseg - optlen);
+}
+
#ifdef IPSEC
/* compute ESP/AH header size for TCP, including outer IP header. */
size_t
OpenPOWER on IntegriCloud