Skip to content

Commit e214282

Browse files
menglongdongdavem330
authored andcommitted
net: tcp: send zero-window ACK when no memory
For now, skb will be dropped when no memory, which makes client keep retrans util timeout and it's not friendly to the users. In this patch, we reply an ACK with zero-window in this case to update the snd_wnd of the sender to 0. Therefore, the sender won't timeout the connection and will probe the zero-window with the retransmits. Signed-off-by: Menglong Dong <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3e6860e commit e214282

File tree

3 files changed

+25
-10
lines changed

3 files changed

+25
-10
lines changed

include/net/inet_connection_sock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ enum inet_csk_ack_state_t {
164164
ICSK_ACK_TIMER = 2,
165165
ICSK_ACK_PUSHED = 4,
166166
ICSK_ACK_PUSHED2 = 8,
167-
ICSK_ACK_NOW = 16 /* Send the next ACK immediately (once) */
167+
ICSK_ACK_NOW = 16, /* Send the next ACK immediately (once) */
168+
ICSK_ACK_NOMEM = 32,
168169
};
169170

170171
void inet_csk_init_xmit_timers(struct sock *sk,

net/ipv4/tcp_input.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5059,13 +5059,19 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
50595059

50605060
/* Ok. In sequence. In window. */
50615061
queue_and_out:
5062-
if (skb_queue_len(&sk->sk_receive_queue) == 0)
5063-
sk_forced_mem_schedule(sk, skb->truesize);
5064-
else if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) {
5065-
reason = SKB_DROP_REASON_PROTO_MEM;
5066-
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP);
5062+
if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) {
5063+
/* TODO: maybe ratelimit these WIN 0 ACK ? */
5064+
inet_csk(sk)->icsk_ack.pending |=
5065+
(ICSK_ACK_NOMEM | ICSK_ACK_NOW);
5066+
inet_csk_schedule_ack(sk);
50675067
sk->sk_data_ready(sk);
5068-
goto drop;
5068+
5069+
if (skb_queue_len(&sk->sk_receive_queue)) {
5070+
reason = SKB_DROP_REASON_PROTO_MEM;
5071+
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP);
5072+
goto drop;
5073+
}
5074+
sk_forced_mem_schedule(sk, skb->truesize);
50695075
}
50705076

50715077
eaten = tcp_queue_rcv(sk, skb, &fragstolen);

net/ipv4/tcp_output.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,19 @@ EXPORT_SYMBOL(tcp_select_initial_window);
257257
static u16 tcp_select_window(struct sock *sk)
258258
{
259259
struct tcp_sock *tp = tcp_sk(sk);
260-
u32 old_win = tp->rcv_wnd;
261-
u32 cur_win = tcp_receive_window(tp);
262-
u32 new_win = __tcp_select_window(sk);
263260
struct net *net = sock_net(sk);
261+
u32 old_win = tp->rcv_wnd;
262+
u32 cur_win, new_win;
263+
264+
/* Make the window 0 if we failed to queue the data because we
265+
* are out of memory. The window is temporary, so we don't store
266+
* it on the socket.
267+
*/
268+
if (unlikely(inet_csk(sk)->icsk_ack.pending & ICSK_ACK_NOMEM))
269+
return 0;
264270

271+
cur_win = tcp_receive_window(tp);
272+
new_win = __tcp_select_window(sk);
265273
if (new_win < cur_win) {
266274
/* Danger Will Robinson!
267275
* Don't update rcv_wup/rcv_wnd here or else

0 commit comments

Comments
 (0)