18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* RTT/RTO calculation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Adapted from TCP for AF_RXRPC by David Howells (dhowells@redhat.com) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * https://tools.ietf.org/html/rfc6298 78c2ecf20Sopenharmony_ci * https://tools.ietf.org/html/rfc1122#section-4.2.3.1 88c2ecf20Sopenharmony_ci * http://ccr.sigcomm.org/archive/1995/jan95/ccr-9501-partridge87.pdf 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/net.h> 128c2ecf20Sopenharmony_ci#include "ar-internal.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define RXRPC_RTO_MAX ((unsigned)(120 * HZ)) 158c2ecf20Sopenharmony_ci#define RXRPC_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC6298 2.1 initial RTO value */ 168c2ecf20Sopenharmony_ci#define rxrpc_jiffies32 ((u32)jiffies) /* As rxrpc_jiffies32 */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic u32 rxrpc_rto_min_us(struct rxrpc_peer *peer) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci return 200; 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic u32 __rxrpc_set_rto(const struct rxrpc_peer *peer) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci return usecs_to_jiffies((peer->srtt_us >> 3) + peer->rttvar_us); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u32 rxrpc_bound_rto(u32 rto) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci return min(rto, RXRPC_RTO_MAX); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Called to compute a smoothed rtt estimate. The data fed to this 358c2ecf20Sopenharmony_ci * routine either comes from timestamps, or from segments that were 368c2ecf20Sopenharmony_ci * known _not_ to have been retransmitted [see Karn/Partridge 378c2ecf20Sopenharmony_ci * Proceedings SIGCOMM 87]. The algorithm is from the SIGCOMM 88 388c2ecf20Sopenharmony_ci * piece by Van Jacobson. 398c2ecf20Sopenharmony_ci * NOTE: the next three routines used to be one big routine. 408c2ecf20Sopenharmony_ci * To save cycles in the RFC 1323 implementation it was better to break 418c2ecf20Sopenharmony_ci * it up into three procedures. -- erics 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_cistatic void rxrpc_rtt_estimator(struct rxrpc_peer *peer, long sample_rtt_us) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci long m = sample_rtt_us; /* RTT */ 468c2ecf20Sopenharmony_ci u32 srtt = peer->srtt_us; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* The following amusing code comes from Jacobson's 498c2ecf20Sopenharmony_ci * article in SIGCOMM '88. Note that rtt and mdev 508c2ecf20Sopenharmony_ci * are scaled versions of rtt and mean deviation. 518c2ecf20Sopenharmony_ci * This is designed to be as fast as possible 528c2ecf20Sopenharmony_ci * m stands for "measurement". 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * On a 1990 paper the rto value is changed to: 558c2ecf20Sopenharmony_ci * RTO = rtt + 4 * mdev 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Funny. This algorithm seems to be very broken. 588c2ecf20Sopenharmony_ci * These formulae increase RTO, when it should be decreased, increase 598c2ecf20Sopenharmony_ci * too slowly, when it should be increased quickly, decrease too quickly 608c2ecf20Sopenharmony_ci * etc. I guess in BSD RTO takes ONE value, so that it is absolutely 618c2ecf20Sopenharmony_ci * does not matter how to _calculate_ it. Seems, it was trap 628c2ecf20Sopenharmony_ci * that VJ failed to avoid. 8) 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci if (srtt != 0) { 658c2ecf20Sopenharmony_ci m -= (srtt >> 3); /* m is now error in rtt est */ 668c2ecf20Sopenharmony_ci srtt += m; /* rtt = 7/8 rtt + 1/8 new */ 678c2ecf20Sopenharmony_ci if (m < 0) { 688c2ecf20Sopenharmony_ci m = -m; /* m is now abs(error) */ 698c2ecf20Sopenharmony_ci m -= (peer->mdev_us >> 2); /* similar update on mdev */ 708c2ecf20Sopenharmony_ci /* This is similar to one of Eifel findings. 718c2ecf20Sopenharmony_ci * Eifel blocks mdev updates when rtt decreases. 728c2ecf20Sopenharmony_ci * This solution is a bit different: we use finer gain 738c2ecf20Sopenharmony_ci * for mdev in this case (alpha*beta). 748c2ecf20Sopenharmony_ci * Like Eifel it also prevents growth of rto, 758c2ecf20Sopenharmony_ci * but also it limits too fast rto decreases, 768c2ecf20Sopenharmony_ci * happening in pure Eifel. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci if (m > 0) 798c2ecf20Sopenharmony_ci m >>= 3; 808c2ecf20Sopenharmony_ci } else { 818c2ecf20Sopenharmony_ci m -= (peer->mdev_us >> 2); /* similar update on mdev */ 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci peer->mdev_us += m; /* mdev = 3/4 mdev + 1/4 new */ 858c2ecf20Sopenharmony_ci if (peer->mdev_us > peer->mdev_max_us) { 868c2ecf20Sopenharmony_ci peer->mdev_max_us = peer->mdev_us; 878c2ecf20Sopenharmony_ci if (peer->mdev_max_us > peer->rttvar_us) 888c2ecf20Sopenharmony_ci peer->rttvar_us = peer->mdev_max_us; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } else { 918c2ecf20Sopenharmony_ci /* no previous measure. */ 928c2ecf20Sopenharmony_ci srtt = m << 3; /* take the measured time to be rtt */ 938c2ecf20Sopenharmony_ci peer->mdev_us = m << 1; /* make sure rto = 3*rtt */ 948c2ecf20Sopenharmony_ci peer->rttvar_us = max(peer->mdev_us, rxrpc_rto_min_us(peer)); 958c2ecf20Sopenharmony_ci peer->mdev_max_us = peer->rttvar_us; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci peer->srtt_us = max(1U, srtt); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* 1028c2ecf20Sopenharmony_ci * Calculate rto without backoff. This is the second half of Van Jacobson's 1038c2ecf20Sopenharmony_ci * routine referred to above. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic void rxrpc_set_rto(struct rxrpc_peer *peer) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci u32 rto; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1. If rtt variance happened to be less 50msec, it is hallucination. 1108c2ecf20Sopenharmony_ci * It cannot be less due to utterly erratic ACK generation made 1118c2ecf20Sopenharmony_ci * at least by solaris and freebsd. "Erratic ACKs" has _nothing_ 1128c2ecf20Sopenharmony_ci * to do with delayed acks, because at cwnd>2 true delack timeout 1138c2ecf20Sopenharmony_ci * is invisible. Actually, Linux-2.4 also generates erratic 1148c2ecf20Sopenharmony_ci * ACKs in some circumstances. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci rto = __rxrpc_set_rto(peer); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* 2. Fixups made earlier cannot be right. 1198c2ecf20Sopenharmony_ci * If we do not estimate RTO correctly without them, 1208c2ecf20Sopenharmony_ci * all the algo is pure shit and should be replaced 1218c2ecf20Sopenharmony_ci * with correct one. It is exactly, which we pretend to do. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* NOTE: clamping at RXRPC_RTO_MIN is not required, current algo 1258c2ecf20Sopenharmony_ci * guarantees that rto is higher. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci peer->rto_j = rxrpc_bound_rto(rto); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void rxrpc_ack_update_rtt(struct rxrpc_peer *peer, long rtt_us) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci if (rtt_us < 0) 1338c2ecf20Sopenharmony_ci return; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci //rxrpc_update_rtt_min(peer, rtt_us); 1368c2ecf20Sopenharmony_ci rxrpc_rtt_estimator(peer, rtt_us); 1378c2ecf20Sopenharmony_ci rxrpc_set_rto(peer); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* RFC6298: only reset backoff on valid RTT measurement. */ 1408c2ecf20Sopenharmony_ci peer->backoff = 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Add RTT information to cache. This is called in softirq mode and has 1458c2ecf20Sopenharmony_ci * exclusive access to the peer RTT data. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_civoid rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why, 1488c2ecf20Sopenharmony_ci int rtt_slot, 1498c2ecf20Sopenharmony_ci rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial, 1508c2ecf20Sopenharmony_ci ktime_t send_time, ktime_t resp_time) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct rxrpc_peer *peer = call->peer; 1538c2ecf20Sopenharmony_ci s64 rtt_us; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci rtt_us = ktime_to_us(ktime_sub(resp_time, send_time)); 1568c2ecf20Sopenharmony_ci if (rtt_us < 0) 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci spin_lock(&peer->rtt_input_lock); 1608c2ecf20Sopenharmony_ci rxrpc_ack_update_rtt(peer, rtt_us); 1618c2ecf20Sopenharmony_ci if (peer->rtt_count < 3) 1628c2ecf20Sopenharmony_ci peer->rtt_count++; 1638c2ecf20Sopenharmony_ci spin_unlock(&peer->rtt_input_lock); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci trace_rxrpc_rtt_rx(call, why, rtt_slot, send_serial, resp_serial, 1668c2ecf20Sopenharmony_ci peer->srtt_us >> 3, peer->rto_j); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * Get the retransmission timeout to set in jiffies, backing it off each time 1718c2ecf20Sopenharmony_ci * we retransmit. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ciunsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *peer, bool retrans) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci u64 timo_j; 1768c2ecf20Sopenharmony_ci u8 backoff = READ_ONCE(peer->backoff); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci timo_j = peer->rto_j; 1798c2ecf20Sopenharmony_ci timo_j <<= backoff; 1808c2ecf20Sopenharmony_ci if (retrans && timo_j * 2 <= RXRPC_RTO_MAX) 1818c2ecf20Sopenharmony_ci WRITE_ONCE(peer->backoff, backoff + 1); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (timo_j < 1) 1848c2ecf20Sopenharmony_ci timo_j = 1; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return timo_j; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_civoid rxrpc_peer_init_rtt(struct rxrpc_peer *peer) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci peer->rto_j = RXRPC_TIMEOUT_INIT; 1928c2ecf20Sopenharmony_ci peer->mdev_us = jiffies_to_usecs(RXRPC_TIMEOUT_INIT); 1938c2ecf20Sopenharmony_ci peer->backoff = 0; 1948c2ecf20Sopenharmony_ci //minmax_reset(&peer->rtt_min, rxrpc_jiffies32, ~0U); 1958c2ecf20Sopenharmony_ci} 196