Skip to content

Commit

Permalink
net: tcp: Add exponential backoff for ZWP probing
Browse files Browse the repository at this point in the history
Persist timer should implement exponential backoff, as per RFC 1122:

    The transmitting host SHOULD send the first zero-window
    probe when a zero window has existed for the retransmission
    timeout period (see Section 4.2.2.15), and SHOULD increase
    exponentially the interval between successive probes.

Implement this, by following Linux behaviour, and simply double the
timeout or each probe transmission.

Additionally, prevent reseting the persist timer in case an
acknowledgment is received with zero window size, and the timer is
already running.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
  • Loading branch information
rlubos authored and fabiobaltieri committed Aug 15, 2022
1 parent 72dab5b commit 405e3d7
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
23 changes: 20 additions & 3 deletions subsys/net/ip/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ LOG_MODULE_REGISTER(net_tcp, CONFIG_NET_TCP_LOG_LEVEL);
#define ACK_TIMEOUT K_MSEC(ACK_TIMEOUT_MS)
#define FIN_TIMEOUT K_MSEC(tcp_fin_timeout_ms)
#define ACK_DELAY K_MSEC(100)
#define ZWP_MAX_DELAY_MS 120000

static int tcp_rto = CONFIG_NET_TCP_INIT_RETRANSMISSION_TIMEOUT;
static int tcp_retries = CONFIG_NET_TCP_RETRY_COUNT;
Expand Down Expand Up @@ -1346,8 +1347,20 @@ static void tcp_send_zwp(struct k_work *work)
tcp_derive_rto(conn);

if (conn->send_win == 0) {
uint64_t timeout;

/* Make sure the retry counter does not overflow. */
if (conn->zwp_retries < UINT8_MAX) {
conn->zwp_retries++;
}

timeout = TCP_RTO_MS << conn->zwp_retries;
if (timeout == 0 || timeout > ZWP_MAX_DELAY_MS) {
timeout = ZWP_MAX_DELAY_MS;
}

(void)k_work_reschedule_for_queue(
&tcp_work_q, &conn->persist_timer, K_MSEC(TCP_RTO_MS));
&tcp_work_q, &conn->persist_timer, K_MSEC(timeout));
}

k_mutex_unlock(&conn->lock);
Expand Down Expand Up @@ -2008,8 +2021,12 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
}

if (conn->send_win == 0) {
(void)k_work_reschedule_for_queue(
&tcp_work_q, &conn->persist_timer, K_MSEC(TCP_RTO_MS));
if (!k_work_delayable_is_pending(&conn->persist_timer)) {
conn->zwp_retries = 0;
(void)k_work_reschedule_for_queue(
&tcp_work_q, &conn->persist_timer,
K_MSEC(TCP_RTO_MS));
}
} else {
(void)k_work_cancel_delayable(&conn->persist_timer);
}
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 @@ -273,6 +273,7 @@ struct tcp { /* TCP connection */
uint16_t rto;
#endif
uint8_t send_data_retries;
uint8_t zwp_retries;
bool in_retransmission : 1;
bool in_connect : 1;
bool in_close : 1;
Expand Down

0 comments on commit 405e3d7

Please sign in to comment.