Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec3c0982 authored by Patrick McManus's avatar Patrick McManus Committed by David S. Miller
Browse files

[TCP]: TCP_DEFER_ACCEPT updates - process as established



Change TCP_DEFER_ACCEPT implementation so that it transitions a
connection to ESTABLISHED after handshake is complete instead of
leaving it in SYN-RECV until some data arrvies. Place connection in
accept queue when first data packet arrives from slow path.

Benefits:
  - established connection is now reset if it never makes it
   to the accept queue

 - diagnostic state of established matches with the packet traces
   showing completed handshake

 - TCP_DEFER_ACCEPT timeouts are expressed in seconds and can now be
   enforced with reasonable accuracy instead of rounding up to next
   exponential back-off of syn-ack retry.

Signed-off-by: default avatarPatrick McManus <mcmanus@ducksong.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e4c78840
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -239,6 +239,11 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
	return (struct tcp_request_sock *)req;
}

struct tcp_deferred_accept_info {
	struct sock *listen_sk;
	struct request_sock *request;
};

struct tcp_sock {
	/* inet_connection_sock has to be the first member of tcp_sock */
	struct inet_connection_sock	inet_conn;
@@ -374,6 +379,8 @@ struct tcp_sock {
	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
	int			linger2;

	struct tcp_deferred_accept_info defer_tcp_accept;

	unsigned long last_synq_overflow; 

	u32	tso_deferred;
+2 −2
Original line number Diff line number Diff line
@@ -115,8 +115,8 @@ struct request_sock_queue {
	struct request_sock	*rskq_accept_head;
	struct request_sock	*rskq_accept_tail;
	rwlock_t		syn_wait_lock;
	u8			rskq_defer_accept;
	/* 3 bytes hole, try to pack */
	u16			rskq_defer_accept;
	/* 2 bytes hole, try to pack */
	struct listen_sock	*listen_opt;
};

+1 −0
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define MAX_TCP_KEEPINTVL	32767
#define MAX_TCP_KEEPCNT		127
#define MAX_TCP_SYNCNT		127
#define MAX_TCP_ACCEPT_DEFERRED 65535

#define TCP_SYNQ_INTERVAL	(HZ/5)	/* Period of SYNACK timer */

+3 −8
Original line number Diff line number Diff line
@@ -414,8 +414,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
	struct inet_connection_sock *icsk = inet_csk(parent);
	struct request_sock_queue *queue = &icsk->icsk_accept_queue;
	struct listen_sock *lopt = queue->listen_opt;
	int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
	int thresh = max_retries;
	int thresh = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
	unsigned long now = jiffies;
	struct request_sock **reqp, *req;
	int i, budget;
@@ -451,9 +450,6 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
		}
	}

	if (queue->rskq_defer_accept)
		max_retries = queue->rskq_defer_accept;

	budget = 2 * (lopt->nr_table_entries / (timeout / interval));
	i = lopt->clock_hand;

@@ -461,9 +457,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
		reqp=&lopt->syn_table[i];
		while ((req = *reqp) != NULL) {
			if (time_after_eq(now, req->expires)) {
				if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) &&
				    (inet_rsk(req)->acked ||
				     !req->rsk_ops->rtx_syn_ack(parent, req))) {
				if (req->retrans < thresh &&
				    !req->rsk_ops->rtx_syn_ack(parent, req)) {
					unsigned long timeo;

					if (req->retrans++ == 0)
+7 −11
Original line number Diff line number Diff line
@@ -2105,15 +2105,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
		break;

	case TCP_DEFER_ACCEPT:
		icsk->icsk_accept_queue.rskq_defer_accept = 0;
		if (val > 0) {
			/* Translate value in seconds to number of
			 * retransmits */
			while (icsk->icsk_accept_queue.rskq_defer_accept < 32 &&
			       val > ((TCP_TIMEOUT_INIT / HZ) <<
				       icsk->icsk_accept_queue.rskq_defer_accept))
				icsk->icsk_accept_queue.rskq_defer_accept++;
			icsk->icsk_accept_queue.rskq_defer_accept++;
		if (val < 0) {
			err = -EINVAL;
		} else {
			if (val > MAX_TCP_ACCEPT_DEFERRED)
				val = MAX_TCP_ACCEPT_DEFERRED;
			icsk->icsk_accept_queue.rskq_defer_accept = val;
		}
		break;

@@ -2295,8 +2292,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
			val = (val ? : sysctl_tcp_fin_timeout) / HZ;
		break;
	case TCP_DEFER_ACCEPT:
		val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 :
			((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1));
		val = icsk->icsk_accept_queue.rskq_defer_accept;
		break;
	case TCP_WINDOW_CLAMP:
		val = tp->window_clamp;
Loading