162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* RTT/RTO calculation. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Adapted from TCP for AF_RXRPC by David Howells (dhowells@redhat.com) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * https://tools.ietf.org/html/rfc6298 762306a36Sopenharmony_ci * https://tools.ietf.org/html/rfc1122#section-4.2.3.1 862306a36Sopenharmony_ci * http://ccr.sigcomm.org/archive/1995/jan95/ccr-9501-partridge87.pdf 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/net.h> 1262306a36Sopenharmony_ci#include "ar-internal.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define RXRPC_RTO_MAX ((unsigned)(120 * HZ)) 1562306a36Sopenharmony_ci#define RXRPC_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC6298 2.1 initial RTO value */ 1662306a36Sopenharmony_ci#define rxrpc_jiffies32 ((u32)jiffies) /* As rxrpc_jiffies32 */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic u32 rxrpc_rto_min_us(struct rxrpc_peer *peer) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci return 200; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic u32 __rxrpc_set_rto(const struct rxrpc_peer *peer) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci return usecs_to_jiffies((peer->srtt_us >> 3) + peer->rttvar_us); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic u32 rxrpc_bound_rto(u32 rto) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci return min(rto, RXRPC_RTO_MAX); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * Called to compute a smoothed rtt estimate. The data fed to this 3562306a36Sopenharmony_ci * routine either comes from timestamps, or from segments that were 3662306a36Sopenharmony_ci * known _not_ to have been retransmitted [see Karn/Partridge 3762306a36Sopenharmony_ci * Proceedings SIGCOMM 87]. The algorithm is from the SIGCOMM 88 3862306a36Sopenharmony_ci * piece by Van Jacobson. 3962306a36Sopenharmony_ci * NOTE: the next three routines used to be one big routine. 4062306a36Sopenharmony_ci * To save cycles in the RFC 1323 implementation it was better to break 4162306a36Sopenharmony_ci * it up into three procedures. -- erics 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistatic void rxrpc_rtt_estimator(struct rxrpc_peer *peer, long sample_rtt_us) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci long m = sample_rtt_us; /* RTT */ 4662306a36Sopenharmony_ci u32 srtt = peer->srtt_us; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* The following amusing code comes from Jacobson's 4962306a36Sopenharmony_ci * article in SIGCOMM '88. Note that rtt and mdev 5062306a36Sopenharmony_ci * are scaled versions of rtt and mean deviation. 5162306a36Sopenharmony_ci * This is designed to be as fast as possible 5262306a36Sopenharmony_ci * m stands for "measurement". 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * On a 1990 paper the rto value is changed to: 5562306a36Sopenharmony_ci * RTO = rtt + 4 * mdev 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * Funny. This algorithm seems to be very broken. 5862306a36Sopenharmony_ci * These formulae increase RTO, when it should be decreased, increase 5962306a36Sopenharmony_ci * too slowly, when it should be increased quickly, decrease too quickly 6062306a36Sopenharmony_ci * etc. I guess in BSD RTO takes ONE value, so that it is absolutely 6162306a36Sopenharmony_ci * does not matter how to _calculate_ it. Seems, it was trap 6262306a36Sopenharmony_ci * that VJ failed to avoid. 8) 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (srtt != 0) { 6562306a36Sopenharmony_ci m -= (srtt >> 3); /* m is now error in rtt est */ 6662306a36Sopenharmony_ci srtt += m; /* rtt = 7/8 rtt + 1/8 new */ 6762306a36Sopenharmony_ci if (m < 0) { 6862306a36Sopenharmony_ci m = -m; /* m is now abs(error) */ 6962306a36Sopenharmony_ci m -= (peer->mdev_us >> 2); /* similar update on mdev */ 7062306a36Sopenharmony_ci /* This is similar to one of Eifel findings. 7162306a36Sopenharmony_ci * Eifel blocks mdev updates when rtt decreases. 7262306a36Sopenharmony_ci * This solution is a bit different: we use finer gain 7362306a36Sopenharmony_ci * for mdev in this case (alpha*beta). 7462306a36Sopenharmony_ci * Like Eifel it also prevents growth of rto, 7562306a36Sopenharmony_ci * but also it limits too fast rto decreases, 7662306a36Sopenharmony_ci * happening in pure Eifel. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci if (m > 0) 7962306a36Sopenharmony_ci m >>= 3; 8062306a36Sopenharmony_ci } else { 8162306a36Sopenharmony_ci m -= (peer->mdev_us >> 2); /* similar update on mdev */ 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci peer->mdev_us += m; /* mdev = 3/4 mdev + 1/4 new */ 8562306a36Sopenharmony_ci if (peer->mdev_us > peer->mdev_max_us) { 8662306a36Sopenharmony_ci peer->mdev_max_us = peer->mdev_us; 8762306a36Sopenharmony_ci if (peer->mdev_max_us > peer->rttvar_us) 8862306a36Sopenharmony_ci peer->rttvar_us = peer->mdev_max_us; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci } else { 9162306a36Sopenharmony_ci /* no previous measure. */ 9262306a36Sopenharmony_ci srtt = m << 3; /* take the measured time to be rtt */ 9362306a36Sopenharmony_ci peer->mdev_us = m << 1; /* make sure rto = 3*rtt */ 9462306a36Sopenharmony_ci peer->rttvar_us = max(peer->mdev_us, rxrpc_rto_min_us(peer)); 9562306a36Sopenharmony_ci peer->mdev_max_us = peer->rttvar_us; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci peer->srtt_us = max(1U, srtt); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * Calculate rto without backoff. This is the second half of Van Jacobson's 10362306a36Sopenharmony_ci * routine referred to above. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic void rxrpc_set_rto(struct rxrpc_peer *peer) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci u32 rto; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* 1. If rtt variance happened to be less 50msec, it is hallucination. 11062306a36Sopenharmony_ci * It cannot be less due to utterly erratic ACK generation made 11162306a36Sopenharmony_ci * at least by solaris and freebsd. "Erratic ACKs" has _nothing_ 11262306a36Sopenharmony_ci * to do with delayed acks, because at cwnd>2 true delack timeout 11362306a36Sopenharmony_ci * is invisible. Actually, Linux-2.4 also generates erratic 11462306a36Sopenharmony_ci * ACKs in some circumstances. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci rto = __rxrpc_set_rto(peer); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 2. Fixups made earlier cannot be right. 11962306a36Sopenharmony_ci * If we do not estimate RTO correctly without them, 12062306a36Sopenharmony_ci * all the algo is pure shit and should be replaced 12162306a36Sopenharmony_ci * with correct one. It is exactly, which we pretend to do. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* NOTE: clamping at RXRPC_RTO_MIN is not required, current algo 12562306a36Sopenharmony_ci * guarantees that rto is higher. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci peer->rto_j = rxrpc_bound_rto(rto); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void rxrpc_ack_update_rtt(struct rxrpc_peer *peer, long rtt_us) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci if (rtt_us < 0) 13362306a36Sopenharmony_ci return; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci //rxrpc_update_rtt_min(peer, rtt_us); 13662306a36Sopenharmony_ci rxrpc_rtt_estimator(peer, rtt_us); 13762306a36Sopenharmony_ci rxrpc_set_rto(peer); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* RFC6298: only reset backoff on valid RTT measurement. */ 14062306a36Sopenharmony_ci peer->backoff = 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Add RTT information to cache. This is called in softirq mode and has 14562306a36Sopenharmony_ci * exclusive access to the peer RTT data. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_civoid rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why, 14862306a36Sopenharmony_ci int rtt_slot, 14962306a36Sopenharmony_ci rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial, 15062306a36Sopenharmony_ci ktime_t send_time, ktime_t resp_time) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct rxrpc_peer *peer = call->peer; 15362306a36Sopenharmony_ci s64 rtt_us; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci rtt_us = ktime_to_us(ktime_sub(resp_time, send_time)); 15662306a36Sopenharmony_ci if (rtt_us < 0) 15762306a36Sopenharmony_ci return; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci spin_lock(&peer->rtt_input_lock); 16062306a36Sopenharmony_ci rxrpc_ack_update_rtt(peer, rtt_us); 16162306a36Sopenharmony_ci if (peer->rtt_count < 3) 16262306a36Sopenharmony_ci peer->rtt_count++; 16362306a36Sopenharmony_ci spin_unlock(&peer->rtt_input_lock); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci trace_rxrpc_rtt_rx(call, why, rtt_slot, send_serial, resp_serial, 16662306a36Sopenharmony_ci peer->srtt_us >> 3, peer->rto_j); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* 17062306a36Sopenharmony_ci * Get the retransmission timeout to set in jiffies, backing it off each time 17162306a36Sopenharmony_ci * we retransmit. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ciunsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *peer, bool retrans) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci u64 timo_j; 17662306a36Sopenharmony_ci u8 backoff = READ_ONCE(peer->backoff); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci timo_j = peer->rto_j; 17962306a36Sopenharmony_ci timo_j <<= backoff; 18062306a36Sopenharmony_ci if (retrans && timo_j * 2 <= RXRPC_RTO_MAX) 18162306a36Sopenharmony_ci WRITE_ONCE(peer->backoff, backoff + 1); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (timo_j < 1) 18462306a36Sopenharmony_ci timo_j = 1; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return timo_j; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_civoid rxrpc_peer_init_rtt(struct rxrpc_peer *peer) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci peer->rto_j = RXRPC_TIMEOUT_INIT; 19262306a36Sopenharmony_ci peer->mdev_us = jiffies_to_usecs(RXRPC_TIMEOUT_INIT); 19362306a36Sopenharmony_ci peer->backoff = 0; 19462306a36Sopenharmony_ci //minmax_reset(&peer->rtt_min, rxrpc_jiffies32, ~0U); 19562306a36Sopenharmony_ci} 196