aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2016-04-14 01:05:39 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-15 16:45:44 -0400
commitb3d051477cf94e9d71d6acadb8a90de15237b9c1 (patch)
tree59009bc698f472b31b15059972e6904cd9272d32 /net
parentac18dd9e842294377dbaf1e8d169493567a81fa1 (diff)
tcp: do not mess with listener sk_wmem_alloc
When removing sk_refcnt manipulation on synflood, I missed that using skb_set_owner_w() was racy, if sk->sk_wmem_alloc had already transitioned to 0. We should hold sk_refcnt instead, but this is a big deal under attack. (Doing so increase performance from 3.2 Mpps to 3.8 Mpps only) In this patch, I chose to not attach a socket to syncookies skb. Performance is now 5 Mpps instead of 3.2 Mpps. Following patch will remove last known false sharing in tcp_rcv_state_process() Fixes: 3b24d854cb35 ("tcp/dccp: do not touch listener sk_refcnt under synflood") Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_input.c7
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv4/tcp_output.c16
-rw-r--r--net/ipv6/tcp_ipv6.c4
4 files changed, 20 insertions, 11 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 983f04c11177..7ea7034af83f 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6327,7 +6327,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
6327 } 6327 }
6328 if (fastopen_sk) { 6328 if (fastopen_sk) {
6329 af_ops->send_synack(fastopen_sk, dst, &fl, req, 6329 af_ops->send_synack(fastopen_sk, dst, &fl, req,
6330 &foc, false); 6330 &foc, TCP_SYNACK_FASTOPEN);
6331 /* Add the child socket directly into the accept queue */ 6331 /* Add the child socket directly into the accept queue */
6332 inet_csk_reqsk_queue_add(sk, req, fastopen_sk); 6332 inet_csk_reqsk_queue_add(sk, req, fastopen_sk);
6333 sk->sk_data_ready(sk); 6333 sk->sk_data_ready(sk);
@@ -6337,8 +6337,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
6337 tcp_rsk(req)->tfo_listener = false; 6337 tcp_rsk(req)->tfo_listener = false;
6338 if (!want_cookie) 6338 if (!want_cookie)
6339 inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); 6339 inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
6340 af_ops->send_synack(sk, dst, &fl, req, 6340 af_ops->send_synack(sk, dst, &fl, req, &foc,
6341 &foc, !want_cookie); 6341 !want_cookie ? TCP_SYNACK_NORMAL :
6342 TCP_SYNACK_COOKIE);
6342 if (want_cookie) { 6343 if (want_cookie) {
6343 reqsk_free(req); 6344 reqsk_free(req);
6344 return 0; 6345 return 0;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f4f2a0a3849d..d2a5763e5abc 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -830,7 +830,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
830 struct flowi *fl, 830 struct flowi *fl,
831 struct request_sock *req, 831 struct request_sock *req,
832 struct tcp_fastopen_cookie *foc, 832 struct tcp_fastopen_cookie *foc,
833 bool attach_req) 833 enum tcp_synack_type synack_type)
834{ 834{
835 const struct inet_request_sock *ireq = inet_rsk(req); 835 const struct inet_request_sock *ireq = inet_rsk(req);
836 struct flowi4 fl4; 836 struct flowi4 fl4;
@@ -841,7 +841,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
841 if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) 841 if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
842 return -1; 842 return -1;
843 843
844 skb = tcp_make_synack(sk, dst, req, foc, attach_req); 844 skb = tcp_make_synack(sk, dst, req, foc, synack_type);
845 845
846 if (skb) { 846 if (skb) {
847 __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); 847 __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7d2dc015cd19..6451b83d81e9 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2944,7 +2944,7 @@ int tcp_send_synack(struct sock *sk)
2944struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, 2944struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
2945 struct request_sock *req, 2945 struct request_sock *req,
2946 struct tcp_fastopen_cookie *foc, 2946 struct tcp_fastopen_cookie *foc,
2947 bool attach_req) 2947 enum tcp_synack_type synack_type)
2948{ 2948{
2949 struct inet_request_sock *ireq = inet_rsk(req); 2949 struct inet_request_sock *ireq = inet_rsk(req);
2950 const struct tcp_sock *tp = tcp_sk(sk); 2950 const struct tcp_sock *tp = tcp_sk(sk);
@@ -2964,14 +2964,22 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
2964 /* Reserve space for headers. */ 2964 /* Reserve space for headers. */
2965 skb_reserve(skb, MAX_TCP_HEADER); 2965 skb_reserve(skb, MAX_TCP_HEADER);
2966 2966
2967 if (attach_req) { 2967 switch (synack_type) {
2968 case TCP_SYNACK_NORMAL:
2968 skb_set_owner_w(skb, req_to_sk(req)); 2969 skb_set_owner_w(skb, req_to_sk(req));
2969 } else { 2970 break;
2971 case TCP_SYNACK_COOKIE:
2972 /* Under synflood, we do not attach skb to a socket,
2973 * to avoid false sharing.
2974 */
2975 break;
2976 case TCP_SYNACK_FASTOPEN:
2970 /* sk is a const pointer, because we want to express multiple 2977 /* sk is a const pointer, because we want to express multiple
2971 * cpu might call us concurrently. 2978 * cpu might call us concurrently.
2972 * sk->sk_wmem_alloc in an atomic, we can promote to rw. 2979 * sk->sk_wmem_alloc in an atomic, we can promote to rw.
2973 */ 2980 */
2974 skb_set_owner_w(skb, (struct sock *)sk); 2981 skb_set_owner_w(skb, (struct sock *)sk);
2982 break;
2975 } 2983 }
2976 skb_dst_set(skb, dst); 2984 skb_dst_set(skb, dst);
2977 2985
@@ -3516,7 +3524,7 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req)
3516 int res; 3524 int res;
3517 3525
3518 tcp_rsk(req)->txhash = net_tx_rndhash(); 3526 tcp_rsk(req)->txhash = net_tx_rndhash();
3519 res = af_ops->send_synack(sk, NULL, &fl, req, NULL, true); 3527 res = af_ops->send_synack(sk, NULL, &fl, req, NULL, TCP_SYNACK_NORMAL);
3520 if (!res) { 3528 if (!res) {
3521 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); 3529 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
3522 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); 3530 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 0e621bc1ae11..800265c7fd3f 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -439,7 +439,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
439 struct flowi *fl, 439 struct flowi *fl,
440 struct request_sock *req, 440 struct request_sock *req,
441 struct tcp_fastopen_cookie *foc, 441 struct tcp_fastopen_cookie *foc,
442 bool attach_req) 442 enum tcp_synack_type synack_type)
443{ 443{
444 struct inet_request_sock *ireq = inet_rsk(req); 444 struct inet_request_sock *ireq = inet_rsk(req);
445 struct ipv6_pinfo *np = inet6_sk(sk); 445 struct ipv6_pinfo *np = inet6_sk(sk);
@@ -452,7 +452,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
452 IPPROTO_TCP)) == NULL) 452 IPPROTO_TCP)) == NULL)
453 goto done; 453 goto done;
454 454
455 skb = tcp_make_synack(sk, dst, req, foc, attach_req); 455 skb = tcp_make_synack(sk, dst, req, foc, synack_type);
456 456
457 if (skb) { 457 if (skb) {
458 __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, 458 __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr,