net: tcp: Keep track of recv window size change since last ACK

Windows TCP stack has a peculiar behavior - when running iperf, it will
fill out the RX window almost entirely, but will not set PSH flag on
packets. In result, our stack would delay the ACK and thus window
update, affecting throughputs heavily.

In order to avoid that, keep track of the most recent window size
reported to the peer, and reduce it when receiving new data. In case the
RX window, as seen from the peer perspective, drops below certain
threshold, and the real RX window is currently empty, send an ACK
immediately when updating window, so that peer can continue
with sending data.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2024-07-29 12:01:50 +02:00 committed by Carles Cufí
parent e31588fcca
commit 349bf81e00
2 changed files with 24 additions and 1 deletions

View File

@ -1177,6 +1177,17 @@ static bool tcp_short_window(struct tcp *conn)
return true;
}
static bool tcp_need_window_update(struct tcp *conn)
{
int32_t threshold = MAX(conn_mss(conn), conn->recv_win_max / 2);
/* In case window is full again, and we didn't send a window update
* since the window size dropped below threshold, do it now.
*/
return (conn->recv_win == conn->recv_win_max &&
conn->recv_win_sent <= threshold);
}
/**
* @brief Update TCP receive window
*
@ -1205,7 +1216,8 @@ static int tcp_update_recv_wnd(struct tcp *conn, int32_t delta)
short_win_after = tcp_short_window(conn);
if (short_win_before && !short_win_after &&
if (((short_win_before && !short_win_after) ||
tcp_need_window_update(conn)) &&
conn->state == TCP_ESTABLISHED) {
k_work_cancel_delayable(&conn->ack_timer);
tcp_out(conn, ACK);
@ -1297,6 +1309,11 @@ static enum net_verdict tcp_data_get(struct tcp *conn, struct net_pkt *pkt, size
net_pkt_skip(pkt, net_pkt_get_len(pkt) - *len);
tcp_update_recv_wnd(conn, -*len);
if (*len > conn->recv_win_sent) {
conn->recv_win_sent = 0;
} else {
conn->recv_win_sent -= *len;
}
/* Do not pass data to application with TCP conn
* locked as there could be an issue when the app tries
@ -1583,6 +1600,10 @@ static int tcp_out_ext(struct tcp *conn, uint8_t flags, struct net_pkt *data,
sys_slist_append(&conn->send_queue, &pkt->next);
if (flags & ACK) {
conn->recv_win_sent = conn->recv_win;
}
if (is_destination_local(pkt)) {
/* If the destination is local, we have to let the current
* thread to finish with any state-machine changes before
@ -2112,6 +2133,7 @@ static struct tcp *tcp_conn_alloc(void)
conn->state = TCP_LISTEN;
conn->recv_win_max = tcp_rx_window;
conn->recv_win = conn->recv_win_max;
conn->recv_win_sent = conn->recv_win_max;
conn->send_win_max = MAX(tcp_tx_window, NET_IPV6_MTU);
conn->send_win = conn->send_win_max;
conn->tcp_nodelay = false;

View File

@ -314,6 +314,7 @@ struct tcp { /* TCP connection */
uint32_t keep_cnt;
uint32_t keep_cur;
#endif /* CONFIG_NET_TCP_KEEPALIVE */
uint16_t recv_win_sent;
uint16_t recv_win_max;
uint16_t recv_win;
uint16_t send_win_max;