diff options
-rw-r--r-- | include/net/tcp.h | 6 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 23 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 22 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 5 | ||||
-rw-r--r-- | net/sched/sch_fq.c | 12 |
8 files changed, 47 insertions, 32 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 225e9561af35..a6be56d5f0e3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -462,7 +462,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); | |||
462 | int tcp_connect(struct sock *sk); | 462 | int tcp_connect(struct sock *sk); |
463 | struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, | 463 | struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, |
464 | struct request_sock *req, | 464 | struct request_sock *req, |
465 | struct tcp_fastopen_cookie *foc); | 465 | struct tcp_fastopen_cookie *foc, |
466 | bool attach_req); | ||
466 | int tcp_disconnect(struct sock *sk, int flags); | 467 | int tcp_disconnect(struct sock *sk, int flags); |
467 | 468 | ||
468 | void tcp_finish_connect(struct sock *sk, struct sk_buff *skb); | 469 | void tcp_finish_connect(struct sock *sk, struct sk_buff *skb); |
@@ -1715,7 +1716,8 @@ struct tcp_request_sock_ops { | |||
1715 | __u32 (*init_seq)(const struct sk_buff *skb); | 1716 | __u32 (*init_seq)(const struct sk_buff *skb); |
1716 | int (*send_synack)(const struct sock *sk, struct dst_entry *dst, | 1717 | int (*send_synack)(const struct sock *sk, struct dst_entry *dst, |
1717 | struct flowi *fl, struct request_sock *req, | 1718 | struct flowi *fl, struct request_sock *req, |
1718 | u16 queue_mapping, struct tcp_fastopen_cookie *foc); | 1719 | u16 queue_mapping, struct tcp_fastopen_cookie *foc, |
1720 | bool attach_req); | ||
1719 | }; | 1721 | }; |
1720 | 1722 | ||
1721 | #ifdef CONFIG_SYN_COOKIES | 1723 | #ifdef CONFIG_SYN_COOKIES |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 80904df02187..099e0ea9242a 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -628,7 +628,7 @@ static void reqsk_queue_hash_req(struct request_sock *req, | |||
628 | * are committed to memory and refcnt initialized. | 628 | * are committed to memory and refcnt initialized. |
629 | */ | 629 | */ |
630 | smp_wmb(); | 630 | smp_wmb(); |
631 | atomic_set(&req->rsk_refcnt, 2); | 631 | atomic_set(&req->rsk_refcnt, 2 + 1); |
632 | } | 632 | } |
633 | 633 | ||
634 | void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, | 634 | void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, |
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index f69f436fcbcc..410ac481fda0 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c | |||
@@ -161,13 +161,13 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk, | |||
161 | tp->snd_wnd = ntohs(tcp_hdr(skb)->window); | 161 | tp->snd_wnd = ntohs(tcp_hdr(skb)->window); |
162 | 162 | ||
163 | /* Activate the retrans timer so that SYNACK can be retransmitted. | 163 | /* Activate the retrans timer so that SYNACK can be retransmitted. |
164 | * The request socket is not added to the SYN table of the parent | 164 | * The request socket is not added to the ehash |
165 | * because it's been added to the accept queue directly. | 165 | * because it's been added to the accept queue directly. |
166 | */ | 166 | */ |
167 | inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS, | 167 | inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS, |
168 | TCP_TIMEOUT_INIT, TCP_RTO_MAX); | 168 | TCP_TIMEOUT_INIT, TCP_RTO_MAX); |
169 | 169 | ||
170 | atomic_set(&req->rsk_refcnt, 1); | 170 | atomic_set(&req->rsk_refcnt, 2); |
171 | /* Add the child socket directly into the accept queue */ | 171 | /* Add the child socket directly into the accept queue */ |
172 | inet_csk_reqsk_queue_add(sk, req, child); | 172 | inet_csk_reqsk_queue_add(sk, req, child); |
173 | 173 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a56912772354..27108757c310 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -6120,8 +6120,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, | |||
6120 | struct request_sock *req; | 6120 | struct request_sock *req; |
6121 | bool want_cookie = false; | 6121 | bool want_cookie = false; |
6122 | struct flowi fl; | 6122 | struct flowi fl; |
6123 | int err; | ||
6124 | |||
6125 | 6123 | ||
6126 | /* TW buckets are converted to open requests without | 6124 | /* TW buckets are converted to open requests without |
6127 | * limitations, they conserve resources and peer is | 6125 | * limitations, they conserve resources and peer is |
@@ -6230,21 +6228,24 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, | |||
6230 | tcp_rsk(req)->snt_isn = isn; | 6228 | tcp_rsk(req)->snt_isn = isn; |
6231 | tcp_rsk(req)->txhash = net_tx_rndhash(); | 6229 | tcp_rsk(req)->txhash = net_tx_rndhash(); |
6232 | tcp_openreq_init_rwin(req, sk, dst); | 6230 | tcp_openreq_init_rwin(req, sk, dst); |
6233 | if (!want_cookie) | 6231 | if (!want_cookie) { |
6234 | fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); | 6232 | fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); |
6235 | err = af_ops->send_synack(fastopen_sk ?: sk, dst, &fl, req, | 6233 | tcp_reqsk_record_syn(sk, req, skb); |
6236 | skb_get_queue_mapping(skb), &foc); | 6234 | } |
6237 | if (fastopen_sk) { | 6235 | if (fastopen_sk) { |
6236 | af_ops->send_synack(fastopen_sk, dst, &fl, req, | ||
6237 | skb_get_queue_mapping(skb), &foc, false); | ||
6238 | sock_put(fastopen_sk); | 6238 | sock_put(fastopen_sk); |
6239 | } else { | 6239 | } else { |
6240 | if (err || want_cookie) | ||
6241 | goto drop_and_free; | ||
6242 | |||
6243 | tcp_rsk(req)->tfo_listener = false; | 6240 | tcp_rsk(req)->tfo_listener = false; |
6244 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 6241 | if (!want_cookie) |
6242 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||
6243 | af_ops->send_synack(sk, dst, &fl, req, | ||
6244 | skb_get_queue_mapping(skb), &foc, !want_cookie); | ||
6245 | if (want_cookie) | ||
6246 | goto drop_and_free; | ||
6245 | } | 6247 | } |
6246 | tcp_reqsk_record_syn(sk, req, skb); | 6248 | reqsk_put(req); |
6247 | |||
6248 | return 0; | 6249 | return 0; |
6249 | 6250 | ||
6250 | drop_and_release: | 6251 | drop_and_release: |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index bfe9d39ee87d..ac2ea73e9aaf 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -822,7 +822,8 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
822 | struct flowi *fl, | 822 | struct flowi *fl, |
823 | struct request_sock *req, | 823 | struct request_sock *req, |
824 | u16 queue_mapping, | 824 | u16 queue_mapping, |
825 | struct tcp_fastopen_cookie *foc) | 825 | struct tcp_fastopen_cookie *foc, |
826 | bool attach_req) | ||
826 | { | 827 | { |
827 | const struct inet_request_sock *ireq = inet_rsk(req); | 828 | const struct inet_request_sock *ireq = inet_rsk(req); |
828 | struct flowi4 fl4; | 829 | struct flowi4 fl4; |
@@ -833,7 +834,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
833 | if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) | 834 | if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) |
834 | return -1; | 835 | return -1; |
835 | 836 | ||
836 | skb = tcp_make_synack(sk, dst, req, foc); | 837 | skb = tcp_make_synack(sk, dst, req, foc, attach_req); |
837 | 838 | ||
838 | if (skb) { | 839 | if (skb) { |
839 | __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); | 840 | __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 09bb082ca1a7..55ed3266b05f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2947,7 +2947,8 @@ int tcp_send_synack(struct sock *sk) | |||
2947 | */ | 2947 | */ |
2948 | struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, | 2948 | struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, |
2949 | struct request_sock *req, | 2949 | struct request_sock *req, |
2950 | struct tcp_fastopen_cookie *foc) | 2950 | struct tcp_fastopen_cookie *foc, |
2951 | bool attach_req) | ||
2951 | { | 2952 | { |
2952 | struct inet_request_sock *ireq = inet_rsk(req); | 2953 | struct inet_request_sock *ireq = inet_rsk(req); |
2953 | const struct tcp_sock *tp = tcp_sk(sk); | 2954 | const struct tcp_sock *tp = tcp_sk(sk); |
@@ -2959,11 +2960,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, | |||
2959 | u16 user_mss; | 2960 | u16 user_mss; |
2960 | int mss; | 2961 | int mss; |
2961 | 2962 | ||
2962 | /* sk is a const pointer, because we want to express multiple cpus | 2963 | skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); |
2963 | * might call us concurrently. | ||
2964 | * sock_wmalloc() will change sk->sk_wmem_alloc in an atomic way. | ||
2965 | */ | ||
2966 | skb = sock_wmalloc((struct sock *)sk, MAX_TCP_HEADER, 1, GFP_ATOMIC); | ||
2967 | if (unlikely(!skb)) { | 2964 | if (unlikely(!skb)) { |
2968 | dst_release(dst); | 2965 | dst_release(dst); |
2969 | return NULL; | 2966 | return NULL; |
@@ -2971,6 +2968,17 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, | |||
2971 | /* Reserve space for headers. */ | 2968 | /* Reserve space for headers. */ |
2972 | skb_reserve(skb, MAX_TCP_HEADER); | 2969 | skb_reserve(skb, MAX_TCP_HEADER); |
2973 | 2970 | ||
2971 | if (attach_req) { | ||
2972 | skb->destructor = sock_edemux; | ||
2973 | sock_hold(req_to_sk(req)); | ||
2974 | skb->sk = req_to_sk(req); | ||
2975 | } else { | ||
2976 | /* sk is a const pointer, because we want to express multiple | ||
2977 | * cpu might call us concurrently. | ||
2978 | * sk->sk_wmem_alloc in an atomic, we can promote to rw. | ||
2979 | */ | ||
2980 | skb_set_owner_w(skb, (struct sock *)sk); | ||
2981 | } | ||
2974 | skb_dst_set(skb, dst); | 2982 | skb_dst_set(skb, dst); |
2975 | 2983 | ||
2976 | mss = dst_metric_advmss(dst); | 2984 | mss = dst_metric_advmss(dst); |
@@ -3510,7 +3518,7 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) | |||
3510 | int res; | 3518 | int res; |
3511 | 3519 | ||
3512 | tcp_rsk(req)->txhash = net_tx_rndhash(); | 3520 | tcp_rsk(req)->txhash = net_tx_rndhash(); |
3513 | res = af_ops->send_synack(sk, NULL, &fl, req, 0, NULL); | 3521 | res = af_ops->send_synack(sk, NULL, &fl, req, 0, NULL, true); |
3514 | if (!res) { | 3522 | if (!res) { |
3515 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | 3523 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); |
3516 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); | 3524 | 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 a215614cfb2b..3d18571811c5 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -438,7 +438,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
438 | struct flowi *fl, | 438 | struct flowi *fl, |
439 | struct request_sock *req, | 439 | struct request_sock *req, |
440 | u16 queue_mapping, | 440 | u16 queue_mapping, |
441 | struct tcp_fastopen_cookie *foc) | 441 | struct tcp_fastopen_cookie *foc, |
442 | bool attach_req) | ||
442 | { | 443 | { |
443 | struct inet_request_sock *ireq = inet_rsk(req); | 444 | struct inet_request_sock *ireq = inet_rsk(req); |
444 | struct ipv6_pinfo *np = inet6_sk(sk); | 445 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -451,7 +452,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
451 | IPPROTO_TCP)) == NULL) | 452 | IPPROTO_TCP)) == NULL) |
452 | goto done; | 453 | goto done; |
453 | 454 | ||
454 | skb = tcp_make_synack(sk, dst, req, foc); | 455 | skb = tcp_make_synack(sk, dst, req, foc, attach_req); |
455 | 456 | ||
456 | if (skb) { | 457 | if (skb) { |
457 | __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, | 458 | __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, |
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index f377702d4b91..3386cce4751e 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c | |||
@@ -224,13 +224,15 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q) | |||
224 | if (unlikely((skb->priority & TC_PRIO_MAX) == TC_PRIO_CONTROL)) | 224 | if (unlikely((skb->priority & TC_PRIO_MAX) == TC_PRIO_CONTROL)) |
225 | return &q->internal; | 225 | return &q->internal; |
226 | 226 | ||
227 | /* SYNACK messages are attached to a listener socket. | 227 | /* SYNACK messages are attached to a TCP_NEW_SYN_RECV request socket |
228 | * 1) They are not part of a 'flow' yet | 228 | * 1) request sockets are not full blown, |
229 | * 2) We do not want to rate limit them (eg SYNFLOOD attack), | 229 | * they do not contain sk_pacing_rate |
230 | * 2) They are not part of a 'flow' yet | ||
231 | * 3) We do not want to rate limit them (eg SYNFLOOD attack), | ||
230 | * especially if the listener set SO_MAX_PACING_RATE | 232 | * especially if the listener set SO_MAX_PACING_RATE |
231 | * 3) We pretend they are orphaned | 233 | * 4) We pretend they are orphaned |
232 | */ | 234 | */ |
233 | if (!sk || sk->sk_state == TCP_LISTEN) { | 235 | if (!sk || sk->sk_state == TCP_NEW_SYN_RECV) { |
234 | unsigned long hash = skb_get_hash(skb) & q->orphan_mask; | 236 | unsigned long hash = skb_get_hash(skb) & q->orphan_mask; |
235 | 237 | ||
236 | /* By forcing low order bit to 1, we make sure to not | 238 | /* By forcing low order bit to 1, we make sure to not |