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:
parent
e31588fcca
commit
349bf81e00
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user