162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * TCP Veno congestion control
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This is based on the congestion detection/avoidance scheme described in
662306a36Sopenharmony_ci *    C. P. Fu, S. C. Liew.
762306a36Sopenharmony_ci *    "TCP Veno: TCP Enhancement for Transmission over Wireless Access Networks."
862306a36Sopenharmony_ci *    IEEE Journal on Selected Areas in Communication,
962306a36Sopenharmony_ci *    Feb. 2003.
1062306a36Sopenharmony_ci * 	See https://www.ie.cuhk.edu.hk/fileadmin/staff_upload/soung/Journal/J3.pdf
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/mm.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/skbuff.h>
1662306a36Sopenharmony_ci#include <linux/inet_diag.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <net/tcp.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Default values of the Veno variables, in fixed-point representation
2162306a36Sopenharmony_ci * with V_PARAM_SHIFT bits to the right of the binary point.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci#define V_PARAM_SHIFT 1
2462306a36Sopenharmony_cistatic const int beta = 3 << V_PARAM_SHIFT;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Veno variables */
2762306a36Sopenharmony_cistruct veno {
2862306a36Sopenharmony_ci	u8 doing_veno_now;	/* if true, do veno for this rtt */
2962306a36Sopenharmony_ci	u16 cntrtt;		/* # of rtts measured within last rtt */
3062306a36Sopenharmony_ci	u32 minrtt;		/* min of rtts measured within last rtt (in usec) */
3162306a36Sopenharmony_ci	u32 basertt;		/* the min of all Veno rtt measurements seen (in usec) */
3262306a36Sopenharmony_ci	u32 inc;		/* decide whether to increase cwnd */
3362306a36Sopenharmony_ci	u32 diff;		/* calculate the diff rate */
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* There are several situations when we must "re-start" Veno:
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci *  o when a connection is established
3962306a36Sopenharmony_ci *  o after an RTO
4062306a36Sopenharmony_ci *  o after fast recovery
4162306a36Sopenharmony_ci *  o when we send a packet and there is no outstanding
4262306a36Sopenharmony_ci *    unacknowledged data (restarting an idle connection)
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistatic inline void veno_enable(struct sock *sk)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct veno *veno = inet_csk_ca(sk);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* turn on Veno */
5062306a36Sopenharmony_ci	veno->doing_veno_now = 1;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	veno->minrtt = 0x7fffffff;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline void veno_disable(struct sock *sk)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct veno *veno = inet_csk_ca(sk);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* turn off Veno */
6062306a36Sopenharmony_ci	veno->doing_veno_now = 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic void tcp_veno_init(struct sock *sk)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct veno *veno = inet_csk_ca(sk);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	veno->basertt = 0x7fffffff;
6862306a36Sopenharmony_ci	veno->inc = 1;
6962306a36Sopenharmony_ci	veno_enable(sk);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Do rtt sampling needed for Veno. */
7362306a36Sopenharmony_cistatic void tcp_veno_pkts_acked(struct sock *sk,
7462306a36Sopenharmony_ci				const struct ack_sample *sample)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct veno *veno = inet_csk_ca(sk);
7762306a36Sopenharmony_ci	u32 vrtt;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (sample->rtt_us < 0)
8062306a36Sopenharmony_ci		return;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* Never allow zero rtt or baseRTT */
8362306a36Sopenharmony_ci	vrtt = sample->rtt_us + 1;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/* Filter to find propagation delay: */
8662306a36Sopenharmony_ci	if (vrtt < veno->basertt)
8762306a36Sopenharmony_ci		veno->basertt = vrtt;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Find the min rtt during the last rtt to find
9062306a36Sopenharmony_ci	 * the current prop. delay + queuing delay:
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	veno->minrtt = min(veno->minrtt, vrtt);
9362306a36Sopenharmony_ci	veno->cntrtt++;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void tcp_veno_state(struct sock *sk, u8 ca_state)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if (ca_state == TCP_CA_Open)
9962306a36Sopenharmony_ci		veno_enable(sk);
10062306a36Sopenharmony_ci	else
10162306a36Sopenharmony_ci		veno_disable(sk);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * If the connection is idle and we are restarting,
10662306a36Sopenharmony_ci * then we don't want to do any Veno calculations
10762306a36Sopenharmony_ci * until we get fresh rtt samples.  So when we
10862306a36Sopenharmony_ci * restart, we reset our Veno state to a clean
10962306a36Sopenharmony_ci * state. After we get acks for this flight of
11062306a36Sopenharmony_ci * packets, _then_ we can make Veno calculations
11162306a36Sopenharmony_ci * again.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	if (event == CA_EVENT_CWND_RESTART || event == CA_EVENT_TX_START)
11662306a36Sopenharmony_ci		tcp_veno_init(sk);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct tcp_sock *tp = tcp_sk(sk);
12262306a36Sopenharmony_ci	struct veno *veno = inet_csk_ca(sk);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!veno->doing_veno_now) {
12562306a36Sopenharmony_ci		tcp_reno_cong_avoid(sk, ack, acked);
12662306a36Sopenharmony_ci		return;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* limited by applications */
13062306a36Sopenharmony_ci	if (!tcp_is_cwnd_limited(sk))
13162306a36Sopenharmony_ci		return;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* We do the Veno calculations only if we got enough rtt samples */
13462306a36Sopenharmony_ci	if (veno->cntrtt <= 2) {
13562306a36Sopenharmony_ci		/* We don't have enough rtt samples to do the Veno
13662306a36Sopenharmony_ci		 * calculation, so we'll behave like Reno.
13762306a36Sopenharmony_ci		 */
13862306a36Sopenharmony_ci		tcp_reno_cong_avoid(sk, ack, acked);
13962306a36Sopenharmony_ci	} else {
14062306a36Sopenharmony_ci		u64 target_cwnd;
14162306a36Sopenharmony_ci		u32 rtt;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci		/* We have enough rtt samples, so, using the Veno
14462306a36Sopenharmony_ci		 * algorithm, we determine the state of the network.
14562306a36Sopenharmony_ci		 */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		rtt = veno->minrtt;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		target_cwnd = (u64)tcp_snd_cwnd(tp) * veno->basertt;
15062306a36Sopenharmony_ci		target_cwnd <<= V_PARAM_SHIFT;
15162306a36Sopenharmony_ci		do_div(target_cwnd, rtt);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		veno->diff = (tcp_snd_cwnd(tp) << V_PARAM_SHIFT) - target_cwnd;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		if (tcp_in_slow_start(tp)) {
15662306a36Sopenharmony_ci			/* Slow start. */
15762306a36Sopenharmony_ci			acked = tcp_slow_start(tp, acked);
15862306a36Sopenharmony_ci			if (!acked)
15962306a36Sopenharmony_ci				goto done;
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		/* Congestion avoidance. */
16362306a36Sopenharmony_ci		if (veno->diff < beta) {
16462306a36Sopenharmony_ci			/* In the "non-congestive state", increase cwnd
16562306a36Sopenharmony_ci			 * every rtt.
16662306a36Sopenharmony_ci			 */
16762306a36Sopenharmony_ci			tcp_cong_avoid_ai(tp, tcp_snd_cwnd(tp), acked);
16862306a36Sopenharmony_ci		} else {
16962306a36Sopenharmony_ci			/* In the "congestive state", increase cwnd
17062306a36Sopenharmony_ci			 * every other rtt.
17162306a36Sopenharmony_ci			 */
17262306a36Sopenharmony_ci			if (tp->snd_cwnd_cnt >= tcp_snd_cwnd(tp)) {
17362306a36Sopenharmony_ci				if (veno->inc &&
17462306a36Sopenharmony_ci				    tcp_snd_cwnd(tp) < tp->snd_cwnd_clamp) {
17562306a36Sopenharmony_ci					tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) + 1);
17662306a36Sopenharmony_ci					veno->inc = 0;
17762306a36Sopenharmony_ci				} else
17862306a36Sopenharmony_ci					veno->inc = 1;
17962306a36Sopenharmony_ci				tp->snd_cwnd_cnt = 0;
18062306a36Sopenharmony_ci			} else
18162306a36Sopenharmony_ci				tp->snd_cwnd_cnt += acked;
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_cidone:
18462306a36Sopenharmony_ci		if (tcp_snd_cwnd(tp) < 2)
18562306a36Sopenharmony_ci			tcp_snd_cwnd_set(tp, 2);
18662306a36Sopenharmony_ci		else if (tcp_snd_cwnd(tp) > tp->snd_cwnd_clamp)
18762306a36Sopenharmony_ci			tcp_snd_cwnd_set(tp, tp->snd_cwnd_clamp);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci	/* Wipe the slate clean for the next rtt. */
19062306a36Sopenharmony_ci	/* veno->cntrtt = 0; */
19162306a36Sopenharmony_ci	veno->minrtt = 0x7fffffff;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/* Veno MD phase */
19562306a36Sopenharmony_cistatic u32 tcp_veno_ssthresh(struct sock *sk)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	const struct tcp_sock *tp = tcp_sk(sk);
19862306a36Sopenharmony_ci	struct veno *veno = inet_csk_ca(sk);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (veno->diff < beta)
20162306a36Sopenharmony_ci		/* in "non-congestive state", cut cwnd by 1/5 */
20262306a36Sopenharmony_ci		return max(tcp_snd_cwnd(tp) * 4 / 5, 2U);
20362306a36Sopenharmony_ci	else
20462306a36Sopenharmony_ci		/* in "congestive state", cut cwnd by 1/2 */
20562306a36Sopenharmony_ci		return max(tcp_snd_cwnd(tp) >> 1U, 2U);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic struct tcp_congestion_ops tcp_veno __read_mostly = {
20962306a36Sopenharmony_ci	.init		= tcp_veno_init,
21062306a36Sopenharmony_ci	.ssthresh	= tcp_veno_ssthresh,
21162306a36Sopenharmony_ci	.undo_cwnd	= tcp_reno_undo_cwnd,
21262306a36Sopenharmony_ci	.cong_avoid	= tcp_veno_cong_avoid,
21362306a36Sopenharmony_ci	.pkts_acked	= tcp_veno_pkts_acked,
21462306a36Sopenharmony_ci	.set_state	= tcp_veno_state,
21562306a36Sopenharmony_ci	.cwnd_event	= tcp_veno_cwnd_event,
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	.owner		= THIS_MODULE,
21862306a36Sopenharmony_ci	.name		= "veno",
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int __init tcp_veno_register(void)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct veno) > ICSK_CA_PRIV_SIZE);
22462306a36Sopenharmony_ci	tcp_register_congestion_control(&tcp_veno);
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void __exit tcp_veno_unregister(void)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	tcp_unregister_congestion_control(&tcp_veno);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cimodule_init(tcp_veno_register);
23462306a36Sopenharmony_cimodule_exit(tcp_veno_unregister);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciMODULE_AUTHOR("Bin Zhou, Cheng Peng Fu");
23762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
23862306a36Sopenharmony_ciMODULE_DESCRIPTION("TCP Veno");
239