diff options
author | Patrick Kelsey <pkelsey@FreeBSD.org> | 2018-02-26 02:53:22 +0000 |
---|---|---|
committer | Patrick Kelsey <pkelsey@FreeBSD.org> | 2018-02-26 02:53:22 +0000 |
commit | c560df6f12f1406a00b22a2e161a6a97d899fb03 (patch) | |
tree | 7503c1dcf4a722831f1f2b73e871551e1928168f /sys/netinet/tcp_output.c | |
parent | 798caa2ee5b5ede4eba0ac13c2ad70d79acedcb8 (diff) | |
download | src-c560df6f12f1406a00b22a2e161a6a97d899fb03.tar.gz src-c560df6f12f1406a00b22a2e161a6a97d899fb03.zip |
This is an implementation of the client side of TCP Fast Open (TFO)
[RFC7413]. It also includes a pre-shared key mode of operation in
which the server requires the client to be in possession of a shared
secret in order to successfully open TFO connections with that server.
The names of some existing fastopen sysctls have changed (e.g.,
net.inet.tcp.fastopen.enabled -> net.inet.tcp.fastopen.server_enable).
Reviewed by: tuexen
MFC after: 1 month
Sponsored by: Limelight Networks
Differential Revision: https://reviews.freebsd.org/D14047
Notes
Notes:
svn path=/head/; revision=330001
Diffstat (limited to 'sys/netinet/tcp_output.c')
-rw-r--r-- | sys/netinet/tcp_output.c | 84 |
1 files changed, 65 insertions, 19 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 66fe00d5a227..af76865b4d65 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -71,9 +71,6 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #endif -#ifdef TCP_RFC7413 -#include <netinet/tcp_fastopen.h> -#endif #include <netinet/tcp.h> #define TCPOUTFLAGS #include <netinet/tcp_fsm.h> @@ -82,6 +79,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcp_var.h> #include <netinet/tcpip.h> #include <netinet/cc/cc.h> +#ifdef TCP_RFC7413 +#include <netinet/tcp_fastopen.h> +#endif #ifdef TCPPCAP #include <netinet/tcp_pcap.h> #endif @@ -212,6 +212,10 @@ tcp_output(struct tcpcb *tp) struct sackhole *p; int tso, mtu; struct tcpopt to; +#ifdef TCP_RFC7413 + unsigned int wanted_cookie = 0; + unsigned int dont_sendalot = 0; +#endif #if 0 int maxburst = TCP_MAXBURST; #endif @@ -237,7 +241,7 @@ tcp_output(struct tcpcb *tp) if (IS_FASTOPEN(tp->t_flags) && (tp->t_state == TCPS_SYN_RECEIVED) && SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN|ACK sent */ - (tp->snd_nxt != tp->snd_una)) /* not a retransmit */ + (tp->snd_nxt != tp->snd_una)) /* not a retransmit */ return (0); #endif /* @@ -449,12 +453,21 @@ after_sack_rexmit: #ifdef TCP_RFC7413 /* - * When retransmitting SYN|ACK on a passively-created TFO socket, - * don't include data, as the presence of data may have caused the - * original SYN|ACK to have been dropped by a middlebox. + * On TFO sockets, ensure no data is sent in the following cases: + * + * - When retransmitting SYN|ACK on a passively-created socket + * + * - When retransmitting SYN on an actively created socket + * + * - When sending a zero-length cookie (cookie request) on an + * actively created socket + * + * - When the socket is in the CLOSED state (RST is being sent) */ if (IS_FASTOPEN(tp->t_flags) && - (((tp->t_state == TCPS_SYN_RECEIVED) && (tp->t_rxtshift > 0)) || + (((flags & TH_SYN) && (tp->t_rxtshift > 0)) || + ((tp->t_state == TCPS_SYN_SENT) && + (tp->t_tfo_client_cookie_len == 0)) || (flags & TH_RST))) len = 0; #endif @@ -541,7 +554,7 @@ after_sack_rexmit: if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg && ((tp->t_flags & TF_SIGNATURE) == 0) && tp->rcv_numsacks == 0 && sack_rxmit == 0 && - ipoptlen == 0) + ipoptlen == 0 && !(flags & TH_SYN)) tso = 1; if (sack_rxmit) { @@ -763,18 +776,36 @@ send: to.to_flags |= TOF_MSS; #ifdef TCP_RFC7413 /* - * Only include the TFO option on the first - * transmission of the SYN|ACK on a - * passively-created TFO socket, as the presence of - * the TFO option may have caused the original - * SYN|ACK to have been dropped by a middlebox. + * On SYN or SYN|ACK transmits on TFO connections, + * only include the TFO option if it is not a + * retransmit, as the presence of the TFO option may + * have caused the original SYN or SYN|ACK to have + * been dropped by a middlebox. */ if (IS_FASTOPEN(tp->t_flags) && - (tp->t_state == TCPS_SYN_RECEIVED) && (tp->t_rxtshift == 0)) { - to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; - to.to_tfo_cookie = (u_char *)&tp->t_tfo_cookie; - to.to_flags |= TOF_FASTOPEN; + if (tp->t_state == TCPS_SYN_RECEIVED) { + to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; + to.to_tfo_cookie = + (u_int8_t *)&tp->t_tfo_cookie.server; + to.to_flags |= TOF_FASTOPEN; + wanted_cookie = 1; + } else if (tp->t_state == TCPS_SYN_SENT) { + to.to_tfo_len = + tp->t_tfo_client_cookie_len; + to.to_tfo_cookie = + tp->t_tfo_cookie.client; + to.to_flags |= TOF_FASTOPEN; + wanted_cookie = 1; + /* + * If we wind up having more data to + * send with the SYN than can fit in + * one segment, don't send any more + * until the SYN|ACK comes back from + * the other end. + */ + dont_sendalot = 1; + } } #endif } @@ -820,6 +851,15 @@ send: /* Processing the options. */ hdrlen += optlen = tcp_addoptions(&to, opt); +#ifdef TCP_RFC7413 + /* + * If we wanted a TFO option to be added, but it was unable + * to fit, ensure no data is sent. + */ + if (IS_FASTOPEN(tp->t_flags) && wanted_cookie && + !(to.to_flags & TOF_FASTOPEN)) + len = 0; +#endif } /* @@ -964,6 +1004,10 @@ send: } else { len = tp->t_maxseg - optlen - ipoptlen; sendalot = 1; +#ifdef TCP_RFC7413 + if (dont_sendalot) + sendalot = 0; +#endif } } else tso = 0; @@ -1774,8 +1818,10 @@ tcp_addoptions(struct tcpopt *to, u_char *optp) /* XXX is there any point to aligning this option? */ total_len = TCPOLEN_FAST_OPEN_EMPTY + to->to_tfo_len; - if (TCP_MAXOLEN - optlen < total_len) + if (TCP_MAXOLEN - optlen < total_len) { + to->to_flags &= ~TOF_FASTOPEN; continue; + } *optp++ = TCPOPT_FAST_OPEN; *optp++ = total_len; if (to->to_tfo_len > 0) { |