ipv4: Namespaceify tcp_fastopen_blackhole_timeout knob

Different namespace application might require different time period in
second to disable Fastopen on active TCP sockets.

Tested:
Simulate following similar situation that the server's data gets dropped
after 3WHS.
C ---- syn-data ---> S
C <--- syn/ack ----- S
C ---- ack --------> S
S (accept & write)
C?  X <- data ------ S
	[retry and timeout]

And then print netstat of TCPFastOpenBlackhole, the counter increased as
expected when the firewall blackhole issue is detected and active TFO is
disabled.
# cat /proc/net/netstat | awk '{print $91}'
TCPFastOpenBlackhole
1

Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Haishuang Yan 2017-09-27 11:35:43 +08:00 committed by David S. Miller
parent 4371384856
commit 3733be14a3
4 changed files with 27 additions and 28 deletions

View File

@ -133,6 +133,9 @@ struct netns_ipv4 {
int sysctl_tcp_fastopen; int sysctl_tcp_fastopen;
struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; struct tcp_fastopen_context __rcu *tcp_fastopen_ctx;
spinlock_t tcp_fastopen_ctx_lock; spinlock_t tcp_fastopen_ctx_lock;
unsigned int sysctl_tcp_fastopen_blackhole_timeout;
atomic_t tfo_active_disable_times;
unsigned long tfo_active_disable_stamp;
#ifdef CONFIG_NET_L3_MASTER_DEV #ifdef CONFIG_NET_L3_MASTER_DEV
int sysctl_udp_l3mdev_accept; int sysctl_udp_l3mdev_accept;

View File

@ -355,11 +355,13 @@ static int proc_tfo_blackhole_detect_timeout(struct ctl_table *table,
void __user *buffer, void __user *buffer,
size_t *lenp, loff_t *ppos) size_t *lenp, loff_t *ppos)
{ {
struct net *net = container_of(table->data, struct net,
ipv4.sysctl_tcp_fastopen_blackhole_timeout);
int ret; int ret;
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (write && ret == 0) if (write && ret == 0)
tcp_fastopen_active_timeout_reset(); atomic_set(&net->ipv4.tfo_active_disable_times, 0);
return ret; return ret;
} }
@ -397,14 +399,6 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec .proc_handler = proc_dointvec
}, },
{
.procname = "tcp_fastopen_blackhole_timeout_sec",
.data = &sysctl_tcp_fastopen_blackhole_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_tfo_blackhole_detect_timeout,
.extra1 = &zero,
},
{ {
.procname = "tcp_abort_on_overflow", .procname = "tcp_abort_on_overflow",
.data = &sysctl_tcp_abort_on_overflow, .data = &sysctl_tcp_abort_on_overflow,
@ -1083,6 +1077,14 @@ static struct ctl_table ipv4_net_table[] = {
.maxlen = ((TCP_FASTOPEN_KEY_LENGTH * 2) + 10), .maxlen = ((TCP_FASTOPEN_KEY_LENGTH * 2) + 10),
.proc_handler = proc_tcp_fastopen_key, .proc_handler = proc_tcp_fastopen_key,
}, },
{
.procname = "tcp_fastopen_blackhole_timeout_sec",
.data = &init_net.ipv4.sysctl_tcp_fastopen_blackhole_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_tfo_blackhole_detect_timeout,
.extra1 = &zero,
},
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
{ {
.procname = "fib_multipath_use_neigh", .procname = "fib_multipath_use_neigh",

View File

@ -422,25 +422,16 @@ EXPORT_SYMBOL(tcp_fastopen_defer_connect);
* TFO connection with data exchanges. * TFO connection with data exchanges.
*/ */
/* Default to 1hr */
unsigned int sysctl_tcp_fastopen_blackhole_timeout __read_mostly = 60 * 60;
static atomic_t tfo_active_disable_times __read_mostly = ATOMIC_INIT(0);
static unsigned long tfo_active_disable_stamp __read_mostly;
/* Disable active TFO and record current jiffies and /* Disable active TFO and record current jiffies and
* tfo_active_disable_times * tfo_active_disable_times
*/ */
void tcp_fastopen_active_disable(struct sock *sk) void tcp_fastopen_active_disable(struct sock *sk)
{ {
atomic_inc(&tfo_active_disable_times); struct net *net = sock_net(sk);
tfo_active_disable_stamp = jiffies;
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENBLACKHOLE);
}
/* Reset tfo_active_disable_times to 0 */ atomic_inc(&net->ipv4.tfo_active_disable_times);
void tcp_fastopen_active_timeout_reset(void) net->ipv4.tfo_active_disable_stamp = jiffies;
{ NET_INC_STATS(net, LINUX_MIB_TCPFASTOPENBLACKHOLE);
atomic_set(&tfo_active_disable_times, 0);
} }
/* Calculate timeout for tfo active disable /* Calculate timeout for tfo active disable
@ -449,17 +440,18 @@ void tcp_fastopen_active_timeout_reset(void)
*/ */
bool tcp_fastopen_active_should_disable(struct sock *sk) bool tcp_fastopen_active_should_disable(struct sock *sk)
{ {
int tfo_da_times = atomic_read(&tfo_active_disable_times); unsigned int tfo_bh_timeout = sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout;
int multiplier; int tfo_da_times = atomic_read(&sock_net(sk)->ipv4.tfo_active_disable_times);
unsigned long timeout; unsigned long timeout;
int multiplier;
if (!tfo_da_times) if (!tfo_da_times)
return false; return false;
/* Limit timout to max: 2^6 * initial timeout */ /* Limit timout to max: 2^6 * initial timeout */
multiplier = 1 << min(tfo_da_times - 1, 6); multiplier = 1 << min(tfo_da_times - 1, 6);
timeout = multiplier * sysctl_tcp_fastopen_blackhole_timeout * HZ; timeout = multiplier * tfo_bh_timeout * HZ;
if (time_before(jiffies, tfo_active_disable_stamp + timeout)) if (time_before(jiffies, sock_net(sk)->ipv4.tfo_active_disable_stamp + timeout))
return true; return true;
/* Mark check bit so we can check for successful active TFO /* Mark check bit so we can check for successful active TFO
@ -495,10 +487,10 @@ void tcp_fastopen_active_disable_ofo_check(struct sock *sk)
} }
} }
} else if (tp->syn_fastopen_ch && } else if (tp->syn_fastopen_ch &&
atomic_read(&tfo_active_disable_times)) { atomic_read(&sock_net(sk)->ipv4.tfo_active_disable_times)) {
dst = sk_dst_get(sk); dst = sk_dst_get(sk);
if (!(dst && dst->dev && (dst->dev->flags & IFF_LOOPBACK))) if (!(dst && dst->dev && (dst->dev->flags & IFF_LOOPBACK)))
tcp_fastopen_active_timeout_reset(); atomic_set(&sock_net(sk)->ipv4.tfo_active_disable_times, 0);
dst_release(dst); dst_release(dst);
} }
} }

View File

@ -2474,6 +2474,8 @@ static int __net_init tcp_sk_init(struct net *net)
net->ipv4.sysctl_tcp_fastopen = TFO_CLIENT_ENABLE; net->ipv4.sysctl_tcp_fastopen = TFO_CLIENT_ENABLE;
spin_lock_init(&net->ipv4.tcp_fastopen_ctx_lock); spin_lock_init(&net->ipv4.tcp_fastopen_ctx_lock);
net->ipv4.sysctl_tcp_fastopen_blackhole_timeout = 60 * 60;
atomic_set(&net->ipv4.tfo_active_disable_times, 0);
return 0; return 0;
fail: fail: