Commit 750f2f91 authored by David S. Miller's avatar David S. Miller

Merge branch 'listener_refactor_part_14'

Eric Dumazet says:

====================
inet: tcp listener refactoring part 14

OK, we have serious patches here.

We get rid of the central timer handling SYNACK rtx,
which is killing us under even medium SYN flood.

We still use the listener specific hash table.

This will be done in next round ;)
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a998f712 becb74f0
...@@ -28,8 +28,7 @@ int inet6_csk_bind_conflict(const struct sock *sk, ...@@ -28,8 +28,7 @@ int inet6_csk_bind_conflict(const struct sock *sk,
struct dst_entry *inet6_csk_route_req(struct sock *sk, struct flowi6 *fl6, struct dst_entry *inet6_csk_route_req(struct sock *sk, struct flowi6 *fl6,
const struct request_sock *req); const struct request_sock *req);
struct request_sock *inet6_csk_search_req(const struct sock *sk, struct request_sock *inet6_csk_search_req(struct sock *sk,
struct request_sock ***prevp,
const __be16 rport, const __be16 rport,
const struct in6_addr *raddr, const struct in6_addr *raddr,
const struct in6_addr *laddr, const struct in6_addr *laddr,
......
...@@ -256,8 +256,7 @@ inet_csk_rto_backoff(const struct inet_connection_sock *icsk, ...@@ -256,8 +256,7 @@ inet_csk_rto_backoff(const struct inet_connection_sock *icsk,
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err); struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
struct request_sock *inet_csk_search_req(const struct sock *sk, struct request_sock *inet_csk_search_req(struct sock *sk,
struct request_sock ***prevp,
const __be16 rport, const __be16 rport,
const __be32 raddr, const __be32 raddr,
const __be32 laddr); const __be32 laddr);
...@@ -283,15 +282,13 @@ void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, ...@@ -283,15 +282,13 @@ void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
static inline void inet_csk_reqsk_queue_removed(struct sock *sk, static inline void inet_csk_reqsk_queue_removed(struct sock *sk,
struct request_sock *req) struct request_sock *req)
{ {
if (reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req) == 0) reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
inet_csk_delete_keepalive_timer(sk);
} }
static inline void inet_csk_reqsk_queue_added(struct sock *sk, static inline void inet_csk_reqsk_queue_added(struct sock *sk,
const unsigned long timeout) const unsigned long timeout)
{ {
if (reqsk_queue_added(&inet_csk(sk)->icsk_accept_queue) == 0) reqsk_queue_added(&inet_csk(sk)->icsk_accept_queue);
inet_csk_reset_keepalive_timer(sk, timeout);
} }
static inline int inet_csk_reqsk_queue_len(const struct sock *sk) static inline int inet_csk_reqsk_queue_len(const struct sock *sk)
...@@ -310,26 +307,19 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) ...@@ -310,26 +307,19 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
} }
static inline void inet_csk_reqsk_queue_unlink(struct sock *sk, static inline void inet_csk_reqsk_queue_unlink(struct sock *sk,
struct request_sock *req, struct request_sock *req)
struct request_sock **prev)
{ {
reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev); reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req);
} }
static inline void inet_csk_reqsk_queue_drop(struct sock *sk, static inline void inet_csk_reqsk_queue_drop(struct sock *sk,
struct request_sock *req, struct request_sock *req)
struct request_sock **prev)
{ {
inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req); inet_csk_reqsk_queue_removed(sk, req);
reqsk_free(req); reqsk_put(req);
} }
void inet_csk_reqsk_queue_prune(struct sock *parent,
const unsigned long interval,
const unsigned long timeout,
const unsigned long max_rto);
void inet_csk_destroy_sock(struct sock *sk); void inet_csk_destroy_sock(struct sock *sk);
void inet_csk_prepare_forced_close(struct sock *sk); void inet_csk_prepare_forced_close(struct sock *sk);
......
...@@ -50,6 +50,7 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req); ...@@ -50,6 +50,7 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req);
struct request_sock { struct request_sock {
struct sock_common __req_common; struct sock_common __req_common;
#define rsk_refcnt __req_common.skc_refcnt #define rsk_refcnt __req_common.skc_refcnt
#define rsk_hash __req_common.skc_hash
struct request_sock *dl_next; struct request_sock *dl_next;
struct sock *rsk_listener; struct sock *rsk_listener;
...@@ -61,7 +62,7 @@ struct request_sock { ...@@ -61,7 +62,7 @@ struct request_sock {
u32 window_clamp; /* window clamp at creation time */ u32 window_clamp; /* window clamp at creation time */
u32 rcv_wnd; /* rcv_wnd offered first time */ u32 rcv_wnd; /* rcv_wnd offered first time */
u32 ts_recent; u32 ts_recent;
unsigned long expires; struct timer_list rsk_timer;
const struct request_sock_ops *rsk_ops; const struct request_sock_ops *rsk_ops;
struct sock *sk; struct sock *sk;
u32 secid; u32 secid;
...@@ -109,9 +110,6 @@ static inline void reqsk_free(struct request_sock *req) ...@@ -109,9 +110,6 @@ static inline void reqsk_free(struct request_sock *req)
static inline void reqsk_put(struct request_sock *req) static inline void reqsk_put(struct request_sock *req)
{ {
/* temporary debugging, until req sock are put into ehash table */
WARN_ON_ONCE(atomic_read(&req->rsk_refcnt) != 1);
if (atomic_dec_and_test(&req->rsk_refcnt)) if (atomic_dec_and_test(&req->rsk_refcnt))
reqsk_free(req); reqsk_free(req);
} }
...@@ -123,12 +121,16 @@ extern int sysctl_max_syn_backlog; ...@@ -123,12 +121,16 @@ extern int sysctl_max_syn_backlog;
* @max_qlen_log - log_2 of maximal queued SYNs/REQUESTs * @max_qlen_log - log_2 of maximal queued SYNs/REQUESTs
*/ */
struct listen_sock { struct listen_sock {
u8 max_qlen_log; int qlen_inc; /* protected by listener lock */
int young_inc;/* protected by listener lock */
/* following fields can be updated by timer */
atomic_t qlen_dec; /* qlen = qlen_inc - qlen_dec */
atomic_t young_dec;
u8 max_qlen_log ____cacheline_aligned_in_smp;
u8 synflood_warned; u8 synflood_warned;
/* 2 bytes hole, try to use */ /* 2 bytes hole, try to use */
int qlen;
int qlen_young;
int clock_hand;
u32 hash_rnd; u32 hash_rnd;
u32 nr_table_entries; u32 nr_table_entries;
struct request_sock *syn_table[0]; struct request_sock *syn_table[0];
...@@ -181,9 +183,7 @@ struct fastopen_queue { ...@@ -181,9 +183,7 @@ struct fastopen_queue {
struct request_sock_queue { struct request_sock_queue {
struct request_sock *rskq_accept_head; struct request_sock *rskq_accept_head;
struct request_sock *rskq_accept_tail; struct request_sock *rskq_accept_tail;
rwlock_t syn_wait_lock;
u8 rskq_defer_accept; u8 rskq_defer_accept;
/* 3 bytes hole, try to pack */
struct listen_sock *listen_opt; struct listen_sock *listen_opt;
struct fastopen_queue *fastopenq; /* This is non-NULL iff TFO has been struct fastopen_queue *fastopenq; /* This is non-NULL iff TFO has been
* enabled on this listener. Check * enabled on this listener. Check
...@@ -191,6 +191,9 @@ struct request_sock_queue { ...@@ -191,6 +191,9 @@ struct request_sock_queue {
* to determine if TFO is enabled * to determine if TFO is enabled
* right at this moment. * right at this moment.
*/ */
/* temporary alignment, our goal is to get rid of this lock */
rwlock_t syn_wait_lock ____cacheline_aligned_in_smp;
}; };
int reqsk_queue_alloc(struct request_sock_queue *queue, int reqsk_queue_alloc(struct request_sock_queue *queue,
...@@ -216,12 +219,21 @@ static inline int reqsk_queue_empty(struct request_sock_queue *queue) ...@@ -216,12 +219,21 @@ static inline int reqsk_queue_empty(struct request_sock_queue *queue)
} }
static inline void reqsk_queue_unlink(struct request_sock_queue *queue, static inline void reqsk_queue_unlink(struct request_sock_queue *queue,
struct request_sock *req, struct request_sock *req)
struct request_sock **prev_req)
{ {
struct listen_sock *lopt = queue->listen_opt;
struct request_sock **prev;
write_lock(&queue->syn_wait_lock); write_lock(&queue->syn_wait_lock);
*prev_req = req->dl_next;
prev = &lopt->syn_table[req->rsk_hash];
while (*prev != req)
prev = &(*prev)->dl_next;
*prev = req->dl_next;
write_unlock(&queue->syn_wait_lock); write_unlock(&queue->syn_wait_lock);
if (del_timer(&req->rsk_timer))
reqsk_put(req);
} }
static inline void reqsk_queue_add(struct request_sock_queue *queue, static inline void reqsk_queue_add(struct request_sock_queue *queue,
...@@ -254,63 +266,53 @@ static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue ...@@ -254,63 +266,53 @@ static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue
return req; return req;
} }
static inline int reqsk_queue_removed(struct request_sock_queue *queue, static inline void reqsk_queue_removed(struct request_sock_queue *queue,
struct request_sock *req) const struct request_sock *req)
{ {
struct listen_sock *lopt = queue->listen_opt; struct listen_sock *lopt = queue->listen_opt;
if (req->num_timeout == 0) if (req->num_timeout == 0)
--lopt->qlen_young; atomic_inc(&lopt->young_dec);
atomic_inc(&lopt->qlen_dec);
return --lopt->qlen;
} }
static inline int reqsk_queue_added(struct request_sock_queue *queue) static inline void reqsk_queue_added(struct request_sock_queue *queue)
{ {
struct listen_sock *lopt = queue->listen_opt; struct listen_sock *lopt = queue->listen_opt;
const int prev_qlen = lopt->qlen;
lopt->qlen_young++; lopt->young_inc++;
lopt->qlen++; lopt->qlen_inc++;
return prev_qlen;
} }
static inline int reqsk_queue_len(const struct request_sock_queue *queue) static inline int listen_sock_qlen(const struct listen_sock *lopt)
{ {
return queue->listen_opt != NULL ? queue->listen_opt->qlen : 0; return lopt->qlen_inc - atomic_read(&lopt->qlen_dec);
} }
static inline int reqsk_queue_len_young(const struct request_sock_queue *queue) static inline int listen_sock_young(const struct listen_sock *lopt)
{ {
return queue->listen_opt->qlen_young; return lopt->young_inc - atomic_read(&lopt->young_dec);
} }
static inline int reqsk_queue_is_full(const struct request_sock_queue *queue) static inline int reqsk_queue_len(const struct request_sock_queue *queue)
{ {
return queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log; const struct listen_sock *lopt = queue->listen_opt;
return lopt ? listen_sock_qlen(lopt) : 0;
} }
static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, static inline int reqsk_queue_len_young(const struct request_sock_queue *queue)
u32 hash, struct request_sock *req,
unsigned long timeout)
{ {
struct listen_sock *lopt = queue->listen_opt; return listen_sock_young(queue->listen_opt);
}
req->expires = jiffies + timeout;
req->num_retrans = 0;
req->num_timeout = 0;
req->sk = NULL;
req->dl_next = lopt->syn_table[hash];
/* before letting lookups find us, make sure all req fields
* are committed to memory and refcnt initialized.
*/
smp_wmb();
atomic_set(&req->rsk_refcnt, 1);
write_lock(&queue->syn_wait_lock); static inline int reqsk_queue_is_full(const struct request_sock_queue *queue)
lopt->syn_table[hash] = req; {
write_unlock(&queue->syn_wait_lock); return reqsk_queue_len(queue) >> queue->listen_opt->max_qlen_log;
} }
void reqsk_queue_hash_req(struct request_sock_queue *queue,
u32 hash, struct request_sock *req,
unsigned long timeout);
#endif /* _REQUEST_SOCK_H */ #endif /* _REQUEST_SOCK_H */
...@@ -405,8 +405,8 @@ struct sock { ...@@ -405,8 +405,8 @@ struct sock {
rwlock_t sk_callback_lock; rwlock_t sk_callback_lock;
int sk_err, int sk_err,
sk_err_soft; sk_err_soft;
unsigned short sk_ack_backlog; u32 sk_ack_backlog;
unsigned short sk_max_ack_backlog; u32 sk_max_ack_backlog;
__u32 sk_priority; __u32 sk_priority;
#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
__u32 sk_cgrp_prioidx; __u32 sk_cgrp_prioidx;
......
...@@ -406,8 +406,7 @@ enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw, ...@@ -406,8 +406,7 @@ enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
struct sk_buff *skb, struct sk_buff *skb,
const struct tcphdr *th); const struct tcphdr *th);
struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock **prev, struct request_sock *req, bool fastopen);
bool fastopen);
int tcp_child_process(struct sock *parent, struct sock *child, int tcp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb); struct sk_buff *skb);
void tcp_enter_loss(struct sock *sk); void tcp_enter_loss(struct sock *sk);
......
...@@ -94,21 +94,26 @@ void reqsk_queue_destroy(struct request_sock_queue *queue) ...@@ -94,21 +94,26 @@ void reqsk_queue_destroy(struct request_sock_queue *queue)
/* make all the listen_opt local to us */ /* make all the listen_opt local to us */
struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue); struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue);
if (lopt->qlen != 0) { if (listen_sock_qlen(lopt) != 0) {
unsigned int i; unsigned int i;
for (i = 0; i < lopt->nr_table_entries; i++) { for (i = 0; i < lopt->nr_table_entries; i++) {
struct request_sock *req; struct request_sock *req;
write_lock_bh(&queue->syn_wait_lock);
while ((req = lopt->syn_table[i]) != NULL) { while ((req = lopt->syn_table[i]) != NULL) {
lopt->syn_table[i] = req->dl_next; lopt->syn_table[i] = req->dl_next;
lopt->qlen--; atomic_inc(&lopt->qlen_dec);
if (del_timer(&req->rsk_timer))
reqsk_put(req);
reqsk_put(req); reqsk_put(req);
} }
write_unlock_bh(&queue->syn_wait_lock);
} }
} }
WARN_ON(lopt->qlen != 0); if (WARN_ON(listen_sock_qlen(lopt) != 0))
pr_err("qlen %u\n", listen_sock_qlen(lopt));
kvfree(lopt); kvfree(lopt);
} }
...@@ -187,7 +192,7 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, ...@@ -187,7 +192,7 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req,
* *
* For more details see CoNext'11 "TCP Fast Open" paper. * For more details see CoNext'11 "TCP Fast Open" paper.
*/ */
req->expires = jiffies + 60*HZ; req->rsk_timer.expires = jiffies + 60*HZ;
if (fastopenq->rskq_rst_head == NULL) if (fastopenq->rskq_rst_head == NULL)
fastopenq->rskq_rst_head = req; fastopenq->rskq_rst_head = req;
else else
......
...@@ -2739,7 +2739,7 @@ static int req_prot_init(const struct proto *prot) ...@@ -2739,7 +2739,7 @@ static int req_prot_init(const struct proto *prot)
rsk_prot->slab = kmem_cache_create(rsk_prot->slab_name, rsk_prot->slab = kmem_cache_create(rsk_prot->slab_name,
rsk_prot->obj_size, 0, rsk_prot->obj_size, 0,
SLAB_HWCACHE_ALIGN, NULL); 0, NULL);
if (!rsk_prot->slab) { if (!rsk_prot->slab) {
pr_crit("%s: Can't create request sock SLAB cache!\n", pr_crit("%s: Can't create request sock SLAB cache!\n",
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
static int zero = 0; static int zero = 0;
static int one = 1; static int one = 1;
static int ushort_max = USHRT_MAX;
static int net_msg_warn; /* Unused, but still a sysctl */ static int net_msg_warn; /* Unused, but still a sysctl */
...@@ -401,7 +400,6 @@ static struct ctl_table netns_core_table[] = { ...@@ -401,7 +400,6 @@ static struct ctl_table netns_core_table[] = {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.extra1 = &zero, .extra1 = &zero,
.extra2 = &ushort_max,
.proc_handler = proc_dointvec_minmax .proc_handler = proc_dointvec_minmax
}, },
{ } { }
......
...@@ -280,8 +280,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -280,8 +280,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock *req,
struct dst_entry *dst); struct dst_entry *dst);
struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock *req);
struct request_sock **prev);
int dccp_child_process(struct sock *parent, struct sock *child, int dccp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb); struct sk_buff *skb);
......
...@@ -288,11 +288,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) ...@@ -288,11 +288,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
} }
switch (sk->sk_state) { switch (sk->sk_state) {
struct request_sock *req , **prev; struct request_sock *req;
case DCCP_LISTEN: case DCCP_LISTEN:
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
goto out; goto out;
req = inet_csk_search_req(sk, &prev, dh->dccph_dport, req = inet_csk_search_req(sk, dh->dccph_dport,
iph->daddr, iph->saddr); iph->daddr, iph->saddr);
if (!req) if (!req)
goto out; goto out;
...@@ -306,6 +306,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) ...@@ -306,6 +306,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
if (!between48(seq, dccp_rsk(req)->dreq_iss, if (!between48(seq, dccp_rsk(req)->dreq_iss,
dccp_rsk(req)->dreq_gss)) { dccp_rsk(req)->dreq_gss)) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
reqsk_put(req);
goto out; goto out;
} }
/* /*
...@@ -314,7 +315,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) ...@@ -314,7 +315,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
* created socket, and POSIX does not want network * created socket, and POSIX does not want network
* errors returned from accept(). * errors returned from accept().
*/ */
inet_csk_reqsk_queue_drop(sk, req, prev); inet_csk_reqsk_queue_drop(sk, req);
reqsk_put(req);
goto out; goto out;
case DCCP_REQUESTING: case DCCP_REQUESTING:
...@@ -448,14 +450,14 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) ...@@ -448,14 +450,14 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
const struct dccp_hdr *dh = dccp_hdr(skb); const struct dccp_hdr *dh = dccp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
struct sock *nsk; struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */ /* Find possible connection requests. */
struct request_sock *req = inet_csk_search_req(sk, &prev, struct request_sock *req = inet_csk_search_req(sk, dh->dccph_sport,
dh->dccph_sport,
iph->saddr, iph->daddr); iph->saddr, iph->daddr);
if (req != NULL) if (req) {
return dccp_check_req(sk, skb, req, prev); nsk = dccp_check_req(sk, skb, req);
reqsk_put(req);
return nsk;
}
nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo, nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo,
iph->saddr, dh->dccph_sport, iph->saddr, dh->dccph_sport,
iph->daddr, dh->dccph_dport, iph->daddr, dh->dccph_dport,
......
...@@ -149,15 +149,15 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -149,15 +149,15 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
/* Might be for an request_sock */ /* Might be for an request_sock */
switch (sk->sk_state) { switch (sk->sk_state) {
struct request_sock *req, **prev; struct request_sock *req;
case DCCP_LISTEN: case DCCP_LISTEN:
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
goto out; goto out;
req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, req = inet6_csk_search_req(sk, dh->dccph_dport,
&hdr->daddr, &hdr->saddr, &hdr->daddr, &hdr->saddr,
inet6_iif(skb)); inet6_iif(skb));
if (req == NULL) if (!req)
goto out; goto out;
/* /*
...@@ -169,10 +169,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -169,10 +169,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!between48(seq, dccp_rsk(req)->dreq_iss, if (!between48(seq, dccp_rsk(req)->dreq_iss,
dccp_rsk(req)->dreq_gss)) { dccp_rsk(req)->dreq_gss)) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
reqsk_put(req);
goto out; goto out;
} }
inet_csk_reqsk_queue_drop(sk, req, prev); inet_csk_reqsk_queue_drop(sk, req);
reqsk_put(req);
goto out; goto out;
case DCCP_REQUESTING: case DCCP_REQUESTING:
...@@ -317,17 +319,16 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) ...@@ -317,17 +319,16 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
{ {
const struct dccp_hdr *dh = dccp_hdr(skb); const struct dccp_hdr *dh = dccp_hdr(skb);
const struct ipv6hdr *iph = ipv6_hdr(skb); const struct ipv6hdr *iph = ipv6_hdr(skb);
struct request_sock *req;
struct sock *nsk; struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */
struct request_sock *req = inet6_csk_search_req(sk, &prev,
dh->dccph_sport,
&iph->saddr,
&iph->daddr,
inet6_iif(skb));
if (req != NULL)
return dccp_check_req(sk, skb, req, prev);
req = inet6_csk_search_req(sk, dh->dccph_sport, &iph->saddr,
&iph->daddr, inet6_iif(skb));
if (req) {
nsk = dccp_check_req(sk, skb, req);
reqsk_put(req);
return nsk;
}
nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo, nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
&iph->saddr, dh->dccph_sport, &iph->saddr, dh->dccph_sport,
&iph->daddr, ntohs(dh->dccph_dport), &iph->daddr, ntohs(dh->dccph_dport),
......
...@@ -152,8 +152,7 @@ EXPORT_SYMBOL_GPL(dccp_create_openreq_child); ...@@ -152,8 +152,7 @@ EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
* as an request_sock. * as an request_sock.
*/ */
struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock *req)
struct request_sock **prev)
{ {
struct sock *child = NULL; struct sock *child = NULL;
struct dccp_request_sock *dreq = dccp_rsk(req); struct dccp_request_sock *dreq = dccp_rsk(req);
...@@ -200,7 +199,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -200,7 +199,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
if (child == NULL) if (child == NULL)
goto listen_overflow; goto listen_overflow;
inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req); inet_csk_reqsk_queue_removed(sk, req);
inet_csk_reqsk_queue_add(sk, req, child); inet_csk_reqsk_queue_add(sk, req, child);
out: out:
...@@ -212,7 +211,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -212,7 +211,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
req->rsk_ops->send_reset(sk, skb); req->rsk_ops->send_reset(sk, skb);
inet_csk_reqsk_queue_drop(sk, req, prev); inet_csk_reqsk_queue_drop(sk, req);
goto out; goto out;
} }
......
...@@ -161,33 +161,11 @@ static void dccp_write_timer(unsigned long data) ...@@ -161,33 +161,11 @@ static void dccp_write_timer(unsigned long data)
sock_put(sk); sock_put(sk);
} }
/*
* Timer for listening sockets
*/
static void dccp_response_timer(struct sock *sk)
{
inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL, DCCP_TIMEOUT_INIT,
DCCP_RTO_MAX);
}
static void dccp_keepalive_timer(unsigned long data) static void dccp_keepalive_timer(unsigned long data)
{ {
struct sock *sk = (struct sock *)data; struct sock *sk = (struct sock *)data;
/* Only process if socket is not in use. */ pr_err("dccp should not use a keepalive timer !\n");
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
/* Try again later. */
inet_csk_reset_keepalive_timer(sk, HZ / 20);
goto out;
}
if (sk->sk_state == DCCP_LISTEN) {
dccp_response_timer(sk);
goto out;
}
out:
bh_unlock_sock(sk);
sock_put(sk); sock_put(sk);
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <net/route.h> #include <net/route.h>
#include <net/tcp_states.h> #include <net/tcp_states.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/tcp.h>
#ifdef INET_CSK_DEBUG #ifdef INET_CSK_DEBUG
const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n"; const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n";
...@@ -476,33 +477,37 @@ static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, ...@@ -476,33 +477,37 @@ static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
#define AF_INET_FAMILY(fam) ((fam) == AF_INET) #define AF_INET_FAMILY(fam) ((fam) == AF_INET)
#else #else
#define AF_INET_FAMILY(fam) 1 #define AF_INET_FAMILY(fam) true
#endif #endif
struct request_sock *inet_csk_search_req(const struct sock *sk, /* Note: this is temporary :
struct request_sock ***prevp, * req sock will no longer be in listener hash table
const __be16 rport, const __be32 raddr, */
struct request_sock *inet_csk_search_req(struct sock *sk,
const __be16 rport,
const __be32 raddr,
const __be32 laddr) const __be32 laddr)
{ {
const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
struct request_sock *req, **prev; struct request_sock *req;
u32 hash = inet_synq_hash(raddr, rport, lopt->hash_rnd,
lopt->nr_table_entries);
for (prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd, write_lock(&icsk->icsk_accept_queue.syn_wait_lock);
lopt->nr_table_entries)]; for (req = lopt->syn_table[hash]; req != NULL; req = req->dl_next) {
(req = *prev) != NULL;
prev = &req->dl_next) {
const struct inet_request_sock *ireq = inet_rsk(req); const struct inet_request_sock *ireq = inet_rsk(req);
if (ireq->ir_rmt_port == rport && if (ireq->ir_rmt_port == rport &&
ireq->ir_rmt_addr == raddr && ireq->ir_rmt_addr == raddr &&
ireq->ir_loc_addr == laddr && ireq->ir_loc_addr == laddr &&
AF_INET_FAMILY(req->rsk_ops->family)) { AF_INET_FAMILY(req->rsk_ops->family)) {
atomic_inc(&req->rsk_refcnt);
WARN_ON(req->sk); WARN_ON(req->sk);
*prevp = prev;
break; break;
} }
} }
write_unlock(&icsk->icsk_accept_queue.syn_wait_lock);
return req; return req;
} }
...@@ -558,23 +563,23 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req) ...@@ -558,23 +563,23 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req)
} }
EXPORT_SYMBOL(inet_rtx_syn_ack); EXPORT_SYMBOL(inet_rtx_syn_ack);
void inet_csk_reqsk_queue_prune(struct sock *parent, static void reqsk_timer_handler(unsigned long data)
const unsigned long interval,
const unsigned long timeout,
const unsigned long max_rto)
{ {
struct inet_connection_sock *icsk = inet_csk(parent); struct request_sock *req = (struct request_sock *)data;
struct sock *sk_listener = req->rsk_listener;
struct inet_connection_sock *icsk = inet_csk(sk_listener);
struct request_sock_queue *queue = &icsk->icsk_accept_queue; struct request_sock_queue *queue = &icsk->icsk_accept_queue;
struct listen_sock *lopt = queue->listen_opt; struct listen_sock *lopt = queue->listen_opt;
int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; int expire = 0, resend = 0;
int thresh = max_retries; int max_retries, thresh;
unsigned long now = jiffies;
struct request_sock **reqp, *req;
int i, budget;
if (lopt == NULL || lopt->qlen == 0) if (sk_listener->sk_state != TCP_LISTEN || !lopt) {
reqsk_put(req);
return; return;
}
max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
thresh = max_retries;
/* Normally all the openreqs are young and become mature /* Normally all the openreqs are young and become mature
* (i.e. converted to established socket) for first timeout. * (i.e. converted to established socket) for first timeout.
* If synack was not acknowledged for 1 second, it means * If synack was not acknowledged for 1 second, it means
...@@ -592,67 +597,63 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, ...@@ -592,67 +597,63 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
* embrions; and abort old ones without pity, if old * embrions; and abort old ones without pity, if old
* ones are about to clog our table. * ones are about to clog our table.
*/ */
if (lopt->qlen>>(lopt->max_qlen_log-1)) { if (listen_sock_qlen(lopt) >> (lopt->max_qlen_log - 1)) {
int young = (lopt->qlen_young<<1); int young = listen_sock_young(lopt) << 1;
while (thresh > 2) { while (thresh > 2) {
if (lopt->qlen < young) if (listen_sock_qlen(lopt) < young)
break; break;
thresh--; thresh--;
young <<= 1; young <<= 1;
} }
} }
if (queue->rskq_defer_accept) if (queue->rskq_defer_accept)
max_retries = queue->rskq_defer_accept; max_retries = queue->rskq_defer_accept;
syn_ack_recalc(req, thresh, max_retries, queue->rskq_defer_accept,
&expire, &resend);
req->rsk_ops->syn_ack_timeout(sk_listener, req);
if (!expire &&
(!resend ||
!inet_rtx_syn_ack(sk_listener, req) ||
inet_rsk(req)->acked)) {
unsigned long timeo;
if (req->num_timeout++ == 0)
atomic_inc(&lopt->young_dec);
timeo = min(TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX);
mod_timer_pinned(&req->rsk_timer, jiffies + timeo);
return;
}
inet_csk_reqsk_queue_drop(sk_listener, req);
reqsk_put(req);
}
budget = 2 * (lopt->nr_table_entries / (timeout / interval)); void reqsk_queue_hash_req(struct request_sock_queue *queue,
i = lopt->clock_hand; u32 hash, struct request_sock *req,
unsigned long timeout)
do { {
reqp=&lopt->syn_table[i]; struct listen_sock *lopt = queue->listen_opt;
while ((req = *reqp) != NULL) {
if (time_after_eq(now, req->expires)) {
int expire = 0, resend = 0;
syn_ack_recalc(req, thresh, max_retries,
queue->rskq_defer_accept,
&expire, &resend);
req->rsk_ops->syn_ack_timeout(parent, req);
if (!expire &&
(!resend ||
!inet_rtx_syn_ack(parent, req) ||
inet_rsk(req)->acked)) {
unsigned long timeo;
if (req->num_timeout++ == 0)
lopt->qlen_young--;
timeo = min(timeout << req->num_timeout,
max_rto);
req->expires = now + timeo;
reqp = &req->dl_next;
continue;
}
/* Drop this request */
inet_csk_reqsk_queue_unlink(parent, req, reqp);
reqsk_queue_removed(queue, req);
reqsk_put(req);
continue;
}
reqp = &req->dl_next;
}
i = (i + 1) & (lopt->nr_table_entries - 1); req->num_retrans = 0;
req->num_timeout = 0;
req->sk = NULL;
} while (--budget > 0); /* before letting lookups find us, make sure all req fields
* are committed to memory and refcnt initialized.
*/
smp_wmb();
atomic_set(&req->rsk_refcnt, 2);
setup_timer(&req->rsk_timer, reqsk_timer_handler, (unsigned long)req);
req->rsk_hash = hash;
lopt->clock_hand = i; write_lock(&queue->syn_wait_lock);
req->dl_next = lopt->syn_table[hash];
lopt->syn_table[hash] = req;
write_unlock(&queue->syn_wait_lock);
if (lopt->qlen) mod_timer_pinned(&req->rsk_timer, jiffies + timeout);
inet_csk_reset_keepalive_timer(parent, interval);
} }
EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_prune); EXPORT_SYMBOL(reqsk_queue_hash_req);
/** /**
* inet_csk_clone_lock - clone an inet socket, and lock its clone * inet_csk_clone_lock - clone an inet socket, and lock its clone
...@@ -788,8 +789,6 @@ void inet_csk_listen_stop(struct sock *sk) ...@@ -788,8 +789,6 @@ void inet_csk_listen_stop(struct sock *sk)
struct request_sock *acc_req; struct request_sock *acc_req;
struct request_sock *req; struct request_sock *req;
inet_csk_delete_keepalive_timer(sk);
/* make all the listen_opt local to us */ /* make all the listen_opt local to us */
acc_req = reqsk_queue_yank_acceptq(queue); acc_req = reqsk_queue_yank_acceptq(queue);
......
...@@ -285,7 +285,7 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, ...@@ -285,7 +285,7 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) != BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) !=
offsetof(struct sock, sk_cookie)); offsetof(struct sock, sk_cookie));
tmo = inet_reqsk(sk)->expires - jiffies; tmo = inet_reqsk(sk)->rsk_timer.expires - jiffies;
r->idiag_expires = (tmo >= 0) ? jiffies_to_msecs(tmo) : 0; r->idiag_expires = (tmo >= 0) ? jiffies_to_msecs(tmo) : 0;
r->idiag_rqueue = 0; r->idiag_rqueue = 0;
r->idiag_wqueue = 0; r->idiag_wqueue = 0;
...@@ -719,7 +719,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, ...@@ -719,7 +719,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock); read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
lopt = icsk->icsk_accept_queue.listen_opt; lopt = icsk->icsk_accept_queue.listen_opt;
if (!lopt || !lopt->qlen) if (!lopt || !listen_sock_qlen(lopt))
goto out; goto out;
if (bc) { if (bc) {
......
...@@ -361,7 +361,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ...@@ -361,7 +361,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
goto out; goto out;
} }
req->expires = 0UL;
req->num_retrans = 0; req->num_retrans = 0;
/* /*
......
...@@ -240,7 +240,7 @@ static bool tcp_fastopen_queue_check(struct sock *sk) ...@@ -240,7 +240,7 @@ static bool tcp_fastopen_queue_check(struct sock *sk)
struct request_sock *req1; struct request_sock *req1;
spin_lock(&fastopenq->lock); spin_lock(&fastopenq->lock);
req1 = fastopenq->rskq_rst_head; req1 = fastopenq->rskq_rst_head;
if ((req1 == NULL) || time_after(req1->expires, jiffies)) { if (!req1 || time_after(req1->rsk_timer.expires, jiffies)) {
spin_unlock(&fastopenq->lock); spin_unlock(&fastopenq->lock);
NET_INC_STATS_BH(sock_net(sk), NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPFASTOPENLISTENOVERFLOW); LINUX_MIB_TCPFASTOPENLISTENOVERFLOW);
......
...@@ -5694,7 +5694,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, ...@@ -5694,7 +5694,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
sk->sk_state != TCP_FIN_WAIT1); sk->sk_state != TCP_FIN_WAIT1);
if (tcp_check_req(sk, skb, req, NULL, true) == NULL) if (tcp_check_req(sk, skb, req, true) == NULL)
goto discard; goto discard;
} }
......
...@@ -458,12 +458,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) ...@@ -458,12 +458,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
} }
switch (sk->sk_state) { switch (sk->sk_state) {
struct request_sock *req, **prev; struct request_sock *req;
case TCP_LISTEN: case TCP_LISTEN:
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
goto out; goto out;
req = inet_csk_search_req(sk, &prev, th->dest, req = inet_csk_search_req(sk, th->dest,
iph->daddr, iph->saddr); iph->daddr, iph->saddr);
if (!req) if (!req)
goto out; goto out;
...@@ -475,6 +475,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) ...@@ -475,6 +475,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
if (seq != tcp_rsk(req)->snt_isn) { if (seq != tcp_rsk(req)->snt_isn) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
reqsk_put(req);
goto out; goto out;
} }
...@@ -484,8 +485,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) ...@@ -484,8 +485,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
* created socket, and POSIX does not want network * created socket, and POSIX does not want network
* errors returned from accept(). * errors returned from accept().
*/ */
inet_csk_reqsk_queue_drop(sk, req, prev); inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
reqsk_put(req);
goto out; goto out;
case TCP_SYN_SENT: case TCP_SYN_SENT:
...@@ -1392,15 +1394,17 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock); ...@@ -1392,15 +1394,17 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{ {
struct tcphdr *th = tcp_hdr(skb); const struct tcphdr *th = tcp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
struct request_sock *req;
struct sock *nsk; struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */ req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
struct request_sock *req = inet_csk_search_req(sk, &prev, th->source, if (req) {
iph->saddr, iph->daddr); nsk = tcp_check_req(sk, skb, req, false);
if (req) reqsk_put(req);
return tcp_check_req(sk, skb, req, prev, false); return nsk;
}
nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr, nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr,
th->source, iph->daddr, th->dest, inet_iif(skb)); th->source, iph->daddr, th->dest, inet_iif(skb));
...@@ -2209,7 +2213,7 @@ static void get_openreq4(const struct request_sock *req, ...@@ -2209,7 +2213,7 @@ static void get_openreq4(const struct request_sock *req,
struct seq_file *f, int i, kuid_t uid) struct seq_file *f, int i, kuid_t uid)
{ {
const struct inet_request_sock *ireq = inet_rsk(req); const struct inet_request_sock *ireq = inet_rsk(req);
long delta = req->expires - jiffies; long delta = req->rsk_timer.expires - jiffies;
seq_printf(f, "%4d: %08X:%04X %08X:%04X" seq_printf(f, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK", " %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK",
......
...@@ -572,7 +572,6 @@ EXPORT_SYMBOL(tcp_create_openreq_child); ...@@ -572,7 +572,6 @@ EXPORT_SYMBOL(tcp_create_openreq_child);
struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock *req,
struct request_sock **prev,
bool fastopen) bool fastopen)
{ {
struct tcp_options_received tmp_opt; struct tcp_options_received tmp_opt;
...@@ -630,8 +629,9 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -630,8 +629,9 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
&tcp_rsk(req)->last_oow_ack_time) && &tcp_rsk(req)->last_oow_ack_time) &&
!inet_rtx_syn_ack(sk, req)) !inet_rtx_syn_ack(sk, req))
req->expires = min(TCP_TIMEOUT_INIT << req->num_timeout, mod_timer_pending(&req->rsk_timer, jiffies +
TCP_RTO_MAX) + jiffies; min(TCP_TIMEOUT_INIT << req->num_timeout,
TCP_RTO_MAX));
return NULL; return NULL;
} }
...@@ -766,7 +766,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -766,7 +766,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (child == NULL) if (child == NULL)
goto listen_overflow; goto listen_overflow;
inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req); inet_csk_reqsk_queue_removed(sk, req);
inet_csk_reqsk_queue_add(sk, req, child); inet_csk_reqsk_queue_add(sk, req, child);
...@@ -791,7 +791,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -791,7 +791,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
tcp_reset(sk); tcp_reset(sk);
} }
if (!fastopen) { if (!fastopen) {
inet_csk_reqsk_queue_drop(sk, req, prev); inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);
} }
return NULL; return NULL;
......
...@@ -539,16 +539,6 @@ static void tcp_write_timer(unsigned long data) ...@@ -539,16 +539,6 @@ static void tcp_write_timer(unsigned long data)
sock_put(sk); sock_put(sk);
} }
/*
* Timer for listening sockets
*/
static void tcp_synack_timer(struct sock *sk)
{
inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL,
TCP_TIMEOUT_INIT, TCP_RTO_MAX);
}
void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req) void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req)
{ {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEOUTS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEOUTS);
...@@ -583,7 +573,7 @@ static void tcp_keepalive_timer (unsigned long data) ...@@ -583,7 +573,7 @@ static void tcp_keepalive_timer (unsigned long data)
} }
if (sk->sk_state == TCP_LISTEN) { if (sk->sk_state == TCP_LISTEN) {
tcp_synack_timer(sk); pr_err("Hmm... keepalive on a LISTEN ???\n");
goto out; goto out;
} }
......
...@@ -112,22 +112,20 @@ static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport, ...@@ -112,22 +112,20 @@ static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport,
return c & (synq_hsize - 1); return c & (synq_hsize - 1);
} }
struct request_sock *inet6_csk_search_req(const struct sock *sk, struct request_sock *inet6_csk_search_req(struct sock *sk,
struct request_sock ***prevp,
const __be16 rport, const __be16 rport,
const struct in6_addr *raddr, const struct in6_addr *raddr,
const struct in6_addr *laddr, const struct in6_addr *laddr,
const int iif) const int iif)
{ {
const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
struct request_sock *req, **prev; struct request_sock *req;
u32 hash = inet6_synq_hash(raddr, rport, lopt->hash_rnd,
lopt->nr_table_entries);
for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport, write_lock(&icsk->icsk_accept_queue.syn_wait_lock);
lopt->hash_rnd, for (req = lopt->syn_table[hash]; req != NULL; req = req->dl_next) {
lopt->nr_table_entries)];
(req = *prev) != NULL;
prev = &req->dl_next) {
const struct inet_request_sock *ireq = inet_rsk(req); const struct inet_request_sock *ireq = inet_rsk(req);
if (ireq->ir_rmt_port == rport && if (ireq->ir_rmt_port == rport &&
...@@ -135,13 +133,14 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk, ...@@ -135,13 +133,14 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk,
ipv6_addr_equal(&ireq->ir_v6_rmt_addr, raddr) && ipv6_addr_equal(&ireq->ir_v6_rmt_addr, raddr) &&
ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) && ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) &&
(!ireq->ir_iif || ireq->ir_iif == iif)) { (!ireq->ir_iif || ireq->ir_iif == iif)) {
atomic_inc(&req->rsk_refcnt);
WARN_ON(req->sk != NULL); WARN_ON(req->sk != NULL);
*prevp = prev; break;
return req;
} }
} }
write_unlock(&icsk->icsk_accept_queue.syn_wait_lock);
return NULL; return req;
} }
EXPORT_SYMBOL_GPL(inet6_csk_search_req); EXPORT_SYMBOL_GPL(inet6_csk_search_req);
......
...@@ -222,7 +222,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ...@@ -222,7 +222,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
ireq->ir_mark = inet_request_mark(sk, skb); ireq->ir_mark = inet_request_mark(sk, skb);
req->expires = 0UL;
req->num_retrans = 0; req->num_retrans = 0;
ireq->snd_wscale = tcp_opt.snd_wscale; ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->sack_ok = tcp_opt.sack_ok; ireq->sack_ok = tcp_opt.sack_ok;
......
...@@ -403,13 +403,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -403,13 +403,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
/* Might be for an request_sock */ /* Might be for an request_sock */
switch (sk->sk_state) { switch (sk->sk_state) {
struct request_sock *req, **prev; struct request_sock *req;
case TCP_LISTEN: case TCP_LISTEN:
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
goto out; goto out;
/* Note : We use inet6_iif() here, not tcp_v6_iif() */ /* Note : We use inet6_iif() here, not tcp_v6_iif() */
req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr, req = inet6_csk_search_req(sk, th->dest, &hdr->daddr,
&hdr->saddr, inet6_iif(skb)); &hdr->saddr, inet6_iif(skb));
if (!req) if (!req)
goto out; goto out;
...@@ -421,11 +421,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -421,11 +421,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (seq != tcp_rsk(req)->snt_isn) { if (seq != tcp_rsk(req)->snt_isn) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
reqsk_put(req);
goto out; goto out;
} }
inet_csk_reqsk_queue_drop(sk, req, prev); inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
reqsk_put(req);
goto out; goto out;
case TCP_SYN_SENT: case TCP_SYN_SENT:
...@@ -980,17 +982,19 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, ...@@ -980,17 +982,19 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
{ {
struct request_sock *req, **prev;
const struct tcphdr *th = tcp_hdr(skb); const struct tcphdr *th = tcp_hdr(skb);
struct request_sock *req;
struct sock *nsk; struct sock *nsk;
/* Find possible connection requests. */ /* Find possible connection requests. */
req = inet6_csk_search_req(sk, &prev, th->source, req = inet6_csk_search_req(sk, th->source,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, tcp_v6_iif(skb)); &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
if (req) if (req) {
return tcp_check_req(sk, skb, req, prev, false); nsk = tcp_check_req(sk, skb, req, false);
reqsk_put(req);
return nsk;
}
nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
&ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->saddr, th->source,
&ipv6_hdr(skb)->daddr, ntohs(th->dest), &ipv6_hdr(skb)->daddr, ntohs(th->dest),
...@@ -1670,7 +1674,7 @@ static void tcp_v6_destroy_sock(struct sock *sk) ...@@ -1670,7 +1674,7 @@ static void tcp_v6_destroy_sock(struct sock *sk)
static void get_openreq6(struct seq_file *seq, static void get_openreq6(struct seq_file *seq,
struct request_sock *req, int i, kuid_t uid) struct request_sock *req, int i, kuid_t uid)
{ {
int ttd = req->expires - jiffies; long ttd = req->rsk_timer.expires - jiffies;
const struct in6_addr *src = &inet_rsk(req)->ir_v6_loc_addr; const struct in6_addr *src = &inet_rsk(req)->ir_v6_loc_addr;
const struct in6_addr *dest = &inet_rsk(req)->ir_v6_rmt_addr; const struct in6_addr *dest = &inet_rsk(req)->ir_v6_rmt_addr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment