Skip to content

Commit

Permalink
net: tcp: Keep track of recv window size change since last ACK
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
rlubos authored and carlescufi committed Jul 31, 2024
1 parent e31588f commit 349bf81
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
24 changes: 23 additions & 1 deletion subsys/net/ip/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions subsys/net/ip/tcp_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 349bf81

Please sign in to comment.