aboutsummaryrefslogtreecommitdiff
path: root/net/ipv4/tcp_agilesd.c
blob: a5bcb37fbc590c04d381ddf2debd7351e34efb36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/* agilesd is a Loss-Based Congestion Control Algorithm for TCP v1.0.
 * agilesd has been created by Mohamed A. Alrshah,
 * at Faculty of Computer Science and Information Technology,
 * Universiti Putra Malaysia.
 * agilesd is based on the article, which is published in 2015 as below:
 * 
 * Alrshah, M.A., Othman, M., Ali, B. and Hanapi, Z.M., 2015. 
 * Agile-SD: a Linux-based TCP congestion control algorithm for supporting high-speed and short-distance networks. 
 * Journal of Network and Computer Applications, 55, pp.181-190. 
 */

/* These includes are very important to operate the algorithm under NS2. */
//#define NS_PROTOCOL "tcp_agilesd.c"
//#include "../ns-linux-c.h"
//#include "../ns-linux-util.h"
//#include <math.h>
/* These includes are very important to operate the algorithm under NS2. */

/* These includes are very important to operate the algorithm under Linux OS. */
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/math64.h>
#include <net/tcp.h>
//#include <linux/skbuff.h>    // optional
//#include <linux/inet_diag.h> // optional
/* These includes are very important to operate the algorithm under Linux OS. */

#define SCALE   1000			/* Scale factor to avoid fractions */
#define Double_SCALE 1000000	/* Double_SCALE must be equal to SCALE^2 */
#define beta    900				/* beta for multiplicative decrease */

static int initial_ssthresh __read_mostly;
//static int beta __read_mostly = 900; /*the initial value of beta is equal to 90%*/

module_param(initial_ssthresh, int, 0644);
MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
//module_param(beta, int, 0444);
//MODULE_PARM_DESC(beta, "beta for multiplicative decrease");

/* agilesd Parameters */
struct agilesdtcp {
	u32		loss_cwnd;			// congestion window at last loss.
	u32		frac_tracer;		// This is to trace the fractions of the increment.
	u32 	degraded_loss_cwnd;	// loss_cwnd after degradation.
	enum 	dystate{SS=0, CA=1} agilesd_tcp_status;
};

static inline void agilesdtcp_reset(struct sock *sk)
{
	/*After timeout loss cntRTT and baseRTT must be reset to the initial values as below */
}

/* This function is called after the first acknowledgment is received and before the congestion
 * control algorithm will be called for the first time. If the congestion control algorithm has
 * private data, it should initialize its private date here. */
static void agilesdtcp_init(struct sock *sk)
{
	struct agilesdtcp *ca = inet_csk_ca(sk);

	// If the value of initial_ssthresh is not set, snd_ssthresh will be initialized by a large value.
	if (initial_ssthresh)
		tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
	else
		tcp_sk(sk)->snd_ssthresh = 0x7fffffff;

	ca->loss_cwnd 		= 0;
	ca->frac_tracer		= 0;
	ca->agilesd_tcp_status 	= SS;
}

/* This function is called whenever an ack is received and the congestion window can be increased.
 * This is equivalent to opencwnd in tcp.cc.
 * ack is the number of bytes that are acknowledged in the latest acknowledgment;
 * rtt is the the rtt measured by the latest acknowledgment;
 * in_flight is the packet in flight before the latest acknowledgment;
 * good_ack is an indicator whether the current situation is normal (no duplicate ack, no loss and no SACK). */
static void agilesdtcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) 					//For Linux Kernel Use.
//static void agilesdtcp_cong_avoid(struct sock *sk, u32 ack, u32 seq_rtt, u32 in_flight, int data_acked) 	//For NS2 Use.
{
	struct tcp_sock *tp = tcp_sk(sk);
	struct agilesdtcp *ca = inet_csk_ca(sk);
	u32 inc_factor;
	u32 ca_inc;
	u32 current_gap, total_gap;
	/* The value of inc_factor is limited by lower_fl and upper_fl.
	 * The lower_fl must be always = 1. The greater the upper_fl the higher the aggressiveness.
	 * But, if upper_fl set to 1, agilesd will work exactly as newreno.
	 * We have already designed an equation to calculate the optimum upper_fl based on the given beta.
	 * This equation will be revealed once its article is published*/
	u32 lower_fl = 1 * SCALE;
	u32 upper_fl = 3 * SCALE;

	//if (!tcp_is_cwnd_limited(sk, in_flight)) return; 	//For NS-2 Use, if the in flight packets not >= cwnd do nothing//
	if (!tcp_is_cwnd_limited(sk)) return;			// For Linux Kernel Use.
	
	if (tp->snd_cwnd < tp->snd_ssthresh){
		ca->agilesd_tcp_status = SS;
		//tcp_slow_start(tp); 				//For NS-2 Use
		tcp_slow_start(tp, in_flight);			// For Linux Kernel Use.
	}
	else {
		ca->agilesd_tcp_status = CA;

		if (ca->loss_cwnd > ca->degraded_loss_cwnd)
			total_gap = ca->loss_cwnd - ca->degraded_loss_cwnd;
		else
			total_gap = 1;

		if (ca->loss_cwnd >  tp->snd_cwnd)
			current_gap = ca->loss_cwnd - tp->snd_cwnd;
		else
			current_gap = 0;

		inc_factor = min(max(((upper_fl * current_gap) / total_gap), lower_fl), upper_fl);

		ca_inc = ((inc_factor * SCALE) / tp->snd_cwnd); /* SCALE is used to avoid fractions*/

		ca->frac_tracer += ca_inc;    			/* This in order to take the fraction increase into account */
		if (ca->frac_tracer >= Double_SCALE) 	/* To take factor scale into account */
		{
			tp->snd_cwnd += 1;
			ca->frac_tracer -= Double_SCALE;
		}
	}
}

/* This function is called when the TCP flow detects a loss.
 * It returns the slow start threshold of a flow, after a packet loss is detected. */
static u32 agilesdtcp_recalc_ssthresh(struct sock *sk)
{
	const struct tcp_sock *tp = tcp_sk(sk);
	struct agilesdtcp *ca = inet_csk_ca(sk);

	ca->loss_cwnd = tp->snd_cwnd;

	if (ca->agilesd_tcp_status == CA)
		ca->degraded_loss_cwnd = max((tp->snd_cwnd * beta) / SCALE, 2U);
	else
		ca->degraded_loss_cwnd = max((tp->snd_cwnd * beta) / SCALE, 2U);

	ca->frac_tracer = 0;

	return ca->degraded_loss_cwnd;
}

/* This function is called when the TCP flow detects a loss.
 * It returns the congestion window of a flow, after a packet loss is detected;
 * (for many algorithms, this will be equal to ssthresh). When a loss is detected,
 * min_cwnd is called after ssthresh. But some others algorithms might set min_cwnd
 * to be smaller than ssthresh. If this is the case, there will be a slow start after loss recovery. */
//static u32 agilesdtcp_min_cwnd(const struct sock *sk)
//{
//	return tcp_sk(sk)->snd_ssthresh;
//}

static u32 agilesdtcp_undo_cwnd(struct sock *sk)
{
	const struct tcp_sock *tp = tcp_sk(sk);
	const struct agilesdtcp *ca = inet_csk_ca(sk);
	return max(tp->snd_cwnd, ca->loss_cwnd);
}

/* This function is called when the congestion state of the TCP is changed.
 * newstate is the state code for the state that TCP is going to be in.
 * The possible states are listed below:
 * The current congestion control state, which can be one of the followings:
 * TCP_CA_Open: normal state
 * TCP_CA_Recovery: Loss Recovery after a Fast Transmission
 * TCP_CA_Loss: Loss Recovery after a  Timeout
 * (The following two states are not effective in TCP-Linux but is effective in Linux)
 * TCP_CA_Disorder: duplicate packets detected, but haven't reach the threshold. So TCP  shall assume that  packet reordering is happening.
 * TCP_CA_CWR: the state that congestion window is decreasing (after local congestion in NIC, or ECN and etc).
 * It is to notify the congestion control algorithm and is used by some
 * algorithms which turn off their special control during loss recovery. */
static void agilesdtcp_state(struct sock *sk, u8 new_state)
{
	if (new_state == TCP_CA_Loss)
		agilesdtcp_reset(inet_csk_ca(sk));
}

/* This function is called when there is an acknowledgment that acknowledges some new packets.
 * num_acked is the number of packets that are acknowledged by this acknowledgments. */
//static void agilesdtcp_acked(struct sock *sk, u32 num_acked, ktime_t rtt_us) 			//For NS2 Use.
static void agilesdtcp_acked(struct sock *sk, const struct ack_sample *sample) 		//For Linux Kernel Use.
{

}

static struct tcp_congestion_ops agilesdtcp __read_mostly = {
	.init		= agilesdtcp_init,
	.ssthresh	= agilesdtcp_recalc_ssthresh, 	//REQUIRED
	.cong_avoid	= agilesdtcp_cong_avoid, 	//REQUIRED
	.set_state	= agilesdtcp_state,
	.undo_cwnd	= agilesdtcp_undo_cwnd,
	.pkts_acked	= agilesdtcp_acked,
	.owner		= THIS_MODULE,
	.name		= "agilesd", 			//REQUIRED
	//.min_cwnd	= agilesdtcp_min_cwnd, 		//NOT REQUIRED
};

static int __init agilesdtcp_register(void)
{
	BUILD_BUG_ON(sizeof(struct agilesdtcp) > ICSK_CA_PRIV_SIZE);
	return tcp_register_congestion_control(&agilesdtcp);
}

static void __exit agilesdtcp_unregister(void)
{
	tcp_unregister_congestion_control(&agilesdtcp);
}

module_init(agilesdtcp_register);
module_exit(agilesdtcp_unregister);

MODULE_AUTHOR("Mohamed A. Alrshah <mohamed.a.alrshah@ieee.org>");
MODULE_AUTHOR("Mohamed Othman");
MODULE_AUTHOR("Borhanuddin Ali");
MODULE_AUTHOR("Zurina Hanapi");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("agilesd is a Loss-Based Congestion Control Algorithm for TCP v1.0. By Mohamed A. Alrshah");
MODULE_VERSION("1.0");