Skip to content

Commit

Permalink
tcp: Export TCP Delayed ACK parameters to user
Browse files Browse the repository at this point in the history
RFC2581 ($4.2) specifies when an ACK should be generated as follows:

" .. an ACK SHOULD be generated for at least every second
  full-sized segment, and MUST be generated within 500 ms
  of the arrival of the first unacknowledged packet.
"

We export the number of segments and the timeout limits
specified above, so that a user can tune them according
to its needs.

Specifically:
	* /proc/sys/net/ipv4/tcp_delack_segs, represents
	the threshold for the number of segments.
	* /proc/sys/net/ipv4/tcp_delack_min, specifies
	the minimum timeout value
	* /proc/sys/net/ipv4/tcp_delack_max, specifies
	the maximum timeout value.

Signed-off-by: Daniel Baluta <dbaluta@ixiacom.com>
  • Loading branch information
Daniel Baluta authored and ariknem committed Feb 18, 2013
1 parent dff6e2b commit ccb9d23
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 15 deletions.
13 changes: 13 additions & 0 deletions Documentation/networking/ip-sysctl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,19 @@ tcp_thin_dupack - BOOLEAN
Documentation/networking/tcp-thin.txt
Default: 0

tcp_delack_segs: - INTEGER
Sets the strict minimal number of full-sized TCP segments
received after which an ACK should be sent.
Default: 1 (as specified in RFC2582, S4.2)

tcp_delack_min: - INTEGER
Sets the minimum time (in miliseconds) to delay before sending an ACK.
Default: 40ms

tcp_delack_max: - INTEGER
Sets the maximum time (in miliseconds) to delay before sending an ACK.
Default: 200ms

UDP variables:

udp_mem - vector of 3 INTEGERs: min, pressure, max
Expand Down
18 changes: 15 additions & 3 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,18 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
* TIME-WAIT timer.
*/

#define TCP_DELACK_MAX ((unsigned)(HZ/5)) /* maximal time to delay before sending an ACK */
/* default maximum time to delay before sending an ACK */
#define TCP_DELACK_MAX_DEFAULT ((unsigned)(HZ/5))

#if HZ >= 100
#define TCP_DELACK_MIN ((unsigned)(HZ/25)) /* minimal time to delay before sending an ACK */
/* default minimum time to delay before sending an ACK */
#define TCP_DELACK_MIN_DEFAULT ((unsigned)(HZ/25))
#define TCP_ATO_MIN ((unsigned)(HZ/25))
#else
#define TCP_DELACK_MIN 4U
#define TCP_DELACK_MIN_DEFAULT 4U
#define TCP_ATO_MIN 4U
#endif

#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC6298 2.1 initial RTO value */
Expand Down Expand Up @@ -253,6 +257,9 @@ extern int sysctl_tcp_cookie_size;
extern int sysctl_tcp_thin_linear_timeouts;
extern int sysctl_tcp_thin_dupack;
extern int sysctl_tcp_early_retrans;
extern int sysctl_tcp_delack_segs;
extern int sysctl_tcp_delack_min;
extern int sysctl_tcp_delack_max;

extern atomic_long_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;
Expand Down Expand Up @@ -1607,6 +1614,11 @@ static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp)
return (struct tcp_extend_values *)rvp;
}

static inline int tcp_delack_thresh(const struct sock *sk)
{
return inet_csk(sk)->icsk_ack.rcv_mss * sysctl_tcp_delack_segs;
}

extern void tcp_v4_init(void);
extern void tcp_init(void);

Expand Down
2 changes: 1 addition & 1 deletion net/dccp/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ void dccp_send_ack(struct sock *sk)
inet_csk_schedule_ack(sk);
inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
TCP_DELACK_MAX,
sysctl_tcp_delack_max,
DCCP_RTO_MAX);
return;
}
Expand Down
2 changes: 1 addition & 1 deletion net/dccp/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static void dccp_delack_timer(unsigned long data)
icsk->icsk_ack.blocked = 1;
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
sk_reset_timer(sk, &icsk->icsk_delack_timer,
jiffies + TCP_DELACK_MIN);
jiffies + sysctl_tcp_delack_min);
goto out;
}

Expand Down
21 changes: 21 additions & 0 deletions net/ipv4/sysctl_net_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,27 @@ static struct ctl_table ipv4_table[] = {
.extra1 = &zero,
.extra2 = &two,
},
{
.procname = "tcp_delack_segs",
.data = &sysctl_tcp_delack_segs,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec
},
{
.procname = "tcp_delack_min",
.data = &sysctl_tcp_delack_min,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_ms_jiffies
},
{
.procname = "tcp_delack_max",
.data = &sysctl_tcp_delack_max,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_ms_jiffies
},
{
.procname = "udp_mem",
.data = &sysctl_udp_mem,
Expand Down
5 changes: 3 additions & 2 deletions net/ipv4/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1305,8 +1305,9 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied)
/* Delayed ACKs frequently hit locked sockets during bulk
* receive. */
if (icsk->icsk_ack.blocked ||
/* Once-per-two-segments ACK was not sent by tcp_input.c */
tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
/* More than once-per-tcp_delack_segs-segments ACK
* was not sent by tcp_input.c */
tp->rcv_nxt - tp->rcv_wup > tcp_delack_thresh(sk) ||
/*
* If this read emptied read buffer, we send ACK, if
* connection is not bidirectional, user drained
Expand Down
8 changes: 5 additions & 3 deletions net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
int sysctl_tcp_abc __read_mostly;
int sysctl_tcp_early_retrans __read_mostly = 2;

int sysctl_tcp_delack_segs __read_mostly = 1;

#define FLAG_DATA 0x01 /* Incoming frame contained data. */
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */
Expand Down Expand Up @@ -5206,8 +5208,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
{
struct tcp_sock *tp = tcp_sk(sk);

/* More than one full frame received... */
if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&
/* More than tcp_delack_segs full frame(s) received... */
if (((tp->rcv_nxt - tp->rcv_wup) > tcp_delack_thresh(sk) &&
/* ... and right edge of window advances far enough.
* (tcp_recvmsg() will send ACK otherwise). Or...
*/
Expand Down Expand Up @@ -5909,7 +5911,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
icsk->icsk_ack.lrcvtime = tcp_time_stamp;
tcp_enter_quickack_mode(sk);
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
TCP_DELACK_MAX, TCP_RTO_MAX);
sysctl_tcp_delack_max, TCP_RTO_MAX);

discard:
__kfree_skb(skb);
Expand Down
13 changes: 9 additions & 4 deletions net/ipv4/tcp_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */
EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size);

int sysctl_tcp_delack_min __read_mostly = TCP_DELACK_MIN_DEFAULT;
EXPORT_SYMBOL(sysctl_tcp_delack_min);

int sysctl_tcp_delack_max __read_mostly = TCP_DELACK_MAX_DEFAULT;
EXPORT_SYMBOL(sysctl_tcp_delack_max);

/* Account for new data that has been sent to the network. */
static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
Expand Down Expand Up @@ -2700,13 +2705,13 @@ void tcp_send_delayed_ack(struct sock *sk)
int ato = icsk->icsk_ack.ato;
unsigned long timeout;

if (ato > TCP_DELACK_MIN) {
if (ato > sysctl_tcp_delack_min) {
const struct tcp_sock *tp = tcp_sk(sk);
int max_ato = HZ / 2;

if (icsk->icsk_ack.pingpong ||
(icsk->icsk_ack.pending & ICSK_ACK_PUSHED))
max_ato = TCP_DELACK_MAX;
max_ato = sysctl_tcp_delack_max;

/* Slow path, intersegment interval is "high". */

Expand All @@ -2715,7 +2720,7 @@ void tcp_send_delayed_ack(struct sock *sk)
* directly.
*/
if (tp->srtt) {
int rtt = max(tp->srtt >> 3, TCP_DELACK_MIN);
int rtt = max_t(unsigned, tp->srtt >> 3, sysctl_tcp_delack_min);

if (rtt < max_ato)
max_ato = rtt;
Expand Down Expand Up @@ -2764,7 +2769,7 @@ void tcp_send_ack(struct sock *sk)
inet_csk_schedule_ack(sk);
inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
TCP_DELACK_MAX, TCP_RTO_MAX);
sysctl_tcp_delack_max, TCP_RTO_MAX);
return;
}

Expand Down
3 changes: 2 additions & 1 deletion net/ipv4/tcp_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ static void tcp_delack_timer(unsigned long data)
/* Try again later. */
icsk->icsk_ack.blocked = 1;
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
sk_reset_timer(sk, &icsk->icsk_delack_timer, jiffies + TCP_DELACK_MIN);
sk_reset_timer(sk, &icsk->icsk_delack_timer,
jiffies + sysctl_tcp_delack_min);
goto out_unlock;
}

Expand Down

0 comments on commit ccb9d23

Please sign in to comment.