tcp: Remove TCPCT

TCPCT uses option-number 253, reserved for experimental use and should
not be used in production environments.
Further, TCPCT does not fully implement RFC 6013.

As a nice side-effect, removing TCPCT increases TCP's performance for
very short flows:

Doing an apache-benchmark with -c 100 -n 100000, sending HTTP-requests
for files of 1KB size.

before this patch:
	average (among 7 runs) of 20845.5 Requests/Second
after:
	average (among 7 runs) of 21403.6 Requests/Second

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Christoph Paasch
2013-03-17 08:23:34 +00:00
committed by David S. Miller
parent 94d8f2b133
commit 1a2c6181c4
18 changed files with 37 additions and 840 deletions

View File

@@ -65,9 +65,6 @@ int sysctl_tcp_base_mss __read_mostly = TCP_BASE_MSS;
/* By default, RFC2861 behavior. */
int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */
EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size);
static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
int push_one, gfp_t gfp);
@@ -386,7 +383,6 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
#define OPTION_TS (1 << 1)
#define OPTION_MD5 (1 << 2)
#define OPTION_WSCALE (1 << 3)
#define OPTION_COOKIE_EXTENSION (1 << 4)
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
struct tcp_out_options {
@@ -400,36 +396,6 @@ struct tcp_out_options {
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
};
/* The sysctl int routines are generic, so check consistency here.
*/
static u8 tcp_cookie_size_check(u8 desired)
{
int cookie_size;
if (desired > 0)
/* previously specified */
return desired;
cookie_size = ACCESS_ONCE(sysctl_tcp_cookie_size);
if (cookie_size <= 0)
/* no default specified */
return 0;
if (cookie_size <= TCP_COOKIE_MIN)
/* value too small, specify minimum */
return TCP_COOKIE_MIN;
if (cookie_size >= TCP_COOKIE_MAX)
/* value too large, specify maximum */
return TCP_COOKIE_MAX;
if (cookie_size & 1)
/* 8-bit multiple, illegal, fix it */
cookie_size++;
return (u8)cookie_size;
}
/* Write previously computed TCP options to the packet.
*
* Beware: Something in the Internet is very sensitive to the ordering of
@@ -448,27 +414,9 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
{
u16 options = opts->options; /* mungable copy */
/* Having both authentication and cookies for security is redundant,
* and there's certainly not enough room. Instead, the cookie-less
* extension variant is proposed.
*
* Consider the pessimal case with authentication. The options
* could look like:
* COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40
*/
if (unlikely(OPTION_MD5 & options)) {
if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
*ptr++ = htonl((TCPOPT_COOKIE << 24) |
(TCPOLEN_COOKIE_BASE << 16) |
(TCPOPT_MD5SIG << 8) |
TCPOLEN_MD5SIG);
} else {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
(TCPOPT_MD5SIG << 8) |
TCPOLEN_MD5SIG);
}
options &= ~OPTION_COOKIE_EXTENSION;
*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
(TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
/* overload cookie hash location */
opts->hash_location = (__u8 *)ptr;
ptr += 4;
@@ -497,44 +445,6 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
*ptr++ = htonl(opts->tsecr);
}
/* Specification requires after timestamp, so do it now.
*
* Consider the pessimal case without authentication. The options
* could look like:
* MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40
*/
if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
__u8 *cookie_copy = opts->hash_location;
u8 cookie_size = opts->hash_size;
/* 8-bit multiple handled in tcp_cookie_size_check() above,
* and elsewhere.
*/
if (0x2 & cookie_size) {
__u8 *p = (__u8 *)ptr;
/* 16-bit multiple */
*p++ = TCPOPT_COOKIE;
*p++ = TCPOLEN_COOKIE_BASE + cookie_size;
*p++ = *cookie_copy++;
*p++ = *cookie_copy++;
ptr++;
cookie_size -= 2;
} else {
/* 32-bit multiple */
*ptr++ = htonl(((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
(TCPOPT_COOKIE << 8) |
TCPOLEN_COOKIE_BASE) +
cookie_size);
}
if (cookie_size > 0) {
memcpy(ptr, cookie_copy, cookie_size);
ptr += (cookie_size / 4);
}
}
if (unlikely(OPTION_SACK_ADVERTISE & options)) {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
@@ -593,11 +503,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_md5sig_key **md5)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_cookie_values *cvp = tp->cookie_values;
unsigned int remaining = MAX_TCP_OPTION_SPACE;
u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ?
tcp_cookie_size_check(cvp->cookie_desired) :
0;
struct tcp_fastopen_request *fastopen = tp->fastopen_req;
#ifdef CONFIG_TCP_MD5SIG
@@ -649,52 +555,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
tp->syn_fastopen = 1;
}
}
/* Note that timestamps are required by the specification.
*
* Odd numbers of bytes are prohibited by the specification, ensuring
* that the cookie is 16-bit aligned, and the resulting cookie pair is
* 32-bit aligned.
*/
if (*md5 == NULL &&
(OPTION_TS & opts->options) &&
cookie_size > 0) {
int need = TCPOLEN_COOKIE_BASE + cookie_size;
if (0x2 & need) {
/* 32-bit multiple */
need += 2; /* NOPs */
if (need > remaining) {
/* try shrinking cookie to fit */
cookie_size -= 2;
need -= 4;
}
}
while (need > remaining && TCP_COOKIE_MIN <= cookie_size) {
cookie_size -= 4;
need -= 4;
}
if (TCP_COOKIE_MIN <= cookie_size) {
opts->options |= OPTION_COOKIE_EXTENSION;
opts->hash_location = (__u8 *)&cvp->cookie_pair[0];
opts->hash_size = cookie_size;
/* Remember for future incarnations. */
cvp->cookie_desired = cookie_size;
if (cvp->cookie_desired != cvp->cookie_pair_size) {
/* Currently use random bytes as a nonce,
* assuming these are completely unpredictable
* by hostile users of the same system.
*/
get_random_bytes(&cvp->cookie_pair[0],
cookie_size);
cvp->cookie_pair_size = cookie_size;
}
remaining -= need;
}
}
return MAX_TCP_OPTION_SPACE - remaining;
}
@@ -704,14 +565,10 @@ static unsigned int tcp_synack_options(struct sock *sk,
unsigned int mss, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5,
struct tcp_extend_values *xvp,
struct tcp_fastopen_cookie *foc)
{
struct inet_request_sock *ireq = inet_rsk(req);
unsigned int remaining = MAX_TCP_OPTION_SPACE;
u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ?
xvp->cookie_plus :
0;
#ifdef CONFIG_TCP_MD5SIG
*md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
@@ -759,28 +616,7 @@ static unsigned int tcp_synack_options(struct sock *sk,
remaining -= need;
}
}
/* Similar rationale to tcp_syn_options() applies here, too.
* If the <SYN> options fit, the same options should fit now!
*/
if (*md5 == NULL &&
ireq->tstamp_ok &&
cookie_plus > TCPOLEN_COOKIE_BASE) {
int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */
if (0x2 & need) {
/* 32-bit multiple */
need += 2; /* NOPs */
}
if (need <= remaining) {
opts->options |= OPTION_COOKIE_EXTENSION;
opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE;
remaining -= need;
} else {
/* There's no error return, so flag it. */
xvp->cookie_out_never = 1; /* true */
opts->hash_size = 0;
}
}
return MAX_TCP_OPTION_SPACE - remaining;
}
@@ -2802,32 +2638,24 @@ int tcp_send_synack(struct sock *sk)
* sk: listener socket
* dst: dst entry attached to the SYNACK
* req: request_sock pointer
* rvp: request_values pointer
*
* Allocate one skb and build a SYNACK packet.
* @dst is consumed : Caller should not use it again.
*/
struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req,
struct request_values *rvp,
struct tcp_fastopen_cookie *foc)
{
struct tcp_out_options opts;
struct tcp_extend_values *xvp = tcp_xv(rvp);
struct inet_request_sock *ireq = inet_rsk(req);
struct tcp_sock *tp = tcp_sk(sk);
const struct tcp_cookie_values *cvp = tp->cookie_values;
struct tcphdr *th;
struct sk_buff *skb;
struct tcp_md5sig_key *md5;
int tcp_header_size;
int mss;
int s_data_desired = 0;
if (cvp != NULL && cvp->s_data_constant && cvp->s_data_desired)
s_data_desired = cvp->s_data_desired;
skb = alloc_skb(MAX_TCP_HEADER + 15 + s_data_desired,
sk_gfp_atomic(sk, GFP_ATOMIC));
skb = alloc_skb(MAX_TCP_HEADER + 15, sk_gfp_atomic(sk, GFP_ATOMIC));
if (unlikely(!skb)) {
dst_release(dst);
return NULL;
@@ -2869,9 +2697,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
else
#endif
TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_header_size = tcp_synack_options(sk, req, mss,
skb, &opts, &md5, xvp, foc)
+ sizeof(*th);
tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5,
foc) + sizeof(*th);
skb_push(skb, tcp_header_size);
skb_reset_transport_header(skb);
@@ -2889,40 +2716,6 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
TCPHDR_SYN | TCPHDR_ACK);
if (OPTION_COOKIE_EXTENSION & opts.options) {
if (s_data_desired) {
u8 *buf = skb_put(skb, s_data_desired);
/* copy data directly from the listening socket. */
memcpy(buf, cvp->s_data_payload, s_data_desired);
TCP_SKB_CB(skb)->end_seq += s_data_desired;
}
if (opts.hash_size > 0) {
__u32 workspace[SHA_WORKSPACE_WORDS];
u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS];
u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1];
/* Secret recipe depends on the Timestamp, (future)
* Sequence and Acknowledgment Numbers, Initiator
* Cookie, and others handled by IP variant caller.
*/
*tail-- ^= opts.tsval;
*tail-- ^= tcp_rsk(req)->rcv_isn + 1;
*tail-- ^= TCP_SKB_CB(skb)->seq + 1;
/* recommended */
*tail-- ^= (((__force u32)th->dest << 16) | (__force u32)th->source);
*tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */
sha_transform((__u32 *)&xvp->cookie_bakery[0],
(char *)mess,
&workspace[0]);
opts.hash_location =
(__u8 *)&xvp->cookie_bakery[0];
}
}
th->seq = htonl(TCP_SKB_CB(skb)->seq);
/* XXX data is queued and acked as is. No buffer/window check */
th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);