~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv4/tcp_htcp.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * H-TCP congestion control. The algorithm is detailed in:
  4  * R.N.Shorten, D.J.Leith:
  5  *   "H-TCP: TCP for high-speed and long-distance networks"
  6  *   Proc. PFLDnet, Argonne, 2004.
  7  * https://www.hamilton.ie/net/htcp3.pdf
  8  */
  9 
 10 #include <linux/mm.h>
 11 #include <linux/module.h>
 12 #include <net/tcp.h>
 13 
 14 #define ALPHA_BASE      (1<<7)  /* 1.0 with shift << 7 */
 15 #define BETA_MIN        (1<<6)  /* 0.5 with shift << 7 */
 16 #define BETA_MAX        102     /* 0.8 with shift << 7 */
 17 
 18 static int use_rtt_scaling __read_mostly = 1;
 19 module_param(use_rtt_scaling, int, 0644);
 20 MODULE_PARM_DESC(use_rtt_scaling, "turn on/off RTT scaling");
 21 
 22 static int use_bandwidth_switch __read_mostly = 1;
 23 module_param(use_bandwidth_switch, int, 0644);
 24 MODULE_PARM_DESC(use_bandwidth_switch, "turn on/off bandwidth switcher");
 25 
 26 struct htcp {
 27         u32     alpha;          /* Fixed point arith, << 7 */
 28         u8      beta;           /* Fixed point arith, << 7 */
 29         u8      modeswitch;     /* Delay modeswitch
 30                                    until we had at least one congestion event */
 31         u16     pkts_acked;
 32         u32     packetcount;
 33         u32     minRTT;
 34         u32     maxRTT;
 35         u32     last_cong;      /* Time since last congestion event end */
 36         u32     undo_last_cong;
 37 
 38         u32     undo_maxRTT;
 39         u32     undo_old_maxB;
 40 
 41         /* Bandwidth estimation */
 42         u32     minB;
 43         u32     maxB;
 44         u32     old_maxB;
 45         u32     Bi;
 46         u32     lasttime;
 47 };
 48 
 49 static inline u32 htcp_cong_time(const struct htcp *ca)
 50 {
 51         return jiffies - ca->last_cong;
 52 }
 53 
 54 static inline u32 htcp_ccount(const struct htcp *ca)
 55 {
 56         return htcp_cong_time(ca) / ca->minRTT;
 57 }
 58 
 59 static inline void htcp_reset(struct htcp *ca)
 60 {
 61         ca->undo_last_cong = ca->last_cong;
 62         ca->undo_maxRTT = ca->maxRTT;
 63         ca->undo_old_maxB = ca->old_maxB;
 64 
 65         ca->last_cong = jiffies;
 66 }
 67 
 68 static u32 htcp_cwnd_undo(struct sock *sk)
 69 {
 70         struct htcp *ca = inet_csk_ca(sk);
 71 
 72         if (ca->undo_last_cong) {
 73                 ca->last_cong = ca->undo_last_cong;
 74                 ca->maxRTT = ca->undo_maxRTT;
 75                 ca->old_maxB = ca->undo_old_maxB;
 76                 ca->undo_last_cong = 0;
 77         }
 78 
 79         return tcp_reno_undo_cwnd(sk);
 80 }
 81 
 82 static inline void measure_rtt(struct sock *sk, u32 srtt)
 83 {
 84         const struct inet_connection_sock *icsk = inet_csk(sk);
 85         struct htcp *ca = inet_csk_ca(sk);
 86 
 87         /* keep track of minimum RTT seen so far, minRTT is zero at first */
 88         if (ca->minRTT > srtt || !ca->minRTT)
 89                 ca->minRTT = srtt;
 90 
 91         /* max RTT */
 92         if (icsk->icsk_ca_state == TCP_CA_Open) {
 93                 if (ca->maxRTT < ca->minRTT)
 94                         ca->maxRTT = ca->minRTT;
 95                 if (ca->maxRTT < srtt &&
 96                     srtt <= ca->maxRTT + msecs_to_jiffies(20))
 97                         ca->maxRTT = srtt;
 98         }
 99 }
100 
101 static void measure_achieved_throughput(struct sock *sk,
102                                         const struct ack_sample *sample)
103 {
104         const struct inet_connection_sock *icsk = inet_csk(sk);
105         const struct tcp_sock *tp = tcp_sk(sk);
106         struct htcp *ca = inet_csk_ca(sk);
107         u32 now = tcp_jiffies32;
108 
109         if (icsk->icsk_ca_state == TCP_CA_Open)
110                 ca->pkts_acked = sample->pkts_acked;
111 
112         if (sample->rtt_us > 0)
113                 measure_rtt(sk, usecs_to_jiffies(sample->rtt_us));
114 
115         if (!use_bandwidth_switch)
116                 return;
117 
118         /* achieved throughput calculations */
119         if (!((1 << icsk->icsk_ca_state) & (TCPF_CA_Open | TCPF_CA_Disorder))) {
120                 ca->packetcount = 0;
121                 ca->lasttime = now;
122                 return;
123         }
124 
125         ca->packetcount += sample->pkts_acked;
126 
127         if (ca->packetcount >= tcp_snd_cwnd(tp) - (ca->alpha >> 7 ? : 1) &&
128             now - ca->lasttime >= ca->minRTT &&
129             ca->minRTT > 0) {
130                 __u32 cur_Bi = ca->packetcount * HZ / (now - ca->lasttime);
131 
132                 if (htcp_ccount(ca) <= 3) {
133                         /* just after backoff */
134                         ca->minB = ca->maxB = ca->Bi = cur_Bi;
135                 } else {
136                         ca->Bi = (3 * ca->Bi + cur_Bi) / 4;
137                         if (ca->Bi > ca->maxB)
138                                 ca->maxB = ca->Bi;
139                         if (ca->minB > ca->maxB)
140                                 ca->minB = ca->maxB;
141                 }
142                 ca->packetcount = 0;
143                 ca->lasttime = now;
144         }
145 }
146 
147 static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT)
148 {
149         if (use_bandwidth_switch) {
150                 u32 maxB = ca->maxB;
151                 u32 old_maxB = ca->old_maxB;
152 
153                 ca->old_maxB = ca->maxB;
154                 if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
155                         ca->beta = BETA_MIN;
156                         ca->modeswitch = 0;
157                         return;
158                 }
159         }
160 
161         if (ca->modeswitch && minRTT > msecs_to_jiffies(10) && maxRTT) {
162                 ca->beta = (minRTT << 7) / maxRTT;
163                 if (ca->beta < BETA_MIN)
164                         ca->beta = BETA_MIN;
165                 else if (ca->beta > BETA_MAX)
166                         ca->beta = BETA_MAX;
167         } else {
168                 ca->beta = BETA_MIN;
169                 ca->modeswitch = 1;
170         }
171 }
172 
173 static inline void htcp_alpha_update(struct htcp *ca)
174 {
175         u32 minRTT = ca->minRTT;
176         u32 factor = 1;
177         u32 diff = htcp_cong_time(ca);
178 
179         if (diff > HZ) {
180                 diff -= HZ;
181                 factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / HZ)) / HZ;
182         }
183 
184         if (use_rtt_scaling && minRTT) {
185                 u32 scale = (HZ << 3) / (10 * minRTT);
186 
187                 /* clamping ratio to interval [0.5,10]<<3 */
188                 scale = min(max(scale, 1U << 2), 10U << 3);
189                 factor = (factor << 3) / scale;
190                 if (!factor)
191                         factor = 1;
192         }
193 
194         ca->alpha = 2 * factor * ((1 << 7) - ca->beta);
195         if (!ca->alpha)
196                 ca->alpha = ALPHA_BASE;
197 }
198 
199 /*
200  * After we have the rtt data to calculate beta, we'd still prefer to wait one
201  * rtt before we adjust our beta to ensure we are working from a consistent
202  * data.
203  *
204  * This function should be called when we hit a congestion event since only at
205  * that point do we really have a real sense of maxRTT (the queues en route
206  * were getting just too full now).
207  */
208 static void htcp_param_update(struct sock *sk)
209 {
210         struct htcp *ca = inet_csk_ca(sk);
211         u32 minRTT = ca->minRTT;
212         u32 maxRTT = ca->maxRTT;
213 
214         htcp_beta_update(ca, minRTT, maxRTT);
215         htcp_alpha_update(ca);
216 
217         /* add slowly fading memory for maxRTT to accommodate routing changes */
218         if (minRTT > 0 && maxRTT > minRTT)
219                 ca->maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100;
220 }
221 
222 static u32 htcp_recalc_ssthresh(struct sock *sk)
223 {
224         const struct tcp_sock *tp = tcp_sk(sk);
225         const struct htcp *ca = inet_csk_ca(sk);
226 
227         htcp_param_update(sk);
228         return max((tcp_snd_cwnd(tp) * ca->beta) >> 7, 2U);
229 }
230 
231 static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
232 {
233         struct tcp_sock *tp = tcp_sk(sk);
234         struct htcp *ca = inet_csk_ca(sk);
235 
236         if (!tcp_is_cwnd_limited(sk))
237                 return;
238 
239         if (tcp_in_slow_start(tp))
240                 tcp_slow_start(tp, acked);
241         else {
242                 /* In dangerous area, increase slowly.
243                  * In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd
244                  */
245                 if ((tp->snd_cwnd_cnt * ca->alpha)>>7 >= tcp_snd_cwnd(tp)) {
246                         if (tcp_snd_cwnd(tp) < tp->snd_cwnd_clamp)
247                                 tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) + 1);
248                         tp->snd_cwnd_cnt = 0;
249                         htcp_alpha_update(ca);
250                 } else
251                         tp->snd_cwnd_cnt += ca->pkts_acked;
252 
253                 ca->pkts_acked = 1;
254         }
255 }
256 
257 static void htcp_init(struct sock *sk)
258 {
259         struct htcp *ca = inet_csk_ca(sk);
260 
261         memset(ca, 0, sizeof(struct htcp));
262         ca->alpha = ALPHA_BASE;
263         ca->beta = BETA_MIN;
264         ca->pkts_acked = 1;
265         ca->last_cong = jiffies;
266 }
267 
268 static void htcp_state(struct sock *sk, u8 new_state)
269 {
270         switch (new_state) {
271         case TCP_CA_Open:
272                 {
273                         struct htcp *ca = inet_csk_ca(sk);
274 
275                         if (ca->undo_last_cong) {
276                                 ca->last_cong = jiffies;
277                                 ca->undo_last_cong = 0;
278                         }
279                 }
280                 break;
281         case TCP_CA_CWR:
282         case TCP_CA_Recovery:
283         case TCP_CA_Loss:
284                 htcp_reset(inet_csk_ca(sk));
285                 break;
286         }
287 }
288 
289 static struct tcp_congestion_ops htcp __read_mostly = {
290         .init           = htcp_init,
291         .ssthresh       = htcp_recalc_ssthresh,
292         .cong_avoid     = htcp_cong_avoid,
293         .set_state      = htcp_state,
294         .undo_cwnd      = htcp_cwnd_undo,
295         .pkts_acked     = measure_achieved_throughput,
296         .owner          = THIS_MODULE,
297         .name           = "htcp",
298 };
299 
300 static int __init htcp_register(void)
301 {
302         BUILD_BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE);
303         BUILD_BUG_ON(BETA_MIN >= BETA_MAX);
304         return tcp_register_congestion_control(&htcp);
305 }
306 
307 static void __exit htcp_unregister(void)
308 {
309         tcp_unregister_congestion_control(&htcp);
310 }
311 
312 module_init(htcp_register);
313 module_exit(htcp_unregister);
314 
315 MODULE_AUTHOR("Baruch Even");
316 MODULE_LICENSE("GPL");
317 MODULE_DESCRIPTION("H-TCP");
318 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php