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