net: tcp: send zero-window 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.

Therefore, now we force to receive one packet on current socket when
the protocol memory is out of the limitation. Then, this socket will
stay in 'no mem' status, util protocol memory is available.

When a socket is in 'no mem' status, it's receive window will become
0, which means window shrink happens. And the sender need to handle
such window shrink properly, which is done in the next commit.

Signed-off-by: Menglong Dong <imagedong@tencent.com>
This commit is contained in:
Menglong Dong 2023-03-08 17:42:16 +08:00 committed by Jianping Liu
parent 1ea94d5505
commit bb00f4ca4c
4 changed files with 34 additions and 0 deletions

View File

@ -868,6 +868,7 @@ enum sock_flags {
SOCK_TXTIME,
SOCK_XDP, /* XDP is attached */
SOCK_TSTAMP_NEW, /* Indicates 64 bit timestamps always */
SOCK_NO_MEM,
};
#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))

View File

@ -728,3 +728,14 @@ config TCP_MD5SIG
on the Internet.
If unsure, say N.
config TCP_WND_SHRINK
bool "TCP: Support window shrink when no memory"
default y
help
Skb will be dropped when no memory, which makes client keep
retrans util timeout and it's not friendly to the users. Enable
this configuration will make the connection keep in zero-window
probe state and avoid connection break.
If unsure, say N

View File

@ -4824,9 +4824,20 @@ queue_and_out:
if (skb_queue_len(&sk->sk_receive_queue) == 0)
sk_forced_mem_schedule(sk, skb->truesize);
else if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) {
#ifdef CONFIG_TCP_WND_SHRINK
if (sock_flag(sk, SOCK_NO_MEM)) {
NET_INC_STATS(sock_net(sk),
LINUX_MIB_TCPRCVQDROP);
sk->sk_data_ready(sk);
goto out_of_window;
}
sk_forced_mem_schedule(sk, skb->truesize);
sock_set_flag(sk, SOCK_NO_MEM);
#else
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP);
sk->sk_data_ready(sk);
goto drop;
#endif
}
eaten = tcp_queue_rcv(sk, skb, &fragstolen);
@ -4867,7 +4878,9 @@ out_of_window:
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPOOWDROP);
tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS);
inet_csk_schedule_ack(sk);
#ifndef CONFIG_TCP_WND_SHRINK
drop:
#endif
tcp_drop(sk, skb);
return;
}

View File

@ -301,6 +301,15 @@ static u16 tcp_select_window(struct sock *sk)
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFROMZEROWINDOWADV);
}
#ifdef CONFIG_TCP_WND_SHRINK
if (sock_flag(sk, SOCK_NO_MEM)) {
if (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 2))
sock_reset_flag(sk, SOCK_NO_MEM);
else
new_win = 0;
}
#endif
return new_win;
}