root/net/ipv4/tcp_htcp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. htcp_cong_time
  2. htcp_ccount
  3. htcp_reset
  4. htcp_cwnd_undo
  5. measure_rtt
  6. measure_achieved_throughput
  7. htcp_beta_update
  8. htcp_alpha_update
  9. htcp_param_update
  10. htcp_recalc_ssthresh
  11. htcp_cong_avoid
  12. htcp_init
  13. htcp_state
  14. htcp_register
  15. htcp_unregister

   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  * http://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 >= tp->snd_cwnd - (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((tp->snd_cwnd * 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 >= tp->snd_cwnd) {
 246                         if (tp->snd_cwnd < tp->snd_cwnd_clamp)
 247                                 tp->snd_cwnd++;
 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");

/* [<][>][^][v][top][bottom][index][help] */