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
This commit is contained in:
parent
798caa2ee5
commit
c560df6f12
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=330001
@ -456,6 +456,7 @@ TCP_HHOOK opt_inet.h
|
|||||||
TCP_OFFLOAD opt_inet.h # Enable code to dispatch TCP offloading
|
TCP_OFFLOAD opt_inet.h # Enable code to dispatch TCP offloading
|
||||||
TCP_RFC7413 opt_inet.h
|
TCP_RFC7413 opt_inet.h
|
||||||
TCP_RFC7413_MAX_KEYS opt_inet.h
|
TCP_RFC7413_MAX_KEYS opt_inet.h
|
||||||
|
TCP_RFC7413_MAX_PSKS opt_inet.h
|
||||||
TCP_SIGNATURE opt_ipsec.h
|
TCP_SIGNATURE opt_ipsec.h
|
||||||
VLAN_ARRAY opt_vlan.h
|
VLAN_ARRAY opt_vlan.h
|
||||||
XBONEHACK
|
XBONEHACK
|
||||||
|
@ -101,8 +101,6 @@ struct tcphdr {
|
|||||||
#define TCPOLEN_SIGNATURE 18
|
#define TCPOLEN_SIGNATURE 18
|
||||||
#define TCPOPT_FAST_OPEN 34
|
#define TCPOPT_FAST_OPEN 34
|
||||||
#define TCPOLEN_FAST_OPEN_EMPTY 2
|
#define TCPOLEN_FAST_OPEN_EMPTY 2
|
||||||
#define TCPOLEN_FAST_OPEN_MIN 6
|
|
||||||
#define TCPOLEN_FAST_OPEN_MAX 18
|
|
||||||
|
|
||||||
/* Miscellaneous constants */
|
/* Miscellaneous constants */
|
||||||
#define MAX_SACK_BLKS 6 /* Max # SACK blocks stored at receiver side */
|
#define MAX_SACK_BLKS 6 /* Max # SACK blocks stored at receiver side */
|
||||||
@ -152,6 +150,10 @@ struct tcphdr {
|
|||||||
#define TCP_MAXHLEN (0xf<<2) /* max length of header in bytes */
|
#define TCP_MAXHLEN (0xf<<2) /* max length of header in bytes */
|
||||||
#define TCP_MAXOLEN (TCP_MAXHLEN - sizeof(struct tcphdr))
|
#define TCP_MAXOLEN (TCP_MAXHLEN - sizeof(struct tcphdr))
|
||||||
/* max space left for options */
|
/* max space left for options */
|
||||||
|
|
||||||
|
#define TCP_FASTOPEN_MIN_COOKIE_LEN 4 /* Per RFC7413 */
|
||||||
|
#define TCP_FASTOPEN_MAX_COOKIE_LEN 16 /* Per RFC7413 */
|
||||||
|
#define TCP_FASTOPEN_PSK_LEN 16 /* Same as TCP_FASTOPEN_KEY_LEN */
|
||||||
#endif /* __BSD_VISIBLE */
|
#endif /* __BSD_VISIBLE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -252,6 +254,16 @@ struct tcp_info {
|
|||||||
/* Padding to grow without breaking ABI. */
|
/* Padding to grow without breaking ABI. */
|
||||||
u_int32_t __tcpi_pad[26]; /* Padding. */
|
u_int32_t __tcpi_pad[26]; /* Padding. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this structure is provided when setting the TCP_FASTOPEN socket
|
||||||
|
* option, and the enable member is non-zero, a subsequent connect will use
|
||||||
|
* pre-shared key (PSK) mode using the provided key.
|
||||||
|
*/
|
||||||
|
struct tcp_fastopen {
|
||||||
|
int enable;
|
||||||
|
uint8_t psk[TCP_FASTOPEN_PSK_LEN];
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
#define TCP_FUNCTION_NAME_LEN_MAX 32
|
#define TCP_FUNCTION_NAME_LEN_MAX 32
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2015 Patrick Kelsey
|
* Copyright (c) 2015-2017 Patrick Kelsey
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -25,23 +25,44 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a server-side implementation of TCP Fast Open (TFO) [RFC7413].
|
* This is an implementation of TCP Fast Open (TFO) [RFC7413]. To include
|
||||||
*
|
* this code, add the following line to your kernel config:
|
||||||
* This implementation is currently considered to be experimental and is not
|
|
||||||
* included in kernel builds by default. To include this code, add the
|
|
||||||
* following line to your kernel config:
|
|
||||||
*
|
*
|
||||||
* options TCP_RFC7413
|
* options TCP_RFC7413
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* The generated TFO cookies are the 64-bit output of
|
* The generated TFO cookies are the 64-bit output of
|
||||||
* SipHash24(<16-byte-key><client-ip>). Multiple concurrent valid keys are
|
* SipHash24(key=<16-byte-key>, msg=<client-ip>). Multiple concurrent valid
|
||||||
* supported so that time-based rolling cookie invalidation policies can be
|
* keys are supported so that time-based rolling cookie invalidation
|
||||||
* implemented in the system. The default number of concurrent keys is 2.
|
* policies can be implemented in the system. The default number of
|
||||||
* This can be adjusted in the kernel config as follows:
|
* concurrent keys is 2. This can be adjusted in the kernel config as
|
||||||
|
* follows:
|
||||||
*
|
*
|
||||||
* options TCP_RFC7413_MAX_KEYS=<num-keys>
|
* options TCP_RFC7413_MAX_KEYS=<num-keys>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
* In addition to the facilities defined in RFC7413, this implementation
|
||||||
|
* supports a pre-shared key (PSK) mode of operation in which the TFO server
|
||||||
|
* requires the client to be in posession of a shared secret in order for
|
||||||
|
* the client to be able to successfully open TFO connections with the
|
||||||
|
* server. This is useful, for example, in environments where TFO servers
|
||||||
|
* are exposed to both internal and external clients and only wish to allow
|
||||||
|
* TFO connections from internal clients.
|
||||||
|
*
|
||||||
|
* In the PSK mode of operation, the server generates and sends TFO cookies
|
||||||
|
* to requesting clients as usual. However, when validating cookies
|
||||||
|
* received in TFO SYNs from clients, the server requires the
|
||||||
|
* client-supplied cookie to equal SipHash24(key=<16-byte-psk>,
|
||||||
|
* msg=<cookie-sent-to-client>).
|
||||||
|
*
|
||||||
|
* Multiple concurrent valid pre-shared keys are supported so that
|
||||||
|
* time-based rolling PSK invalidation policies can be implemented in the
|
||||||
|
* system. The default number of concurrent pre-shared keys is 2. This can
|
||||||
|
* be adjusted in the kernel config as follows:
|
||||||
|
*
|
||||||
|
* options TCP_RFC7413_MAX_PSKS=<num-psks>
|
||||||
|
*
|
||||||
|
*
|
||||||
* The following TFO-specific sysctls are defined:
|
* The following TFO-specific sysctls are defined:
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.acceptany (RW, default 0)
|
* net.inet.tcp.fastopen.acceptany (RW, default 0)
|
||||||
@ -49,31 +70,72 @@
|
|||||||
* be valid.
|
* be valid.
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.autokey (RW, default 120)
|
* net.inet.tcp.fastopen.autokey (RW, default 120)
|
||||||
* When this and net.inet.tcp.fastopen.enabled are non-zero, a new key
|
* When this and net.inet.tcp.fastopen.server_enable are non-zero, a new
|
||||||
* will be automatically generated after this many seconds.
|
* key will be automatically generated after this many seconds.
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.enabled (RW, default 0)
|
* net.inet.tcp.fastopen.ccache_bucket_limit
|
||||||
* When zero, no new TFO connections can be created. On the transition
|
* (RWTUN, default TCP_FASTOPEN_CCACHE_BUCKET_LIMIT_DEFAULT)
|
||||||
* from enabled to disabled, all installed keys are removed. On the
|
* The maximum number of entries in a client cookie cache bucket.
|
||||||
* transition from disabled to enabled, if net.inet.tcp.fastopen.autokey
|
|
||||||
* is non-zero and there are no keys installed, a new key will be
|
|
||||||
* generated immediately. The transition from enabled to disabled does
|
|
||||||
* not affect any TFO connections in progress; it only prevents new ones
|
|
||||||
* from being made.
|
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.keylen (RO)
|
* net.inet.tcp.fastopen.ccache_buckets
|
||||||
|
* (RDTUN, default TCP_FASTOPEN_CCACHE_BUCKETS_DEFAULT)
|
||||||
|
* The number of client cookie cache buckets.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.client_enable (RW, default 0)
|
||||||
|
* When zero, no new active (i.e., client) TFO connections can be
|
||||||
|
* created. On the transition from enabled to disabled, the client
|
||||||
|
* cookie cache is cleared and disabled. The transition from enabled to
|
||||||
|
* disabled does not affect any active TFO connections in progress; it
|
||||||
|
* only prevents new ones from being made.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.keylen (RD)
|
||||||
* The key length in bytes.
|
* The key length in bytes.
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.maxkeys (RO)
|
* net.inet.tcp.fastopen.maxkeys (RD)
|
||||||
* The maximum number of keys supported.
|
* The maximum number of keys supported.
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.numkeys (RO)
|
* net.inet.tcp.fastopen.maxpsks (RD)
|
||||||
|
* The maximum number of pre-shared keys supported.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.numkeys (RD)
|
||||||
* The current number of keys installed.
|
* The current number of keys installed.
|
||||||
*
|
*
|
||||||
* net.inet.tcp.fastopen.setkey (WO)
|
* net.inet.tcp.fastopen.numpsks (RD)
|
||||||
* Install a new key by writing net.inet.tcp.fastopen.keylen bytes to this
|
* The current number of pre-shared keys installed.
|
||||||
* sysctl.
|
|
||||||
*
|
*
|
||||||
|
* net.inet.tcp.fastopen.path_disable_time
|
||||||
|
* (RW, default TCP_FASTOPEN_PATH_DISABLE_TIME_DEFAULT)
|
||||||
|
* When a failure occurs while trying to create a new active (i.e.,
|
||||||
|
* client) TFO connection, new active connections on the same path, as
|
||||||
|
* determined by the tuple {client_ip, server_ip, server_port}, will be
|
||||||
|
* forced to be non-TFO for this many seconds. Note that the path
|
||||||
|
* disable mechanism relies on state stored in client cookie cache
|
||||||
|
* entries, so it is possible for the disable time for a given path to
|
||||||
|
* be reduced if the corresponding client cookie cache entry is reused
|
||||||
|
* due to resource pressure before the disable period has elapsed.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.psk_enable (RW, default 0)
|
||||||
|
* When non-zero, pre-shared key (PSK) mode is enabled for all TFO
|
||||||
|
* servers. On the transition from enabled to disabled, all installed
|
||||||
|
* pre-shared keys are removed.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.server_enable (RW, default 0)
|
||||||
|
* When zero, no new passive (i.e., server) TFO connections can be
|
||||||
|
* created. On the transition from enabled to disabled, all installed
|
||||||
|
* keys and pre-shared keys are removed. On the transition from
|
||||||
|
* disabled to enabled, if net.inet.tcp.fastopen.autokey is non-zero and
|
||||||
|
* there are no keys installed, a new key will be generated immediately.
|
||||||
|
* The transition from enabled to disabled does not affect any passive
|
||||||
|
* TFO connections in progress; it only prevents new ones from being
|
||||||
|
* made.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.setkey (WR)
|
||||||
|
* Install a new key by writing net.inet.tcp.fastopen.keylen bytes to
|
||||||
|
* this sysctl.
|
||||||
|
*
|
||||||
|
* net.inet.tcp.fastopen.setpsk (WR)
|
||||||
|
* Install a new pre-shared key by writing net.inet.tcp.fastopen.keylen
|
||||||
|
* bytes to this sysctl.
|
||||||
*
|
*
|
||||||
* In order for TFO connections to be created via a listen socket, that
|
* In order for TFO connections to be created via a listen socket, that
|
||||||
* socket must have the TCP_FASTOPEN socket option set on it. This option
|
* socket must have the TCP_FASTOPEN socket option set on it. This option
|
||||||
@ -105,6 +167,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/hash.h>
|
||||||
#include <sys/limits.h>
|
#include <sys/limits.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/rmlock.h>
|
#include <sys/rmlock.h>
|
||||||
@ -119,21 +182,56 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/in_pcb.h>
|
#include <netinet/in_pcb.h>
|
||||||
#include <netinet/tcp_fastopen.h>
|
|
||||||
#include <netinet/tcp_var.h>
|
#include <netinet/tcp_var.h>
|
||||||
|
#include <netinet/tcp_fastopen.h>
|
||||||
|
|
||||||
|
|
||||||
#define TCP_FASTOPEN_KEY_LEN SIPHASH_KEY_LENGTH
|
#define TCP_FASTOPEN_KEY_LEN SIPHASH_KEY_LENGTH
|
||||||
|
|
||||||
|
#if TCP_FASTOPEN_PSK_LEN != TCP_FASTOPEN_KEY_LEN
|
||||||
|
#error TCP_FASTOPEN_PSK_LEN must be equal to TCP_FASTOPEN_KEY_LEN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because a PSK-mode setsockopt() uses tcpcb.t_tfo_cookie.client to hold
|
||||||
|
* the PSK until the connect occurs.
|
||||||
|
*/
|
||||||
|
#if TCP_FASTOPEN_MAX_COOKIE_LEN < TCP_FASTOPEN_PSK_LEN
|
||||||
|
#error TCP_FASTOPEN_MAX_COOKIE_LEN must be >= TCP_FASTOPEN_PSK_LEN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TCP_FASTOPEN_CCACHE_BUCKET_LIMIT_DEFAULT 16
|
||||||
|
#define TCP_FASTOPEN_CCACHE_BUCKETS_DEFAULT 2048 /* must be power of 2 */
|
||||||
|
|
||||||
|
#define TCP_FASTOPEN_PATH_DISABLE_TIME_DEFAULT 900 /* seconds */
|
||||||
|
|
||||||
#if !defined(TCP_RFC7413_MAX_KEYS) || (TCP_RFC7413_MAX_KEYS < 1)
|
#if !defined(TCP_RFC7413_MAX_KEYS) || (TCP_RFC7413_MAX_KEYS < 1)
|
||||||
#define TCP_FASTOPEN_MAX_KEYS 2
|
#define TCP_FASTOPEN_MAX_KEYS 2
|
||||||
#else
|
#else
|
||||||
#define TCP_FASTOPEN_MAX_KEYS TCP_RFC7413_MAX_KEYS
|
#define TCP_FASTOPEN_MAX_KEYS TCP_RFC7413_MAX_KEYS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TCP_FASTOPEN_MAX_KEYS > 10
|
||||||
|
#undef TCP_FASTOPEN_MAX_KEYS
|
||||||
|
#define TCP_FASTOPEN_MAX_KEYS 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(TCP_RFC7413_MAX_PSKS) || (TCP_RFC7413_MAX_PSKS < 1)
|
||||||
|
#define TCP_FASTOPEN_MAX_PSKS 2
|
||||||
|
#else
|
||||||
|
#define TCP_FASTOPEN_MAX_PSKS TCP_RFC7413_MAX_PSKS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TCP_FASTOPEN_MAX_PSKS > 10
|
||||||
|
#undef TCP_FASTOPEN_MAX_PSKS
|
||||||
|
#define TCP_FASTOPEN_MAX_PSKS 10
|
||||||
|
#endif
|
||||||
|
|
||||||
struct tcp_fastopen_keylist {
|
struct tcp_fastopen_keylist {
|
||||||
unsigned int newest;
|
unsigned int newest;
|
||||||
|
unsigned int newest_psk;
|
||||||
uint8_t key[TCP_FASTOPEN_MAX_KEYS][TCP_FASTOPEN_KEY_LEN];
|
uint8_t key[TCP_FASTOPEN_MAX_KEYS][TCP_FASTOPEN_KEY_LEN];
|
||||||
|
uint8_t psk[TCP_FASTOPEN_MAX_PSKS][TCP_FASTOPEN_KEY_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcp_fastopen_callout {
|
struct tcp_fastopen_callout {
|
||||||
@ -141,6 +239,16 @@ struct tcp_fastopen_callout {
|
|||||||
struct vnet *v;
|
struct vnet *v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct tcp_fastopen_ccache_entry *tcp_fastopen_ccache_lookup(
|
||||||
|
struct in_conninfo *, struct tcp_fastopen_ccache_bucket **);
|
||||||
|
static struct tcp_fastopen_ccache_entry *tcp_fastopen_ccache_create(
|
||||||
|
struct tcp_fastopen_ccache_bucket *, struct in_conninfo *, uint16_t, uint8_t,
|
||||||
|
uint8_t *);
|
||||||
|
static void tcp_fastopen_ccache_bucket_trim(struct tcp_fastopen_ccache_bucket *,
|
||||||
|
unsigned int);
|
||||||
|
static void tcp_fastopen_ccache_entry_drop(struct tcp_fastopen_ccache_entry *,
|
||||||
|
struct tcp_fastopen_ccache_bucket *);
|
||||||
|
|
||||||
SYSCTL_NODE(_net_inet_tcp, OID_AUTO, fastopen, CTLFLAG_RW, 0, "TCP Fast Open");
|
SYSCTL_NODE(_net_inet_tcp, OID_AUTO, fastopen, CTLFLAG_RW, 0, "TCP Fast Open");
|
||||||
|
|
||||||
static VNET_DEFINE(int, tcp_fastopen_acceptany) = 0;
|
static VNET_DEFINE(int, tcp_fastopen_acceptany) = 0;
|
||||||
@ -157,12 +265,25 @@ SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, autokey,
|
|||||||
&sysctl_net_inet_tcp_fastopen_autokey, "IU",
|
&sysctl_net_inet_tcp_fastopen_autokey, "IU",
|
||||||
"Number of seconds between auto-generation of a new key; zero disables");
|
"Number of seconds between auto-generation of a new key; zero disables");
|
||||||
|
|
||||||
VNET_DEFINE(unsigned int, tcp_fastopen_enabled) = 0;
|
static int sysctl_net_inet_tcp_fastopen_ccache_bucket_limit(SYSCTL_HANDLER_ARGS);
|
||||||
static int sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS);
|
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, ccache_bucket_limit,
|
||||||
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, enabled,
|
CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RWTUN, NULL, 0,
|
||||||
|
&sysctl_net_inet_tcp_fastopen_ccache_bucket_limit, "IU",
|
||||||
|
"Max entries per bucket in client cookie cache");
|
||||||
|
|
||||||
|
static VNET_DEFINE(unsigned int, tcp_fastopen_ccache_buckets) =
|
||||||
|
TCP_FASTOPEN_CCACHE_BUCKETS_DEFAULT;
|
||||||
|
#define V_tcp_fastopen_ccache_buckets VNET(tcp_fastopen_ccache_buckets)
|
||||||
|
SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, ccache_buckets,
|
||||||
|
CTLFLAG_VNET | CTLFLAG_RDTUN, &VNET_NAME(tcp_fastopen_ccache_buckets), 0,
|
||||||
|
"Client cookie cache number of buckets (power of 2)");
|
||||||
|
|
||||||
|
VNET_DEFINE(unsigned int, tcp_fastopen_client_enable) = 0;
|
||||||
|
static int sysctl_net_inet_tcp_fastopen_client_enable(SYSCTL_HANDLER_ARGS);
|
||||||
|
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, client_enable,
|
||||||
CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
|
CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
|
||||||
&sysctl_net_inet_tcp_fastopen_enabled, "IU",
|
&sysctl_net_inet_tcp_fastopen_client_enable, "IU",
|
||||||
"Enable/disable TCP Fast Open processing");
|
"Enable/disable TCP Fast Open client functionality");
|
||||||
|
|
||||||
SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, keylen,
|
SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, keylen,
|
||||||
CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_KEY_LEN,
|
CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_KEY_LEN,
|
||||||
@ -172,18 +293,56 @@ SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, maxkeys,
|
|||||||
CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_MAX_KEYS,
|
CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_MAX_KEYS,
|
||||||
"Maximum number of keys supported");
|
"Maximum number of keys supported");
|
||||||
|
|
||||||
|
SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, maxpsks,
|
||||||
|
CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_MAX_PSKS,
|
||||||
|
"Maximum number of pre-shared keys supported");
|
||||||
|
|
||||||
static VNET_DEFINE(unsigned int, tcp_fastopen_numkeys) = 0;
|
static VNET_DEFINE(unsigned int, tcp_fastopen_numkeys) = 0;
|
||||||
#define V_tcp_fastopen_numkeys VNET(tcp_fastopen_numkeys)
|
#define V_tcp_fastopen_numkeys VNET(tcp_fastopen_numkeys)
|
||||||
SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, numkeys,
|
SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, numkeys,
|
||||||
CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(tcp_fastopen_numkeys), 0,
|
CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(tcp_fastopen_numkeys), 0,
|
||||||
"Number of keys installed");
|
"Number of keys installed");
|
||||||
|
|
||||||
|
static VNET_DEFINE(unsigned int, tcp_fastopen_numpsks) = 0;
|
||||||
|
#define V_tcp_fastopen_numpsks VNET(tcp_fastopen_numpsks)
|
||||||
|
SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, numpsks,
|
||||||
|
CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(tcp_fastopen_numpsks), 0,
|
||||||
|
"Number of pre-shared keys installed");
|
||||||
|
|
||||||
|
static VNET_DEFINE(unsigned int, tcp_fastopen_path_disable_time) =
|
||||||
|
TCP_FASTOPEN_PATH_DISABLE_TIME_DEFAULT;
|
||||||
|
#define V_tcp_fastopen_path_disable_time VNET(tcp_fastopen_path_disable_time)
|
||||||
|
SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, path_disable_time,
|
||||||
|
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_fastopen_path_disable_time), 0,
|
||||||
|
"Seconds a TFO failure disables a {client_ip, server_ip, server_port} path");
|
||||||
|
|
||||||
|
static VNET_DEFINE(unsigned int, tcp_fastopen_psk_enable) = 0;
|
||||||
|
#define V_tcp_fastopen_psk_enable VNET(tcp_fastopen_psk_enable)
|
||||||
|
static int sysctl_net_inet_tcp_fastopen_psk_enable(SYSCTL_HANDLER_ARGS);
|
||||||
|
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, psk_enable,
|
||||||
|
CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
|
||||||
|
&sysctl_net_inet_tcp_fastopen_psk_enable, "IU",
|
||||||
|
"Enable/disable TCP Fast Open server pre-shared key mode");
|
||||||
|
|
||||||
|
VNET_DEFINE(unsigned int, tcp_fastopen_server_enable) = 0;
|
||||||
|
static int sysctl_net_inet_tcp_fastopen_server_enable(SYSCTL_HANDLER_ARGS);
|
||||||
|
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, server_enable,
|
||||||
|
CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
|
||||||
|
&sysctl_net_inet_tcp_fastopen_server_enable, "IU",
|
||||||
|
"Enable/disable TCP Fast Open server functionality");
|
||||||
|
|
||||||
static int sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS);
|
static int sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS);
|
||||||
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, setkey,
|
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, setkey,
|
||||||
CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0,
|
CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0,
|
||||||
&sysctl_net_inet_tcp_fastopen_setkey, "",
|
&sysctl_net_inet_tcp_fastopen_setkey, "",
|
||||||
"Install a new key");
|
"Install a new key");
|
||||||
|
|
||||||
|
static int sysctl_net_inet_tcp_fastopen_setpsk(SYSCTL_HANDLER_ARGS);
|
||||||
|
SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, setpsk,
|
||||||
|
CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0,
|
||||||
|
&sysctl_net_inet_tcp_fastopen_setpsk, "",
|
||||||
|
"Install a new pre-shared key");
|
||||||
|
|
||||||
static VNET_DEFINE(struct rmlock, tcp_fastopen_keylock);
|
static VNET_DEFINE(struct rmlock, tcp_fastopen_keylock);
|
||||||
#define V_tcp_fastopen_keylock VNET(tcp_fastopen_keylock)
|
#define V_tcp_fastopen_keylock VNET(tcp_fastopen_keylock)
|
||||||
|
|
||||||
@ -201,9 +360,21 @@ static VNET_DEFINE(struct tcp_fastopen_callout, tcp_fastopen_autokey_ctx);
|
|||||||
static VNET_DEFINE(uma_zone_t, counter_zone);
|
static VNET_DEFINE(uma_zone_t, counter_zone);
|
||||||
#define V_counter_zone VNET(counter_zone)
|
#define V_counter_zone VNET(counter_zone)
|
||||||
|
|
||||||
|
static MALLOC_DEFINE(M_TCP_FASTOPEN_CCACHE, "tfo_ccache", "TFO client cookie cache buckets");
|
||||||
|
|
||||||
|
static VNET_DEFINE(struct tcp_fastopen_ccache, tcp_fastopen_ccache);
|
||||||
|
#define V_tcp_fastopen_ccache VNET(tcp_fastopen_ccache)
|
||||||
|
|
||||||
|
#define CCB_LOCK(ccb) mtx_lock(&(ccb)->ccb_mtx)
|
||||||
|
#define CCB_UNLOCK(ccb) mtx_unlock(&(ccb)->ccb_mtx)
|
||||||
|
#define CCB_LOCK_ASSERT(ccb) mtx_assert(&(ccb)->ccb_mtx, MA_OWNED)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tcp_fastopen_init(void)
|
tcp_fastopen_init(void)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
V_counter_zone = uma_zcreate("tfo", sizeof(unsigned int),
|
V_counter_zone = uma_zcreate("tfo", sizeof(unsigned int),
|
||||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
||||||
rm_init(&V_tcp_fastopen_keylock, "tfo_keylock");
|
rm_init(&V_tcp_fastopen_keylock, "tfo_keylock");
|
||||||
@ -211,11 +382,67 @@ tcp_fastopen_init(void)
|
|||||||
&V_tcp_fastopen_keylock, 0);
|
&V_tcp_fastopen_keylock, 0);
|
||||||
V_tcp_fastopen_autokey_ctx.v = curvnet;
|
V_tcp_fastopen_autokey_ctx.v = curvnet;
|
||||||
V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
|
V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
|
||||||
|
V_tcp_fastopen_keys.newest_psk = TCP_FASTOPEN_MAX_PSKS - 1;
|
||||||
|
|
||||||
|
/* May already be non-zero if kernel tunable was set */
|
||||||
|
if (V_tcp_fastopen_ccache.bucket_limit == 0)
|
||||||
|
V_tcp_fastopen_ccache.bucket_limit =
|
||||||
|
TCP_FASTOPEN_CCACHE_BUCKET_LIMIT_DEFAULT;
|
||||||
|
|
||||||
|
/* May already be non-zero if kernel tunable was set */
|
||||||
|
if ((V_tcp_fastopen_ccache_buckets == 0) ||
|
||||||
|
!powerof2(V_tcp_fastopen_ccache_buckets))
|
||||||
|
V_tcp_fastopen_ccache.buckets =
|
||||||
|
TCP_FASTOPEN_CCACHE_BUCKETS_DEFAULT;
|
||||||
|
else
|
||||||
|
V_tcp_fastopen_ccache.buckets = V_tcp_fastopen_ccache_buckets;
|
||||||
|
|
||||||
|
V_tcp_fastopen_ccache.mask = V_tcp_fastopen_ccache.buckets - 1;
|
||||||
|
V_tcp_fastopen_ccache.secret = arc4random();
|
||||||
|
|
||||||
|
V_tcp_fastopen_ccache.base = malloc(V_tcp_fastopen_ccache.buckets *
|
||||||
|
sizeof(struct tcp_fastopen_ccache_bucket), M_TCP_FASTOPEN_CCACHE,
|
||||||
|
M_WAITOK | M_ZERO);
|
||||||
|
|
||||||
|
for (i = 0; i < V_tcp_fastopen_ccache.buckets; i++) {
|
||||||
|
TAILQ_INIT(&V_tcp_fastopen_ccache.base[i].ccb_entries);
|
||||||
|
mtx_init(&V_tcp_fastopen_ccache.base[i].ccb_mtx, "tfo_ccache_bucket",
|
||||||
|
NULL, MTX_DEF);
|
||||||
|
V_tcp_fastopen_ccache.base[i].ccb_num_entries = -1; /* bucket disabled */
|
||||||
|
V_tcp_fastopen_ccache.base[i].ccb_ccache = &V_tcp_fastopen_ccache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that while the total number of entries in the cookie cache
|
||||||
|
* is limited by the table management logic to
|
||||||
|
* V_tcp_fastopen_ccache.buckets *
|
||||||
|
* V_tcp_fastopen_ccache.bucket_limit, the total number of items in
|
||||||
|
* this zone can exceed that amount by the number of CPUs in the
|
||||||
|
* system times the maximum number of unallocated items that can be
|
||||||
|
* present in each UMA per-CPU cache for this zone.
|
||||||
|
*/
|
||||||
|
V_tcp_fastopen_ccache.zone = uma_zcreate("tfo_ccache_entries",
|
||||||
|
sizeof(struct tcp_fastopen_ccache_entry), NULL, NULL, NULL, NULL,
|
||||||
|
UMA_ALIGN_CACHE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tcp_fastopen_destroy(void)
|
tcp_fastopen_destroy(void)
|
||||||
{
|
{
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < V_tcp_fastopen_ccache.buckets; i++) {
|
||||||
|
ccb = &V_tcp_fastopen_ccache.base[i];
|
||||||
|
tcp_fastopen_ccache_bucket_trim(ccb, 0);
|
||||||
|
mtx_destroy(&ccb->ccb_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(uma_zone_get_cur(V_tcp_fastopen_ccache.zone) == 0,
|
||||||
|
("%s: TFO ccache zone allocation count not 0", __func__));
|
||||||
|
uma_zdestroy(V_tcp_fastopen_ccache.zone);
|
||||||
|
free(V_tcp_fastopen_ccache.base, M_TCP_FASTOPEN_CCACHE);
|
||||||
|
|
||||||
callout_drain(&V_tcp_fastopen_autokey_ctx.c);
|
callout_drain(&V_tcp_fastopen_autokey_ctx.c);
|
||||||
rm_destroy(&V_tcp_fastopen_keylock);
|
rm_destroy(&V_tcp_fastopen_keylock);
|
||||||
uma_zdestroy(V_counter_zone);
|
uma_zdestroy(V_counter_zone);
|
||||||
@ -253,6 +480,19 @@ tcp_fastopen_addkey_locked(uint8_t *key)
|
|||||||
V_tcp_fastopen_numkeys++;
|
V_tcp_fastopen_numkeys++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tcp_fastopen_addpsk_locked(uint8_t *psk)
|
||||||
|
{
|
||||||
|
|
||||||
|
V_tcp_fastopen_keys.newest_psk++;
|
||||||
|
if (V_tcp_fastopen_keys.newest_psk == TCP_FASTOPEN_MAX_PSKS)
|
||||||
|
V_tcp_fastopen_keys.newest_psk = 0;
|
||||||
|
memcpy(V_tcp_fastopen_keys.psk[V_tcp_fastopen_keys.newest_psk], psk,
|
||||||
|
TCP_FASTOPEN_KEY_LEN);
|
||||||
|
if (V_tcp_fastopen_numpsks < TCP_FASTOPEN_MAX_PSKS)
|
||||||
|
V_tcp_fastopen_numpsks++;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tcp_fastopen_autokey_locked(void)
|
tcp_fastopen_autokey_locked(void)
|
||||||
{
|
{
|
||||||
@ -300,6 +540,49 @@ tcp_fastopen_make_cookie(uint8_t key[SIPHASH_KEY_LENGTH], struct in_conninfo *in
|
|||||||
return (siphash);
|
return (siphash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
tcp_fastopen_make_psk_cookie(uint8_t *psk, uint8_t *cookie, uint8_t cookie_len)
|
||||||
|
{
|
||||||
|
SIPHASH_CTX ctx;
|
||||||
|
uint64_t psk_cookie;
|
||||||
|
|
||||||
|
SipHash24_Init(&ctx);
|
||||||
|
SipHash_SetKey(&ctx, psk);
|
||||||
|
SipHash_Update(&ctx, cookie, cookie_len);
|
||||||
|
SipHash_Final((u_int8_t *)&psk_cookie, &ctx);
|
||||||
|
|
||||||
|
return (psk_cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tcp_fastopen_find_cookie_match_locked(uint8_t *wire_cookie, uint64_t *cur_cookie)
|
||||||
|
{
|
||||||
|
unsigned int i, psk_index;
|
||||||
|
uint64_t psk_cookie;
|
||||||
|
|
||||||
|
if (V_tcp_fastopen_psk_enable) {
|
||||||
|
psk_index = V_tcp_fastopen_keys.newest_psk;
|
||||||
|
for (i = 0; i < V_tcp_fastopen_numpsks; i++) {
|
||||||
|
psk_cookie =
|
||||||
|
tcp_fastopen_make_psk_cookie(
|
||||||
|
V_tcp_fastopen_keys.psk[psk_index],
|
||||||
|
(uint8_t *)cur_cookie,
|
||||||
|
TCP_FASTOPEN_COOKIE_LEN);
|
||||||
|
|
||||||
|
if (memcmp(wire_cookie, &psk_cookie,
|
||||||
|
TCP_FASTOPEN_COOKIE_LEN) == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (psk_index == 0)
|
||||||
|
psk_index = TCP_FASTOPEN_MAX_PSKS - 1;
|
||||||
|
else
|
||||||
|
psk_index--;
|
||||||
|
}
|
||||||
|
} else if (memcmp(wire_cookie, cur_cookie, TCP_FASTOPEN_COOKIE_LEN) == 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return values:
|
* Return values:
|
||||||
@ -344,10 +627,9 @@ tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie,
|
|||||||
inc);
|
inc);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
*latest_cookie = cur_cookie;
|
*latest_cookie = cur_cookie;
|
||||||
if (memcmp(cookie, &cur_cookie, TCP_FASTOPEN_COOKIE_LEN) == 0) {
|
rv = tcp_fastopen_find_cookie_match_locked(cookie, &cur_cookie);
|
||||||
rv = 1;
|
if (rv)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
if (key_index == 0)
|
if (key_index == 0)
|
||||||
key_index = TCP_FASTOPEN_MAX_KEYS - 1;
|
key_index = TCP_FASTOPEN_MAX_KEYS - 1;
|
||||||
else
|
else
|
||||||
@ -355,7 +637,7 @@ tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie,
|
|||||||
}
|
}
|
||||||
rv = 0;
|
rv = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
TCP_FASTOPEN_KEYS_RUNLOCK(&tracker);
|
TCP_FASTOPEN_KEYS_RUNLOCK(&tracker);
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
@ -373,7 +655,7 @@ sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS)
|
|||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
|
||||||
TCP_FASTOPEN_KEYS_WLOCK();
|
TCP_FASTOPEN_KEYS_WLOCK();
|
||||||
if (V_tcp_fastopen_enabled) {
|
if (V_tcp_fastopen_server_enable) {
|
||||||
if (V_tcp_fastopen_autokey && !new)
|
if (V_tcp_fastopen_autokey && !new)
|
||||||
callout_stop(&V_tcp_fastopen_autokey_ctx.c);
|
callout_stop(&V_tcp_fastopen_autokey_ctx.c);
|
||||||
else if (new)
|
else if (new)
|
||||||
@ -389,24 +671,54 @@ sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS)
|
sysctl_net_inet_tcp_fastopen_psk_enable(SYSCTL_HANDLER_ARGS)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
unsigned int new;
|
unsigned int new;
|
||||||
|
|
||||||
new = V_tcp_fastopen_enabled;
|
new = V_tcp_fastopen_psk_enable;
|
||||||
error = sysctl_handle_int(oidp, &new, 0, req);
|
error = sysctl_handle_int(oidp, &new, 0, req);
|
||||||
if (error == 0 && req->newptr) {
|
if (error == 0 && req->newptr) {
|
||||||
if (V_tcp_fastopen_enabled && !new) {
|
if (V_tcp_fastopen_psk_enable && !new) {
|
||||||
|
/* enabled -> disabled */
|
||||||
|
TCP_FASTOPEN_KEYS_WLOCK();
|
||||||
|
V_tcp_fastopen_numpsks = 0;
|
||||||
|
V_tcp_fastopen_keys.newest_psk =
|
||||||
|
TCP_FASTOPEN_MAX_PSKS - 1;
|
||||||
|
V_tcp_fastopen_psk_enable = 0;
|
||||||
|
TCP_FASTOPEN_KEYS_WUNLOCK();
|
||||||
|
} else if (!V_tcp_fastopen_psk_enable && new) {
|
||||||
|
/* disabled -> enabled */
|
||||||
|
TCP_FASTOPEN_KEYS_WLOCK();
|
||||||
|
V_tcp_fastopen_psk_enable = 1;
|
||||||
|
TCP_FASTOPEN_KEYS_WUNLOCK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sysctl_net_inet_tcp_fastopen_server_enable(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
unsigned int new;
|
||||||
|
|
||||||
|
new = V_tcp_fastopen_server_enable;
|
||||||
|
error = sysctl_handle_int(oidp, &new, 0, req);
|
||||||
|
if (error == 0 && req->newptr) {
|
||||||
|
if (V_tcp_fastopen_server_enable && !new) {
|
||||||
/* enabled -> disabled */
|
/* enabled -> disabled */
|
||||||
TCP_FASTOPEN_KEYS_WLOCK();
|
TCP_FASTOPEN_KEYS_WLOCK();
|
||||||
V_tcp_fastopen_numkeys = 0;
|
V_tcp_fastopen_numkeys = 0;
|
||||||
V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
|
V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
|
||||||
if (V_tcp_fastopen_autokey)
|
if (V_tcp_fastopen_autokey)
|
||||||
callout_stop(&V_tcp_fastopen_autokey_ctx.c);
|
callout_stop(&V_tcp_fastopen_autokey_ctx.c);
|
||||||
V_tcp_fastopen_enabled = 0;
|
V_tcp_fastopen_numpsks = 0;
|
||||||
|
V_tcp_fastopen_keys.newest_psk =
|
||||||
|
TCP_FASTOPEN_MAX_PSKS - 1;
|
||||||
|
V_tcp_fastopen_server_enable = 0;
|
||||||
TCP_FASTOPEN_KEYS_WUNLOCK();
|
TCP_FASTOPEN_KEYS_WUNLOCK();
|
||||||
} else if (!V_tcp_fastopen_enabled && new) {
|
} else if (!V_tcp_fastopen_server_enable && new) {
|
||||||
/* disabled -> enabled */
|
/* disabled -> enabled */
|
||||||
TCP_FASTOPEN_KEYS_WLOCK();
|
TCP_FASTOPEN_KEYS_WLOCK();
|
||||||
if (V_tcp_fastopen_autokey &&
|
if (V_tcp_fastopen_autokey &&
|
||||||
@ -417,7 +729,7 @@ sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS)
|
|||||||
tcp_fastopen_autokey_callout,
|
tcp_fastopen_autokey_callout,
|
||||||
&V_tcp_fastopen_autokey_ctx);
|
&V_tcp_fastopen_autokey_ctx);
|
||||||
}
|
}
|
||||||
V_tcp_fastopen_enabled = 1;
|
V_tcp_fastopen_server_enable = 1;
|
||||||
TCP_FASTOPEN_KEYS_WUNLOCK();
|
TCP_FASTOPEN_KEYS_WUNLOCK();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,3 +758,369 @@ sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS)
|
|||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sysctl_net_inet_tcp_fastopen_setpsk(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
uint8_t newpsk[TCP_FASTOPEN_KEY_LEN];
|
||||||
|
|
||||||
|
if (req->oldptr != NULL || req->oldlen != 0)
|
||||||
|
return (EINVAL);
|
||||||
|
if (req->newptr == NULL)
|
||||||
|
return (EPERM);
|
||||||
|
if (req->newlen != sizeof(newpsk))
|
||||||
|
return (EINVAL);
|
||||||
|
error = SYSCTL_IN(req, newpsk, sizeof(newpsk));
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
TCP_FASTOPEN_KEYS_WLOCK();
|
||||||
|
tcp_fastopen_addpsk_locked(newpsk);
|
||||||
|
TCP_FASTOPEN_KEYS_WUNLOCK();
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sysctl_net_inet_tcp_fastopen_ccache_bucket_limit(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
int error;
|
||||||
|
unsigned int new;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
new = V_tcp_fastopen_ccache.bucket_limit;
|
||||||
|
error = sysctl_handle_int(oidp, &new, 0, req);
|
||||||
|
if (error == 0 && req->newptr) {
|
||||||
|
if ((new == 0) || (new > INT_MAX))
|
||||||
|
error = EINVAL;
|
||||||
|
else {
|
||||||
|
if (new < V_tcp_fastopen_ccache.bucket_limit) {
|
||||||
|
for (i = 0; i < V_tcp_fastopen_ccache.buckets;
|
||||||
|
i++) {
|
||||||
|
ccb = &V_tcp_fastopen_ccache.base[i];
|
||||||
|
tcp_fastopen_ccache_bucket_trim(ccb, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
V_tcp_fastopen_ccache.bucket_limit = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sysctl_net_inet_tcp_fastopen_client_enable(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
int error;
|
||||||
|
unsigned int new, i;
|
||||||
|
|
||||||
|
new = V_tcp_fastopen_client_enable;
|
||||||
|
error = sysctl_handle_int(oidp, &new, 0, req);
|
||||||
|
if (error == 0 && req->newptr) {
|
||||||
|
if (V_tcp_fastopen_client_enable && !new) {
|
||||||
|
/* enabled -> disabled */
|
||||||
|
for (i = 0; i < V_tcp_fastopen_ccache.buckets; i++) {
|
||||||
|
ccb = &V_tcp_fastopen_ccache.base[i];
|
||||||
|
tcp_fastopen_ccache_bucket_trim(ccb, 0);
|
||||||
|
}
|
||||||
|
V_tcp_fastopen_client_enable = 0;
|
||||||
|
} else if (!V_tcp_fastopen_client_enable && new) {
|
||||||
|
/* disabled -> enabled */
|
||||||
|
for (i = 0; i < V_tcp_fastopen_ccache.buckets; i++) {
|
||||||
|
ccb = &V_tcp_fastopen_ccache.base[i];
|
||||||
|
CCB_LOCK(ccb);
|
||||||
|
KASSERT(TAILQ_EMPTY(&ccb->ccb_entries),
|
||||||
|
("%s: ccb->ccb_entries not empty", __func__));
|
||||||
|
KASSERT(ccb->ccb_num_entries == -1,
|
||||||
|
("%s: ccb->ccb_num_entries %d not -1", __func__,
|
||||||
|
ccb->ccb_num_entries));
|
||||||
|
ccb->ccb_num_entries = 0; /* enable bucket */
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
}
|
||||||
|
V_tcp_fastopen_client_enable = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcp_fastopen_connect(struct tcpcb *tp)
|
||||||
|
{
|
||||||
|
struct inpcb *inp;
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
struct tcp_fastopen_ccache_entry *cce;
|
||||||
|
sbintime_t now;
|
||||||
|
uint16_t server_mss;
|
||||||
|
uint64_t psk_cookie;
|
||||||
|
|
||||||
|
inp = tp->t_inpcb;
|
||||||
|
cce = tcp_fastopen_ccache_lookup(&inp->inp_inc, &ccb);
|
||||||
|
if (cce) {
|
||||||
|
if (cce->disable_time == 0) {
|
||||||
|
if ((cce->cookie_len > 0) &&
|
||||||
|
(tp->t_tfo_client_cookie_len ==
|
||||||
|
TCP_FASTOPEN_PSK_LEN)) {
|
||||||
|
psk_cookie =
|
||||||
|
tcp_fastopen_make_psk_cookie(
|
||||||
|
tp->t_tfo_cookie.client,
|
||||||
|
cce->cookie, cce->cookie_len);
|
||||||
|
} else {
|
||||||
|
tp->t_tfo_client_cookie_len = cce->cookie_len;
|
||||||
|
memcpy(tp->t_tfo_cookie.client, cce->cookie,
|
||||||
|
cce->cookie_len);
|
||||||
|
}
|
||||||
|
server_mss = cce->server_mss;
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
if (tp->t_tfo_client_cookie_len ==
|
||||||
|
TCP_FASTOPEN_PSK_LEN) {
|
||||||
|
tp->t_tfo_client_cookie_len =
|
||||||
|
TCP_FASTOPEN_COOKIE_LEN;
|
||||||
|
memcpy(tp->t_tfo_cookie.client, &psk_cookie,
|
||||||
|
TCP_FASTOPEN_COOKIE_LEN);
|
||||||
|
}
|
||||||
|
tcp_mss(tp, server_mss ? server_mss : -1);
|
||||||
|
tp->snd_wnd = tp->t_maxseg;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The path is disabled. Check the time and
|
||||||
|
* possibly re-enable.
|
||||||
|
*/
|
||||||
|
now = getsbinuptime();
|
||||||
|
if (now - cce->disable_time >
|
||||||
|
((sbintime_t)V_tcp_fastopen_path_disable_time << 32)) {
|
||||||
|
/*
|
||||||
|
* Re-enable path. Force a TFO cookie
|
||||||
|
* request. Forget the old MSS as it may be
|
||||||
|
* bogus now, and we will rediscover it in
|
||||||
|
* the SYN|ACK.
|
||||||
|
*/
|
||||||
|
cce->disable_time = 0;
|
||||||
|
cce->server_mss = 0;
|
||||||
|
cce->cookie_len = 0;
|
||||||
|
/*
|
||||||
|
* tp->t_tfo... cookie details are already
|
||||||
|
* zero from the tcpcb init.
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Path is disabled, so disable TFO on this
|
||||||
|
* connection.
|
||||||
|
*/
|
||||||
|
tp->t_flags &= ~TF_FASTOPEN;
|
||||||
|
}
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
tcp_mss(tp, -1);
|
||||||
|
/*
|
||||||
|
* snd_wnd is irrelevant since we are either forcing
|
||||||
|
* a TFO cookie request or disabling TFO - either
|
||||||
|
* way, no data with the SYN.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* A new entry for this path will be created when a SYN|ACK
|
||||||
|
* comes back, or the attempt otherwise fails.
|
||||||
|
*/
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
tcp_mss(tp, -1);
|
||||||
|
/*
|
||||||
|
* snd_wnd is irrelevant since we are forcing a TFO cookie
|
||||||
|
* request.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcp_fastopen_disable_path(struct tcpcb *tp)
|
||||||
|
{
|
||||||
|
struct in_conninfo *inc = &tp->t_inpcb->inp_inc;
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
struct tcp_fastopen_ccache_entry *cce;
|
||||||
|
|
||||||
|
cce = tcp_fastopen_ccache_lookup(inc, &ccb);
|
||||||
|
if (cce) {
|
||||||
|
cce->server_mss = 0;
|
||||||
|
cce->cookie_len = 0;
|
||||||
|
/*
|
||||||
|
* Preserve the existing disable time if it is already
|
||||||
|
* disabled.
|
||||||
|
*/
|
||||||
|
if (cce->disable_time == 0)
|
||||||
|
cce->disable_time = getsbinuptime();
|
||||||
|
} else /* use invalid cookie len to create disabled entry */
|
||||||
|
tcp_fastopen_ccache_create(ccb, inc, 0,
|
||||||
|
TCP_FASTOPEN_MAX_COOKIE_LEN + 1, NULL);
|
||||||
|
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
tp->t_flags &= ~TF_FASTOPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcp_fastopen_update_cache(struct tcpcb *tp, uint16_t mss,
|
||||||
|
uint8_t cookie_len, uint8_t *cookie)
|
||||||
|
{
|
||||||
|
struct in_conninfo *inc = &tp->t_inpcb->inp_inc;
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
struct tcp_fastopen_ccache_entry *cce;
|
||||||
|
|
||||||
|
cce = tcp_fastopen_ccache_lookup(inc, &ccb);
|
||||||
|
if (cce) {
|
||||||
|
if ((cookie_len >= TCP_FASTOPEN_MIN_COOKIE_LEN) &&
|
||||||
|
(cookie_len <= TCP_FASTOPEN_MAX_COOKIE_LEN) &&
|
||||||
|
((cookie_len & 0x1) == 0)) {
|
||||||
|
cce->server_mss = mss;
|
||||||
|
cce->cookie_len = cookie_len;
|
||||||
|
memcpy(cce->cookie, cookie, cookie_len);
|
||||||
|
cce->disable_time = 0;
|
||||||
|
} else {
|
||||||
|
/* invalid cookie length, disable entry */
|
||||||
|
cce->server_mss = 0;
|
||||||
|
cce->cookie_len = 0;
|
||||||
|
/*
|
||||||
|
* Preserve the existing disable time if it is
|
||||||
|
* already disabled.
|
||||||
|
*/
|
||||||
|
if (cce->disable_time == 0)
|
||||||
|
cce->disable_time = getsbinuptime();
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
tcp_fastopen_ccache_create(ccb, inc, mss, cookie_len, cookie);
|
||||||
|
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tcp_fastopen_ccache_entry *
|
||||||
|
tcp_fastopen_ccache_lookup(struct in_conninfo *inc,
|
||||||
|
struct tcp_fastopen_ccache_bucket **ccbp)
|
||||||
|
{
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb;
|
||||||
|
struct tcp_fastopen_ccache_entry *cce;
|
||||||
|
uint32_t last_word;
|
||||||
|
uint32_t hash;
|
||||||
|
|
||||||
|
hash = jenkins_hash32((uint32_t *)&inc->inc_ie.ie_dependladdr, 4,
|
||||||
|
V_tcp_fastopen_ccache.secret);
|
||||||
|
hash = jenkins_hash32((uint32_t *)&inc->inc_ie.ie_dependfaddr, 4,
|
||||||
|
hash);
|
||||||
|
last_word = inc->inc_fport;
|
||||||
|
hash = jenkins_hash32(&last_word, 1, hash);
|
||||||
|
ccb = &V_tcp_fastopen_ccache.base[hash & V_tcp_fastopen_ccache.mask];
|
||||||
|
*ccbp = ccb;
|
||||||
|
CCB_LOCK(ccb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always returns with locked bucket.
|
||||||
|
*/
|
||||||
|
TAILQ_FOREACH(cce, &ccb->ccb_entries, cce_link)
|
||||||
|
if ((!(cce->af == AF_INET6) == !(inc->inc_flags & INC_ISIPV6)) &&
|
||||||
|
(cce->server_port == inc->inc_ie.ie_fport) &&
|
||||||
|
(((cce->af == AF_INET) &&
|
||||||
|
(cce->cce_client_ip.v4.s_addr == inc->inc_laddr.s_addr) &&
|
||||||
|
(cce->cce_server_ip.v4.s_addr == inc->inc_faddr.s_addr)) ||
|
||||||
|
((cce->af == AF_INET6) &&
|
||||||
|
IN6_ARE_ADDR_EQUAL(&cce->cce_client_ip.v6, &inc->inc6_laddr) &&
|
||||||
|
IN6_ARE_ADDR_EQUAL(&cce->cce_server_ip.v6, &inc->inc6_faddr))))
|
||||||
|
break;
|
||||||
|
|
||||||
|
return (cce);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tcp_fastopen_ccache_entry *
|
||||||
|
tcp_fastopen_ccache_create(struct tcp_fastopen_ccache_bucket *ccb,
|
||||||
|
struct in_conninfo *inc, uint16_t mss, uint8_t cookie_len, uint8_t *cookie)
|
||||||
|
{
|
||||||
|
struct tcp_fastopen_ccache_entry *cce;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1. Create a new entry, or
|
||||||
|
* 2. Reclaim an existing entry, or
|
||||||
|
* 3. Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCB_LOCK_ASSERT(ccb);
|
||||||
|
|
||||||
|
cce = NULL;
|
||||||
|
if (ccb->ccb_num_entries < V_tcp_fastopen_ccache.bucket_limit)
|
||||||
|
cce = uma_zalloc(V_tcp_fastopen_ccache.zone, M_NOWAIT);
|
||||||
|
|
||||||
|
if (cce == NULL) {
|
||||||
|
/*
|
||||||
|
* At bucket limit, or out of memory - reclaim last
|
||||||
|
* entry in bucket.
|
||||||
|
*/
|
||||||
|
cce = TAILQ_LAST(&ccb->ccb_entries, bucket_entries);
|
||||||
|
if (cce == NULL) {
|
||||||
|
/* XXX count this event */
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&ccb->ccb_entries, cce, cce_link);
|
||||||
|
} else
|
||||||
|
ccb->ccb_num_entries++;
|
||||||
|
|
||||||
|
TAILQ_INSERT_HEAD(&ccb->ccb_entries, cce, cce_link);
|
||||||
|
cce->af = (inc->inc_flags & INC_ISIPV6) ? AF_INET6 : AF_INET;
|
||||||
|
if (cce->af == AF_INET) {
|
||||||
|
cce->cce_client_ip.v4 = inc->inc_laddr;
|
||||||
|
cce->cce_server_ip.v4 = inc->inc_faddr;
|
||||||
|
} else {
|
||||||
|
cce->cce_client_ip.v6 = inc->inc6_laddr;
|
||||||
|
cce->cce_server_ip.v6 = inc->inc6_faddr;
|
||||||
|
}
|
||||||
|
cce->server_port = inc->inc_fport;
|
||||||
|
if ((cookie_len <= TCP_FASTOPEN_MAX_COOKIE_LEN) &&
|
||||||
|
((cookie_len & 0x1) == 0)) {
|
||||||
|
cce->server_mss = mss;
|
||||||
|
cce->cookie_len = cookie_len;
|
||||||
|
memcpy(cce->cookie, cookie, cookie_len);
|
||||||
|
cce->disable_time = 0;
|
||||||
|
} else {
|
||||||
|
/* invalid cookie length, disable cce */
|
||||||
|
cce->server_mss = 0;
|
||||||
|
cce->cookie_len = 0;
|
||||||
|
cce->disable_time = getsbinuptime();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cce);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tcp_fastopen_ccache_bucket_trim(struct tcp_fastopen_ccache_bucket *ccb,
|
||||||
|
unsigned int limit)
|
||||||
|
{
|
||||||
|
struct tcp_fastopen_ccache_entry *cce, *cce_tmp;
|
||||||
|
unsigned int entries;
|
||||||
|
|
||||||
|
CCB_LOCK(ccb);
|
||||||
|
entries = 0;
|
||||||
|
TAILQ_FOREACH_SAFE(cce, &ccb->ccb_entries, cce_link, cce_tmp) {
|
||||||
|
entries++;
|
||||||
|
if (entries > limit)
|
||||||
|
tcp_fastopen_ccache_entry_drop(cce, ccb);
|
||||||
|
}
|
||||||
|
KASSERT(ccb->ccb_num_entries <= limit,
|
||||||
|
("%s: ccb->ccb_num_entries %d exceeds limit %d", __func__,
|
||||||
|
ccb->ccb_num_entries, limit));
|
||||||
|
if (limit == 0) {
|
||||||
|
KASSERT(TAILQ_EMPTY(&ccb->ccb_entries),
|
||||||
|
("%s: ccb->ccb_entries not empty", __func__));
|
||||||
|
ccb->ccb_num_entries = -1; /* disable bucket */
|
||||||
|
}
|
||||||
|
CCB_UNLOCK(ccb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tcp_fastopen_ccache_entry_drop(struct tcp_fastopen_ccache_entry *cce,
|
||||||
|
struct tcp_fastopen_ccache_bucket *ccb)
|
||||||
|
{
|
||||||
|
|
||||||
|
CCB_LOCK_ASSERT(ccb);
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&ccb->ccb_entries, cce, cce_link);
|
||||||
|
ccb->ccb_num_entries--;
|
||||||
|
uma_zfree(V_tcp_fastopen_ccache.zone, cce);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2015 Patrick Kelsey
|
* Copyright (c) 2015-2017 Patrick Kelsey
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -31,17 +31,59 @@
|
|||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|
||||||
#define TCP_FASTOPEN_COOKIE_LEN 8 /* tied to SipHash24 64-bit output */
|
#define TCP_FASTOPEN_COOKIE_LEN 8 /* SipHash24 64-bit output */
|
||||||
|
|
||||||
VNET_DECLARE(unsigned int, tcp_fastopen_enabled);
|
VNET_DECLARE(unsigned int, tcp_fastopen_client_enable);
|
||||||
#define V_tcp_fastopen_enabled VNET(tcp_fastopen_enabled)
|
#define V_tcp_fastopen_client_enable VNET(tcp_fastopen_client_enable)
|
||||||
|
|
||||||
|
VNET_DECLARE(unsigned int, tcp_fastopen_server_enable);
|
||||||
|
#define V_tcp_fastopen_server_enable VNET(tcp_fastopen_server_enable)
|
||||||
|
|
||||||
|
union tcp_fastopen_ip_addr {
|
||||||
|
struct in_addr v4;
|
||||||
|
struct in6_addr v6;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcp_fastopen_ccache_entry {
|
||||||
|
TAILQ_ENTRY(tcp_fastopen_ccache_entry) cce_link;
|
||||||
|
union tcp_fastopen_ip_addr cce_client_ip; /* network byte order */
|
||||||
|
union tcp_fastopen_ip_addr cce_server_ip; /* network byte order */
|
||||||
|
uint16_t server_port; /* network byte order */
|
||||||
|
uint16_t server_mss; /* host byte order */
|
||||||
|
uint8_t af;
|
||||||
|
uint8_t cookie_len;
|
||||||
|
uint8_t cookie[TCP_FASTOPEN_MAX_COOKIE_LEN];
|
||||||
|
sbintime_t disable_time; /* non-zero value means path is disabled */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcp_fastopen_ccache;
|
||||||
|
|
||||||
|
struct tcp_fastopen_ccache_bucket {
|
||||||
|
struct mtx ccb_mtx;
|
||||||
|
TAILQ_HEAD(bucket_entries, tcp_fastopen_ccache_entry) ccb_entries;
|
||||||
|
int ccb_num_entries;
|
||||||
|
struct tcp_fastopen_ccache *ccb_ccache;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcp_fastopen_ccache {
|
||||||
|
uma_zone_t zone;
|
||||||
|
struct tcp_fastopen_ccache_bucket *base;
|
||||||
|
unsigned int bucket_limit;
|
||||||
|
unsigned int buckets;
|
||||||
|
unsigned int mask;
|
||||||
|
uint32_t secret;
|
||||||
|
};
|
||||||
|
|
||||||
void tcp_fastopen_init(void);
|
void tcp_fastopen_init(void);
|
||||||
void tcp_fastopen_destroy(void);
|
void tcp_fastopen_destroy(void);
|
||||||
unsigned int *tcp_fastopen_alloc_counter(void);
|
unsigned int *tcp_fastopen_alloc_counter(void);
|
||||||
void tcp_fastopen_decrement_counter(unsigned int *counter);
|
void tcp_fastopen_decrement_counter(unsigned int *);
|
||||||
int tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie,
|
int tcp_fastopen_check_cookie(struct in_conninfo *, uint8_t *, unsigned int,
|
||||||
unsigned int len, uint64_t *latest_cookie);
|
uint64_t *);
|
||||||
|
void tcp_fastopen_connect(struct tcpcb *);
|
||||||
|
void tcp_fastopen_disable_path(struct tcpcb *);
|
||||||
|
void tcp_fastopen_update_cache(struct tcpcb *, uint16_t, uint8_t,
|
||||||
|
uint8_t *);
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
#endif /* _TCP_FASTOPEN_H_ */
|
#endif /* _TCP_FASTOPEN_H_ */
|
||||||
|
@ -100,9 +100,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet6/in6_var.h>
|
#include <netinet6/in6_var.h>
|
||||||
#include <netinet6/ip6_var.h>
|
#include <netinet6/ip6_var.h>
|
||||||
#include <netinet6/nd6.h>
|
#include <netinet6/nd6.h>
|
||||||
#ifdef TCP_RFC7413
|
|
||||||
#include <netinet/tcp_fastopen.h>
|
|
||||||
#endif
|
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/tcp_fsm.h>
|
#include <netinet/tcp_fsm.h>
|
||||||
#include <netinet/tcp_seq.h>
|
#include <netinet/tcp_seq.h>
|
||||||
@ -111,6 +108,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet6/tcp6_var.h>
|
#include <netinet6/tcp6_var.h>
|
||||||
#include <netinet/tcpip.h>
|
#include <netinet/tcpip.h>
|
||||||
#include <netinet/cc/cc.h>
|
#include <netinet/cc/cc.h>
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
#include <netinet/tcp_fastopen.h>
|
||||||
|
#endif
|
||||||
#ifdef TCPPCAP
|
#ifdef TCPPCAP
|
||||||
#include <netinet/tcp_pcap.h>
|
#include <netinet/tcp_pcap.h>
|
||||||
#endif
|
#endif
|
||||||
@ -1717,6 +1717,15 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
|||||||
if ((tp->t_flags & TF_SACK_PERMIT) &&
|
if ((tp->t_flags & TF_SACK_PERMIT) &&
|
||||||
(to.to_flags & TOF_SACKPERM) == 0)
|
(to.to_flags & TOF_SACKPERM) == 0)
|
||||||
tp->t_flags &= ~TF_SACK_PERMIT;
|
tp->t_flags &= ~TF_SACK_PERMIT;
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
if (IS_FASTOPEN(tp->t_flags)) {
|
||||||
|
if (to.to_flags & TOF_FASTOPEN)
|
||||||
|
tcp_fastopen_update_cache(tp, to.to_mss,
|
||||||
|
to.to_tfo_len, to.to_tfo_cookie);
|
||||||
|
else
|
||||||
|
tcp_fastopen_disable_path(tp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2027,6 +2036,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
|||||||
tp->irs = th->th_seq;
|
tp->irs = th->th_seq;
|
||||||
tcp_rcvseqinit(tp);
|
tcp_rcvseqinit(tp);
|
||||||
if (thflags & TH_ACK) {
|
if (thflags & TH_ACK) {
|
||||||
|
int tfo_partial_ack = 0;
|
||||||
|
|
||||||
TCPSTAT_INC(tcps_connects);
|
TCPSTAT_INC(tcps_connects);
|
||||||
soisconnected(so);
|
soisconnected(so);
|
||||||
#ifdef MAC
|
#ifdef MAC
|
||||||
@ -2040,11 +2051,20 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
|||||||
tp->rcv_adv += min(tp->rcv_wnd,
|
tp->rcv_adv += min(tp->rcv_wnd,
|
||||||
TCP_MAXWIN << tp->rcv_scale);
|
TCP_MAXWIN << tp->rcv_scale);
|
||||||
tp->snd_una++; /* SYN is acked */
|
tp->snd_una++; /* SYN is acked */
|
||||||
|
/*
|
||||||
|
* If not all the data that was sent in the TFO SYN
|
||||||
|
* has been acked, resend the remainder right away.
|
||||||
|
*/
|
||||||
|
if (IS_FASTOPEN(tp->t_flags) &&
|
||||||
|
(tp->snd_una != tp->snd_max)) {
|
||||||
|
tp->snd_nxt = th->th_ack;
|
||||||
|
tfo_partial_ack = 1;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* If there's data, delay ACK; if there's also a FIN
|
* If there's data, delay ACK; if there's also a FIN
|
||||||
* ACKNOW will be turned on later.
|
* ACKNOW will be turned on later.
|
||||||
*/
|
*/
|
||||||
if (DELAY_ACK(tp, tlen) && tlen != 0)
|
if (DELAY_ACK(tp, tlen) && tlen != 0 && !tfo_partial_ack)
|
||||||
tcp_timer_activate(tp, TT_DELACK,
|
tcp_timer_activate(tp, TT_DELACK,
|
||||||
tcp_delacktime);
|
tcp_delacktime);
|
||||||
else
|
else
|
||||||
@ -3422,13 +3442,15 @@ tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags)
|
|||||||
break;
|
break;
|
||||||
#ifdef TCP_RFC7413
|
#ifdef TCP_RFC7413
|
||||||
case TCPOPT_FAST_OPEN:
|
case TCPOPT_FAST_OPEN:
|
||||||
if ((optlen != TCPOLEN_FAST_OPEN_EMPTY) &&
|
/*
|
||||||
(optlen < TCPOLEN_FAST_OPEN_MIN) &&
|
* Cookie length validation is performed by the
|
||||||
(optlen > TCPOLEN_FAST_OPEN_MAX))
|
* server side cookie checking code or the client
|
||||||
continue;
|
* side cookie cache update code.
|
||||||
|
*/
|
||||||
if (!(flags & TO_SYN))
|
if (!(flags & TO_SYN))
|
||||||
continue;
|
continue;
|
||||||
if (!V_tcp_fastopen_enabled)
|
if (!V_tcp_fastopen_client_enable &&
|
||||||
|
!V_tcp_fastopen_server_enable)
|
||||||
continue;
|
continue;
|
||||||
to->to_flags |= TOF_FASTOPEN;
|
to->to_flags |= TOF_FASTOPEN;
|
||||||
to->to_tfo_len = optlen - 2;
|
to->to_tfo_len = optlen - 2;
|
||||||
|
@ -71,9 +71,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet/ip6.h>
|
#include <netinet/ip6.h>
|
||||||
#include <netinet6/ip6_var.h>
|
#include <netinet6/ip6_var.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCP_RFC7413
|
|
||||||
#include <netinet/tcp_fastopen.h>
|
|
||||||
#endif
|
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#define TCPOUTFLAGS
|
#define TCPOUTFLAGS
|
||||||
#include <netinet/tcp_fsm.h>
|
#include <netinet/tcp_fsm.h>
|
||||||
@ -82,6 +79,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet/tcp_var.h>
|
#include <netinet/tcp_var.h>
|
||||||
#include <netinet/tcpip.h>
|
#include <netinet/tcpip.h>
|
||||||
#include <netinet/cc/cc.h>
|
#include <netinet/cc/cc.h>
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
#include <netinet/tcp_fastopen.h>
|
||||||
|
#endif
|
||||||
#ifdef TCPPCAP
|
#ifdef TCPPCAP
|
||||||
#include <netinet/tcp_pcap.h>
|
#include <netinet/tcp_pcap.h>
|
||||||
#endif
|
#endif
|
||||||
@ -212,6 +212,10 @@ tcp_output(struct tcpcb *tp)
|
|||||||
struct sackhole *p;
|
struct sackhole *p;
|
||||||
int tso, mtu;
|
int tso, mtu;
|
||||||
struct tcpopt to;
|
struct tcpopt to;
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
unsigned int wanted_cookie = 0;
|
||||||
|
unsigned int dont_sendalot = 0;
|
||||||
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
int maxburst = TCP_MAXBURST;
|
int maxburst = TCP_MAXBURST;
|
||||||
#endif
|
#endif
|
||||||
@ -237,7 +241,7 @@ tcp_output(struct tcpcb *tp)
|
|||||||
if (IS_FASTOPEN(tp->t_flags) &&
|
if (IS_FASTOPEN(tp->t_flags) &&
|
||||||
(tp->t_state == TCPS_SYN_RECEIVED) &&
|
(tp->t_state == TCPS_SYN_RECEIVED) &&
|
||||||
SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN|ACK sent */
|
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);
|
return (0);
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
@ -449,12 +453,21 @@ tcp_output(struct tcpcb *tp)
|
|||||||
|
|
||||||
#ifdef TCP_RFC7413
|
#ifdef TCP_RFC7413
|
||||||
/*
|
/*
|
||||||
* When retransmitting SYN|ACK on a passively-created TFO socket,
|
* On TFO sockets, ensure no data is sent in the following cases:
|
||||||
* don't include data, as the presence of data may have caused the
|
*
|
||||||
* original SYN|ACK to have been dropped by a middlebox.
|
* - 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) &&
|
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)))
|
(flags & TH_RST)))
|
||||||
len = 0;
|
len = 0;
|
||||||
#endif
|
#endif
|
||||||
@ -541,7 +554,7 @@ tcp_output(struct tcpcb *tp)
|
|||||||
if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg &&
|
if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg &&
|
||||||
((tp->t_flags & TF_SIGNATURE) == 0) &&
|
((tp->t_flags & TF_SIGNATURE) == 0) &&
|
||||||
tp->rcv_numsacks == 0 && sack_rxmit == 0 &&
|
tp->rcv_numsacks == 0 && sack_rxmit == 0 &&
|
||||||
ipoptlen == 0)
|
ipoptlen == 0 && !(flags & TH_SYN))
|
||||||
tso = 1;
|
tso = 1;
|
||||||
|
|
||||||
if (sack_rxmit) {
|
if (sack_rxmit) {
|
||||||
@ -763,18 +776,36 @@ tcp_output(struct tcpcb *tp)
|
|||||||
to.to_flags |= TOF_MSS;
|
to.to_flags |= TOF_MSS;
|
||||||
#ifdef TCP_RFC7413
|
#ifdef TCP_RFC7413
|
||||||
/*
|
/*
|
||||||
* Only include the TFO option on the first
|
* On SYN or SYN|ACK transmits on TFO connections,
|
||||||
* transmission of the SYN|ACK on a
|
* only include the TFO option if it is not a
|
||||||
* passively-created TFO socket, as the presence of
|
* retransmit, as the presence of the TFO option may
|
||||||
* the TFO option may have caused the original
|
* have caused the original SYN or SYN|ACK to have
|
||||||
* SYN|ACK to have been dropped by a middlebox.
|
* been dropped by a middlebox.
|
||||||
*/
|
*/
|
||||||
if (IS_FASTOPEN(tp->t_flags) &&
|
if (IS_FASTOPEN(tp->t_flags) &&
|
||||||
(tp->t_state == TCPS_SYN_RECEIVED) &&
|
|
||||||
(tp->t_rxtshift == 0)) {
|
(tp->t_rxtshift == 0)) {
|
||||||
to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN;
|
if (tp->t_state == TCPS_SYN_RECEIVED) {
|
||||||
to.to_tfo_cookie = (u_char *)&tp->t_tfo_cookie;
|
to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN;
|
||||||
to.to_flags |= TOF_FASTOPEN;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
@ -820,6 +851,15 @@ tcp_output(struct tcpcb *tp)
|
|||||||
|
|
||||||
/* Processing the options. */
|
/* Processing the options. */
|
||||||
hdrlen += optlen = tcp_addoptions(&to, opt);
|
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 @@ tcp_output(struct tcpcb *tp)
|
|||||||
} else {
|
} else {
|
||||||
len = tp->t_maxseg - optlen - ipoptlen;
|
len = tp->t_maxseg - optlen - ipoptlen;
|
||||||
sendalot = 1;
|
sendalot = 1;
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
if (dont_sendalot)
|
||||||
|
sendalot = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
tso = 0;
|
tso = 0;
|
||||||
@ -1774,8 +1818,10 @@ tcp_addoptions(struct tcpopt *to, u_char *optp)
|
|||||||
|
|
||||||
/* XXX is there any point to aligning this option? */
|
/* XXX is there any point to aligning this option? */
|
||||||
total_len = TCPOLEN_FAST_OPEN_EMPTY + to->to_tfo_len;
|
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;
|
continue;
|
||||||
|
}
|
||||||
*optp++ = TCPOPT_FAST_OPEN;
|
*optp++ = TCPOPT_FAST_OPEN;
|
||||||
*optp++ = total_len;
|
*optp++ = total_len;
|
||||||
if (to->to_tfo_len > 0) {
|
if (to->to_tfo_len > 0) {
|
||||||
|
@ -93,9 +93,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet6/nd6.h>
|
#include <netinet6/nd6.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCP_RFC7413
|
|
||||||
#include <netinet/tcp_fastopen.h>
|
|
||||||
#endif
|
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/tcp_fsm.h>
|
#include <netinet/tcp_fsm.h>
|
||||||
#include <netinet/tcp_seq.h>
|
#include <netinet/tcp_seq.h>
|
||||||
@ -107,6 +104,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet6/tcp6_var.h>
|
#include <netinet6/tcp6_var.h>
|
||||||
#endif
|
#endif
|
||||||
#include <netinet/tcpip.h>
|
#include <netinet/tcpip.h>
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
#include <netinet/tcp_fastopen.h>
|
||||||
|
#endif
|
||||||
#ifdef TCPPCAP
|
#ifdef TCPPCAP
|
||||||
#include <netinet/tcp_pcap.h>
|
#include <netinet/tcp_pcap.h>
|
||||||
#endif
|
#endif
|
||||||
@ -2407,6 +2407,11 @@ tcp_drop_syn_sent(struct inpcb *inp, int errno)
|
|||||||
if (tp->t_state != TCPS_SYN_SENT)
|
if (tp->t_state != TCPS_SYN_SENT)
|
||||||
return (inp);
|
return (inp);
|
||||||
|
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
if (IS_FASTOPEN(tp->t_flags))
|
||||||
|
tcp_fastopen_disable_path(tp);
|
||||||
|
#endif
|
||||||
|
|
||||||
tp = tcp_drop(tp, errno);
|
tp = tcp_drop(tp, errno);
|
||||||
if (tp != NULL)
|
if (tp != NULL)
|
||||||
return (inp);
|
return (inp);
|
||||||
|
@ -1201,7 +1201,7 @@ syncache_tfo_expand(struct syncache *sc, struct socket **lsop, struct mbuf *m,
|
|||||||
inp = sotoinpcb(*lsop);
|
inp = sotoinpcb(*lsop);
|
||||||
tp = intotcpcb(inp);
|
tp = intotcpcb(inp);
|
||||||
tp->t_flags |= TF_FASTOPEN;
|
tp->t_flags |= TF_FASTOPEN;
|
||||||
tp->t_tfo_cookie = response_cookie;
|
tp->t_tfo_cookie.server = response_cookie;
|
||||||
tp->snd_max = tp->iss;
|
tp->snd_max = tp->iss;
|
||||||
tp->snd_nxt = tp->iss;
|
tp->snd_nxt = tp->iss;
|
||||||
tp->t_tfo_pending = pending_counter;
|
tp->t_tfo_pending = pending_counter;
|
||||||
@ -1282,8 +1282,9 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
|
|||||||
ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE));
|
ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE));
|
||||||
|
|
||||||
#ifdef TCP_RFC7413
|
#ifdef TCP_RFC7413
|
||||||
if (V_tcp_fastopen_enabled && IS_FASTOPEN(tp->t_flags) &&
|
if (V_tcp_fastopen_server_enable && IS_FASTOPEN(tp->t_flags) &&
|
||||||
(tp->t_tfo_pending != NULL) && (to->to_flags & TOF_FASTOPEN)) {
|
(tp->t_tfo_pending != NULL) &&
|
||||||
|
(to->to_flags & TOF_FASTOPEN)) {
|
||||||
/*
|
/*
|
||||||
* Limit the number of pending TFO connections to
|
* Limit the number of pending TFO connections to
|
||||||
* approximately half of the queue limit. This prevents TFO
|
* approximately half of the queue limit. This prevents TFO
|
||||||
|
@ -85,9 +85,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet6/ip6_var.h>
|
#include <netinet6/ip6_var.h>
|
||||||
#include <netinet6/scope6_var.h>
|
#include <netinet6/scope6_var.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCP_RFC7413
|
|
||||||
#include <netinet/tcp_fastopen.h>
|
|
||||||
#endif
|
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/tcp_fsm.h>
|
#include <netinet/tcp_fsm.h>
|
||||||
#include <netinet/tcp_seq.h>
|
#include <netinet/tcp_seq.h>
|
||||||
@ -95,6 +92,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet/tcp_var.h>
|
#include <netinet/tcp_var.h>
|
||||||
#include <netinet/tcpip.h>
|
#include <netinet/tcpip.h>
|
||||||
#include <netinet/cc/cc.h>
|
#include <netinet/cc/cc.h>
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
#include <netinet/tcp_fastopen.h>
|
||||||
|
#endif
|
||||||
#ifdef TCPPCAP
|
#ifdef TCPPCAP
|
||||||
#include <netinet/tcp_pcap.h>
|
#include <netinet/tcp_pcap.h>
|
||||||
#endif
|
#endif
|
||||||
@ -950,8 +950,15 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
#endif
|
#endif
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
tp->snd_wnd = TTCP_CLIENT_SND_WND;
|
#ifdef TCP_RFC7413
|
||||||
tcp_mss(tp, -1);
|
if (IS_FASTOPEN(tp->t_flags))
|
||||||
|
tcp_fastopen_connect(tp);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
tp->snd_wnd = TTCP_CLIENT_SND_WND;
|
||||||
|
tcp_mss(tp, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (flags & PRUS_EOF) {
|
if (flags & PRUS_EOF) {
|
||||||
/*
|
/*
|
||||||
@ -997,6 +1004,13 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
* initialize window to default value, and
|
* initialize window to default value, and
|
||||||
* initialize maxseg using peer's cached MSS.
|
* initialize maxseg using peer's cached MSS.
|
||||||
*/
|
*/
|
||||||
|
#ifdef TCP_RFC7413
|
||||||
|
/*
|
||||||
|
* Not going to contemplate SYN|URG
|
||||||
|
*/
|
||||||
|
if (IS_FASTOPEN(tp->t_flags))
|
||||||
|
tp->t_flags &= ~TF_FASTOPEN;
|
||||||
|
#endif
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
if (isipv6)
|
if (isipv6)
|
||||||
error = tcp6_connect(tp, nam, td);
|
error = tcp6_connect(tp, nam, td);
|
||||||
@ -1769,26 +1783,52 @@ tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCP_RFC7413
|
#ifdef TCP_RFC7413
|
||||||
case TCP_FASTOPEN:
|
case TCP_FASTOPEN: {
|
||||||
|
struct tcp_fastopen tfo_optval;
|
||||||
|
|
||||||
INP_WUNLOCK(inp);
|
INP_WUNLOCK(inp);
|
||||||
if (!V_tcp_fastopen_enabled)
|
if (!V_tcp_fastopen_client_enable &&
|
||||||
|
!V_tcp_fastopen_server_enable)
|
||||||
return (EPERM);
|
return (EPERM);
|
||||||
|
|
||||||
error = sooptcopyin(sopt, &optval, sizeof optval,
|
error = sooptcopyin(sopt, &tfo_optval,
|
||||||
sizeof optval);
|
sizeof(tfo_optval), sizeof(int));
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
INP_WLOCK_RECHECK(inp);
|
INP_WLOCK_RECHECK(inp);
|
||||||
if (optval) {
|
if (tfo_optval.enable) {
|
||||||
tp->t_flags |= TF_FASTOPEN;
|
if (tp->t_state == TCPS_LISTEN) {
|
||||||
if ((tp->t_state == TCPS_LISTEN) &&
|
if (!V_tcp_fastopen_server_enable) {
|
||||||
(tp->t_tfo_pending == NULL))
|
error = EPERM;
|
||||||
tp->t_tfo_pending =
|
goto unlock_and_done;
|
||||||
tcp_fastopen_alloc_counter();
|
}
|
||||||
|
|
||||||
|
tp->t_flags |= TF_FASTOPEN;
|
||||||
|
if (tp->t_tfo_pending == NULL)
|
||||||
|
tp->t_tfo_pending =
|
||||||
|
tcp_fastopen_alloc_counter();
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If a pre-shared key was provided,
|
||||||
|
* stash it in the client cookie
|
||||||
|
* field of the tcpcb for use during
|
||||||
|
* connect.
|
||||||
|
*/
|
||||||
|
if (sopt->sopt_valsize ==
|
||||||
|
sizeof(tfo_optval)) {
|
||||||
|
memcpy(tp->t_tfo_cookie.client,
|
||||||
|
tfo_optval.psk,
|
||||||
|
TCP_FASTOPEN_PSK_LEN);
|
||||||
|
tp->t_tfo_client_cookie_len =
|
||||||
|
TCP_FASTOPEN_PSK_LEN;
|
||||||
|
}
|
||||||
|
tp->t_flags |= TF_FASTOPEN;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
tp->t_flags &= ~TF_FASTOPEN;
|
tp->t_flags &= ~TF_FASTOPEN;
|
||||||
goto unlock_and_done;
|
goto unlock_and_done;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -192,8 +192,12 @@ struct tcpcb {
|
|||||||
struct tcp_function_block *t_fb;/* TCP function call block */
|
struct tcp_function_block *t_fb;/* TCP function call block */
|
||||||
void *t_fb_ptr; /* Pointer to t_fb specific data */
|
void *t_fb_ptr; /* Pointer to t_fb specific data */
|
||||||
#ifdef TCP_RFC7413
|
#ifdef TCP_RFC7413
|
||||||
uint64_t t_tfo_cookie; /* TCP Fast Open cookie */
|
uint8_t t_tfo_client_cookie_len; /* TCP Fast Open client cookie length */
|
||||||
unsigned int *t_tfo_pending; /* TCP Fast Open pending counter */
|
unsigned int *t_tfo_pending; /* TCP Fast Open server pending counter */
|
||||||
|
union {
|
||||||
|
uint8_t client[TCP_FASTOPEN_MAX_COOKIE_LEN];
|
||||||
|
uint64_t server;
|
||||||
|
} t_tfo_cookie; /* TCP Fast Open cookie to send */
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCPPCAP
|
#ifdef TCPPCAP
|
||||||
struct mbufq t_inpkts; /* List of saved input packets. */
|
struct mbufq t_inpkts; /* List of saved input packets. */
|
||||||
@ -365,7 +369,7 @@ struct tcpopt {
|
|||||||
u_int32_t to_tsecr; /* reflected timestamp */
|
u_int32_t to_tsecr; /* reflected timestamp */
|
||||||
u_char *to_sacks; /* pointer to the first SACK blocks */
|
u_char *to_sacks; /* pointer to the first SACK blocks */
|
||||||
u_char *to_signature; /* pointer to the TCP-MD5 signature */
|
u_char *to_signature; /* pointer to the TCP-MD5 signature */
|
||||||
u_char *to_tfo_cookie; /* pointer to the TFO cookie */
|
u_int8_t *to_tfo_cookie; /* pointer to the TFO cookie */
|
||||||
u_int16_t to_mss; /* maximum segment size */
|
u_int16_t to_mss; /* maximum segment size */
|
||||||
u_int8_t to_wscale; /* window scaling */
|
u_int8_t to_wscale; /* window scaling */
|
||||||
u_int8_t to_nsacks; /* number of SACK blocks */
|
u_int8_t to_nsacks; /* number of SACK blocks */
|
||||||
|
Loading…
Reference in New Issue
Block a user