1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009-2013 5 * Swinburne University of Technology, Melbourne, Australia 6 * All rights reserved. 7 * 8 * This software was developed at the Centre for Advanced Internet 9 * Architectures, Swinburne University of Technology, by David Hayes, made 10 * possible in part by a gift from The Cisco University Research Program Fund, 11 * a corporate advised fund of Silicon Valley Community Foundation. Development 12 * and testing were further assisted by a grant from the FreeBSD Foundation. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /* 37 * CAIA Delay-Gradient (CDG) congestion control algorithm 38 * 39 * An implemention of the delay-gradient congestion control algorithm proposed 40 * in the following paper: 41 * 42 * D. A. Hayes and G. Armitage, "Revisiting TCP Congestion Control using Delay 43 * Gradients", in IFIP Networking, Valencia, Spain, 9-13 May 2011. 44 * 45 * Developed as part of the NewTCP research project at Swinburne University of 46 * Technology's Centre for Advanced Internet Architectures, Melbourne, 47 * Australia. More details are available at: 48 * http://caia.swin.edu.au/urp/newtcp/ 49 */ 50 51 #include <sys/param.h> 52 #include <sys/hhook.h> 53 #include <sys/kernel.h> 54 #include <sys/khelp.h> 55 #include <sys/limits.h> 56 #include <sys/lock.h> 57 #include <sys/malloc.h> 58 #include <sys/module.h> 59 #include <sys/queue.h> 60 #include <sys/prng.h> 61 #include <sys/socket.h> 62 #include <sys/socketvar.h> 63 #include <sys/sysctl.h> 64 #include <sys/systm.h> 65 66 #include <net/vnet.h> 67 68 #include <net/route.h> 69 #include <net/route/nhop.h> 70 71 #include <netinet/in_pcb.h> 72 #include <netinet/tcp.h> 73 #include <netinet/tcp_seq.h> 74 #include <netinet/tcp_timer.h> 75 #include <netinet/tcp_var.h> 76 #include <netinet/cc/cc.h> 77 #include <netinet/cc/cc_module.h> 78 79 #include <netinet/khelp/h_ertt.h> 80 81 #include <vm/uma.h> 82 83 #define CDG_VERSION "0.1" 84 85 /* Private delay-gradient induced congestion control signal. */ 86 #define CC_CDG_DELAY 0x01000000 87 88 /* NewReno window deflation factor on loss (as a percentage). */ 89 #define RENO_BETA 50 90 91 /* Queue states. */ 92 #define CDG_Q_EMPTY 1 93 #define CDG_Q_RISING 2 94 #define CDG_Q_FALLING 3 95 #define CDG_Q_FULL 4 96 #define CDG_Q_UNKNOWN 9999 97 98 /* Number of bit shifts used in probexp lookup table. */ 99 #define EXP_PREC 15 100 101 /* Largest gradient represented in probexp lookup table. */ 102 #define MAXGRAD 5 103 104 /* 105 * Delay Precision Enhance - number of bit shifts used for qtrend related 106 * integer arithmetic precision. 107 */ 108 #define D_P_E 7 109 110 struct qdiff_sample { 111 long qdiff; 112 STAILQ_ENTRY(qdiff_sample) qdiff_lnk; 113 }; 114 115 struct cdg { 116 long max_qtrend; 117 long min_qtrend; 118 STAILQ_HEAD(minrtts_head, qdiff_sample) qdiffmin_q; 119 STAILQ_HEAD(maxrtts_head, qdiff_sample) qdiffmax_q; 120 long window_incr; 121 /* rttcount for window increase when in congestion avoidance */ 122 long rtt_count; 123 /* maximum measured rtt within an rtt period */ 124 int maxrtt_in_rtt; 125 /* maximum measured rtt within prev rtt period */ 126 int maxrtt_in_prevrtt; 127 /* minimum measured rtt within an rtt period */ 128 int minrtt_in_rtt; 129 /* minimum measured rtt within prev rtt period */ 130 int minrtt_in_prevrtt; 131 /* consecutive congestion episode counter */ 132 uint32_t consec_cong_cnt; 133 /* when tracking a new reno type loss window */ 134 uint32_t shadow_w; 135 /* maximum number of samples in the moving average queue */ 136 int sample_q_size; 137 /* number of samples in the moving average queue */ 138 int num_samples; 139 /* estimate of the queue state of the path */ 140 int queue_state; 141 }; 142 143 /* 144 * Lookup table for: 145 * (1 - exp(-x)) << EXP_PREC, where x = [0,MAXGRAD] in 2^-7 increments 146 * 147 * Note: probexp[0] is set to 10 (not 0) as a safety for very low increase 148 * gradients. 149 */ 150 static const int probexp[641] = { 151 10,255,508,759,1008,1255,1501,1744,1985,2225,2463,2698,2932,3165,3395,3624, 152 3850,4075,4299,4520,4740,4958,5175,5389,5602,5814,6024,6232,6438,6643,6846, 153 7048,7248,7447,7644,7839,8033,8226,8417,8606,8794,8981,9166,9350,9532,9713, 154 9892,10070,10247,10422,10596,10769,10940,11110,11278,11445,11611,11776,11939, 155 12101,12262,12422,12580,12737,12893,13048,13201,13354,13505,13655,13803,13951, 156 14097,14243,14387,14530,14672,14813,14952,15091,15229,15365,15500,15635,15768, 157 15900,16032,16162,16291,16419,16547,16673,16798,16922,17046,17168,17289,17410, 158 17529,17648,17766,17882,17998,18113,18227,18340,18453,18564,18675,18784,18893, 159 19001,19108,19215,19320,19425,19529,19632,19734,19835,19936,20036,20135,20233, 160 20331,20427,20523,20619,20713,20807,20900,20993,21084,21175,21265,21355,21444, 161 21532,21619,21706,21792,21878,21962,22046,22130,22213,22295,22376,22457,22537, 162 22617,22696,22774,22852,22929,23006,23082,23157,23232,23306,23380,23453,23525, 163 23597,23669,23739,23810,23879,23949,24017,24085,24153,24220,24286,24352,24418, 164 24483,24547,24611,24675,24738,24800,24862,24924,24985,25045,25106,25165,25224, 165 25283,25341,25399,25456,25513,25570,25626,25681,25737,25791,25846,25899,25953, 166 26006,26059,26111,26163,26214,26265,26316,26366,26416,26465,26514,26563,26611, 167 26659,26707,26754,26801,26847,26893,26939,26984,27029,27074,27118,27162,27206, 168 27249,27292,27335,27377,27419,27460,27502,27543,27583,27624,27664,27703,27743, 169 27782,27821,27859,27897,27935,27973,28010,28047,28084,28121,28157,28193,28228, 170 28263,28299,28333,28368,28402,28436,28470,28503,28536,28569,28602,28634,28667, 171 28699,28730,28762,28793,28824,28854,28885,28915,28945,28975,29004,29034,29063, 172 29092,29120,29149,29177,29205,29232,29260,29287,29314,29341,29368,29394,29421, 173 29447,29472,29498,29524,29549,29574,29599,29623,29648,29672,29696,29720,29744, 174 29767,29791,29814,29837,29860,29882,29905,29927,29949,29971,29993,30014,30036, 175 30057,30078,30099,30120,30141,30161,30181,30201,30221,30241,30261,30280,30300, 176 30319,30338,30357,30376,30394,30413,30431,30449,30467,30485,30503,30521,30538, 177 30555,30573,30590,30607,30624,30640,30657,30673,30690,30706,30722,30738,30753, 178 30769,30785,30800,30815,30831,30846,30861,30876,30890,30905,30919,30934,30948, 179 30962,30976,30990,31004,31018,31031,31045,31058,31072,31085,31098,31111,31124, 180 31137,31149,31162,31174,31187,31199,31211,31223,31235,31247,31259,31271,31283, 181 31294,31306,31317,31328,31339,31351,31362,31373,31383,31394,31405,31416,31426, 182 31436,31447,31457,31467,31477,31487,31497,31507,31517,31527,31537,31546,31556, 183 31565,31574,31584,31593,31602,31611,31620,31629,31638,31647,31655,31664,31673, 184 31681,31690,31698,31706,31715,31723,31731,31739,31747,31755,31763,31771,31778, 185 31786,31794,31801,31809,31816,31824,31831,31838,31846,31853,31860,31867,31874, 186 31881,31888,31895,31902,31908,31915,31922,31928,31935,31941,31948,31954,31960, 187 31967,31973,31979,31985,31991,31997,32003,32009,32015,32021,32027,32033,32038, 188 32044,32050,32055,32061,32066,32072,32077,32083,32088,32093,32098,32104,32109, 189 32114,32119,32124,32129,32134,32139,32144,32149,32154,32158,32163,32168,32173, 190 32177,32182,32186,32191,32195,32200,32204,32209,32213,32217,32222,32226,32230, 191 32234,32238,32242,32247,32251,32255,32259,32263,32267,32270,32274,32278,32282, 192 32286,32290,32293,32297,32301,32304,32308,32311,32315,32318,32322,32325,32329, 193 32332,32336,32339,32342,32346,32349,32352,32356,32359,32362,32365,32368,32371, 194 32374,32377,32381,32384,32387,32389,32392,32395,32398,32401,32404,32407,32410, 195 32412,32415,32418,32421,32423,32426,32429,32431,32434,32437,32439,32442,32444, 196 32447,32449,32452,32454,32457,32459,32461,32464,32466,32469,32471,32473,32476, 197 32478,32480,32482,32485,32487,32489,32491,32493,32495,32497,32500,32502,32504, 198 32506,32508,32510,32512,32514,32516,32518,32520,32522,32524,32526,32527,32529, 199 32531,32533,32535,32537,32538,32540,32542,32544,32545,32547}; 200 201 static uma_zone_t qdiffsample_zone; 202 static int ertt_id; 203 204 VNET_DEFINE_STATIC(uint32_t, cdg_alpha_inc); 205 VNET_DEFINE_STATIC(uint32_t, cdg_beta_delay); 206 VNET_DEFINE_STATIC(uint32_t, cdg_beta_loss); 207 VNET_DEFINE_STATIC(uint32_t, cdg_smoothing_factor); 208 VNET_DEFINE_STATIC(uint32_t, cdg_exp_backoff_scale); 209 VNET_DEFINE_STATIC(uint32_t, cdg_consec_cong); 210 VNET_DEFINE_STATIC(uint32_t, cdg_hold_backoff); 211 #define V_cdg_alpha_inc VNET(cdg_alpha_inc) 212 #define V_cdg_beta_delay VNET(cdg_beta_delay) 213 #define V_cdg_beta_loss VNET(cdg_beta_loss) 214 #define V_cdg_smoothing_factor VNET(cdg_smoothing_factor) 215 #define V_cdg_exp_backoff_scale VNET(cdg_exp_backoff_scale) 216 #define V_cdg_consec_cong VNET(cdg_consec_cong) 217 #define V_cdg_hold_backoff VNET(cdg_hold_backoff) 218 219 /* Function prototypes. */ 220 static int cdg_mod_init(void); 221 static int cdg_mod_destroy(void); 222 static void cdg_conn_init(struct cc_var *ccv); 223 static int cdg_cb_init(struct cc_var *ccv, void *ptr); 224 static void cdg_cb_destroy(struct cc_var *ccv); 225 static void cdg_cong_signal(struct cc_var *ccv, ccsignal_t signal_type); 226 static void cdg_ack_received(struct cc_var *ccv, ccsignal_t ack_type); 227 static size_t cdg_data_sz(void); 228 229 struct cc_algo cdg_cc_algo = { 230 .name = "cdg", 231 .mod_init = cdg_mod_init, 232 .ack_received = cdg_ack_received, 233 .cb_destroy = cdg_cb_destroy, 234 .cb_init = cdg_cb_init, 235 .conn_init = cdg_conn_init, 236 .cong_signal = cdg_cong_signal, 237 .mod_destroy = cdg_mod_destroy, 238 .cc_data_sz = cdg_data_sz, 239 .post_recovery = newreno_cc_post_recovery, 240 .after_idle = newreno_cc_after_idle, 241 }; 242 243 /* Vnet created and being initialised. */ 244 static void 245 cdg_init_vnet(const void *unused __unused) 246 { 247 248 V_cdg_alpha_inc = 0; 249 V_cdg_beta_delay = 70; 250 V_cdg_beta_loss = 50; 251 V_cdg_smoothing_factor = 8; 252 V_cdg_exp_backoff_scale = 3; 253 V_cdg_consec_cong = 5; 254 V_cdg_hold_backoff = 5; 255 } 256 257 static int 258 cdg_mod_init(void) 259 { 260 VNET_ITERATOR_DECL(v); 261 262 ertt_id = khelp_get_id("ertt"); 263 if (ertt_id <= 0) 264 return (EINVAL); 265 266 qdiffsample_zone = uma_zcreate("cdg_qdiffsample", 267 sizeof(struct qdiff_sample), NULL, NULL, NULL, NULL, 0, 0); 268 269 VNET_LIST_RLOCK(); 270 VNET_FOREACH(v) { 271 CURVNET_SET(v); 272 cdg_init_vnet(NULL); 273 CURVNET_RESTORE(); 274 } 275 VNET_LIST_RUNLOCK(); 276 return (0); 277 } 278 279 static int 280 cdg_mod_destroy(void) 281 { 282 283 uma_zdestroy(qdiffsample_zone); 284 return (0); 285 } 286 287 static size_t 288 cdg_data_sz(void) 289 { 290 return (sizeof(struct cdg)); 291 } 292 293 static int 294 cdg_cb_init(struct cc_var *ccv, void *ptr) 295 { 296 struct cdg *cdg_data; 297 298 INP_WLOCK_ASSERT(tptoinpcb(ccv->tp)); 299 if (ptr == NULL) { 300 cdg_data = malloc(sizeof(struct cdg), M_CC_MEM, M_NOWAIT); 301 if (cdg_data == NULL) 302 return (ENOMEM); 303 } else { 304 cdg_data = ptr; 305 } 306 cdg_data->shadow_w = 0; 307 cdg_data->max_qtrend = 0; 308 cdg_data->min_qtrend = 0; 309 cdg_data->queue_state = CDG_Q_UNKNOWN; 310 cdg_data->maxrtt_in_rtt = 0; 311 cdg_data->maxrtt_in_prevrtt = 0; 312 cdg_data->minrtt_in_rtt = INT_MAX; 313 cdg_data->minrtt_in_prevrtt = 0; 314 cdg_data->window_incr = 0; 315 cdg_data->rtt_count = 0; 316 cdg_data->consec_cong_cnt = 0; 317 cdg_data->sample_q_size = V_cdg_smoothing_factor; 318 cdg_data->num_samples = 0; 319 STAILQ_INIT(&cdg_data->qdiffmin_q); 320 STAILQ_INIT(&cdg_data->qdiffmax_q); 321 322 ccv->cc_data = cdg_data; 323 324 return (0); 325 } 326 327 static void 328 cdg_conn_init(struct cc_var *ccv) 329 { 330 struct cdg *cdg_data = ccv->cc_data; 331 332 /* 333 * Initialise the shadow_cwnd in case we are competing with loss based 334 * flows from the start 335 */ 336 cdg_data->shadow_w = CCV(ccv, snd_cwnd); 337 } 338 339 static void 340 cdg_cb_destroy(struct cc_var *ccv) 341 { 342 struct cdg *cdg_data; 343 struct qdiff_sample *qds, *qds_n; 344 345 cdg_data = ccv->cc_data; 346 347 qds = STAILQ_FIRST(&cdg_data->qdiffmin_q); 348 while (qds != NULL) { 349 qds_n = STAILQ_NEXT(qds, qdiff_lnk); 350 uma_zfree(qdiffsample_zone,qds); 351 qds = qds_n; 352 } 353 354 qds = STAILQ_FIRST(&cdg_data->qdiffmax_q); 355 while (qds != NULL) { 356 qds_n = STAILQ_NEXT(qds, qdiff_lnk); 357 uma_zfree(qdiffsample_zone,qds); 358 qds = qds_n; 359 } 360 361 free(ccv->cc_data, M_CC_MEM); 362 } 363 364 static int 365 cdg_beta_handler(SYSCTL_HANDLER_ARGS) 366 { 367 int error; 368 uint32_t new; 369 370 new = *(uint32_t *)arg1; 371 error = sysctl_handle_int(oidp, &new, 0, req); 372 if (error == 0 && req->newptr != NULL) { 373 if (new == 0 || new > 100) 374 error = EINVAL; 375 else 376 *(uint32_t *)arg1 = new; 377 } 378 379 return (error); 380 } 381 382 static int 383 cdg_exp_backoff_scale_handler(SYSCTL_HANDLER_ARGS) 384 { 385 int error; 386 uint32_t new; 387 388 new = *(uint32_t *)arg1; 389 error = sysctl_handle_int(oidp, &new, 0, req); 390 if (error == 0 && req->newptr != NULL) { 391 if (new < 1) 392 error = EINVAL; 393 else 394 *(uint32_t *)arg1 = new; 395 } 396 397 return (error); 398 } 399 400 static inline uint32_t 401 cdg_window_decrease(struct cc_var *ccv, unsigned long owin, unsigned int beta) 402 { 403 404 return ((ulmin(CCV(ccv, snd_wnd), owin) * beta) / 100); 405 } 406 407 /* 408 * Window increase function 409 * This window increase function is independent of the initial window size 410 * to ensure small window flows are not discriminated against (i.e. fairness). 411 * It increases at 1pkt/rtt like Reno for alpha_inc rtts, and then 2pkts/rtt for 412 * the next alpha_inc rtts, etc. 413 */ 414 static void 415 cdg_window_increase(struct cc_var *ccv, int new_measurement) 416 { 417 struct cdg *cdg_data; 418 int incr, s_w_incr; 419 420 cdg_data = ccv->cc_data; 421 incr = s_w_incr = 0; 422 423 if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh)) { 424 /* Slow start. */ 425 incr = CCV(ccv, t_maxseg); 426 s_w_incr = incr; 427 cdg_data->window_incr = cdg_data->rtt_count = 0; 428 } else { 429 /* Congestion avoidance. */ 430 if (new_measurement) { 431 s_w_incr = CCV(ccv, t_maxseg); 432 if (V_cdg_alpha_inc == 0) { 433 incr = CCV(ccv, t_maxseg); 434 } else { 435 if (++cdg_data->rtt_count >= V_cdg_alpha_inc) { 436 cdg_data->window_incr++; 437 cdg_data->rtt_count = 0; 438 } 439 incr = CCV(ccv, t_maxseg) * 440 cdg_data->window_incr; 441 } 442 } 443 } 444 445 if (cdg_data->shadow_w > 0) 446 cdg_data->shadow_w = ulmin(cdg_data->shadow_w + s_w_incr, 447 TCP_MAXWIN << CCV(ccv, snd_scale)); 448 449 CCV(ccv, snd_cwnd) = ulmin(CCV(ccv, snd_cwnd) + incr, 450 TCP_MAXWIN << CCV(ccv, snd_scale)); 451 } 452 453 static void 454 cdg_cong_signal(struct cc_var *ccv, ccsignal_t signal_type) 455 { 456 struct cdg *cdg_data = ccv->cc_data; 457 458 switch((int)signal_type) { 459 case CC_CDG_DELAY: 460 CCV(ccv, snd_ssthresh) = cdg_window_decrease(ccv, 461 CCV(ccv, snd_cwnd), V_cdg_beta_delay); 462 CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); 463 CCV(ccv, snd_recover) = CCV(ccv, snd_max); 464 cdg_data->window_incr = cdg_data->rtt_count = 0; 465 ENTER_CONGRECOVERY(CCV(ccv, t_flags)); 466 break; 467 case CC_NDUPACK: 468 /* 469 * If already responding to congestion OR we have guessed no 470 * queue in the path is full. 471 */ 472 if (IN_CONGRECOVERY(CCV(ccv, t_flags)) || 473 cdg_data->queue_state < CDG_Q_FULL) { 474 CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd); 475 CCV(ccv, snd_recover) = CCV(ccv, snd_max); 476 } else { 477 /* 478 * Loss is likely to be congestion related. We have 479 * inferred a queue full state, so have shadow window 480 * react to loss as NewReno would. 481 */ 482 if (cdg_data->shadow_w > 0) 483 cdg_data->shadow_w = cdg_window_decrease(ccv, 484 cdg_data->shadow_w, RENO_BETA); 485 486 CCV(ccv, snd_ssthresh) = max(cdg_data->shadow_w, 487 cdg_window_decrease(ccv, CCV(ccv, snd_cwnd), 488 V_cdg_beta_loss)); 489 490 cdg_data->window_incr = cdg_data->rtt_count = 0; 491 } 492 ENTER_RECOVERY(CCV(ccv, t_flags)); 493 break; 494 default: 495 newreno_cc_cong_signal(ccv, signal_type); 496 break; 497 } 498 } 499 500 /* 501 * Using a negative exponential probabilistic backoff so that sources with 502 * varying RTTs which share the same link will, on average, have the same 503 * probability of backoff over time. 504 * 505 * Prob_backoff = 1 - exp(-qtrend / V_cdg_exp_backoff_scale), where 506 * V_cdg_exp_backoff_scale is the average qtrend for the exponential backoff. 507 */ 508 static inline int 509 prob_backoff(long qtrend) 510 { 511 int backoff, idx; 512 uint32_t p; 513 514 backoff = (qtrend > ((MAXGRAD * V_cdg_exp_backoff_scale) << D_P_E)); 515 516 if (!backoff) { 517 if (V_cdg_exp_backoff_scale > 1) 518 idx = (qtrend + V_cdg_exp_backoff_scale / 2) / 519 V_cdg_exp_backoff_scale; 520 else 521 idx = qtrend; 522 523 /* Backoff probability proportional to rate of queue growth. */ 524 p = (UINT32_MAX / (1 << EXP_PREC)) * probexp[idx]; 525 backoff = (prng32() < p); 526 } 527 528 return (backoff); 529 } 530 531 static inline void 532 calc_moving_average(struct cdg *cdg_data, long qdiff_max, long qdiff_min) 533 { 534 struct qdiff_sample *qds; 535 536 ++cdg_data->num_samples; 537 if (cdg_data->num_samples > cdg_data->sample_q_size) { 538 /* Minimum RTT. */ 539 qds = STAILQ_FIRST(&cdg_data->qdiffmin_q); 540 cdg_data->min_qtrend = cdg_data->min_qtrend + 541 (qdiff_min - qds->qdiff) / cdg_data->sample_q_size; 542 STAILQ_REMOVE_HEAD(&cdg_data->qdiffmin_q, qdiff_lnk); 543 qds->qdiff = qdiff_min; 544 STAILQ_INSERT_TAIL(&cdg_data->qdiffmin_q, qds, qdiff_lnk); 545 546 /* Maximum RTT. */ 547 qds = STAILQ_FIRST(&cdg_data->qdiffmax_q); 548 cdg_data->max_qtrend = cdg_data->max_qtrend + 549 (qdiff_max - qds->qdiff) / cdg_data->sample_q_size; 550 STAILQ_REMOVE_HEAD(&cdg_data->qdiffmax_q, qdiff_lnk); 551 qds->qdiff = qdiff_max; 552 STAILQ_INSERT_TAIL(&cdg_data->qdiffmax_q, qds, qdiff_lnk); 553 --cdg_data->num_samples; 554 } else { 555 qds = uma_zalloc(qdiffsample_zone, M_NOWAIT); 556 if (qds != NULL) { 557 cdg_data->min_qtrend = cdg_data->min_qtrend + 558 qdiff_min / cdg_data->sample_q_size; 559 qds->qdiff = qdiff_min; 560 STAILQ_INSERT_TAIL(&cdg_data->qdiffmin_q, qds, 561 qdiff_lnk); 562 } 563 564 qds = uma_zalloc(qdiffsample_zone, M_NOWAIT); 565 if (qds) { 566 cdg_data->max_qtrend = cdg_data->max_qtrend + 567 qdiff_max / cdg_data->sample_q_size; 568 qds->qdiff = qdiff_max; 569 STAILQ_INSERT_TAIL(&cdg_data->qdiffmax_q, qds, 570 qdiff_lnk); 571 } 572 } 573 } 574 575 static void 576 cdg_ack_received(struct cc_var *ccv, ccsignal_t ack_type) 577 { 578 struct cdg *cdg_data; 579 struct ertt *e_t; 580 long qdiff_max, qdiff_min; 581 int congestion, new_measurement, slowstart; 582 583 cdg_data = ccv->cc_data; 584 e_t = (struct ertt *)khelp_get_osd(&CCV(ccv, t_osd), ertt_id); 585 new_measurement = e_t->flags & ERTT_NEW_MEASUREMENT; 586 congestion = 0; 587 cdg_data->maxrtt_in_rtt = imax(e_t->rtt, cdg_data->maxrtt_in_rtt); 588 cdg_data->minrtt_in_rtt = imin(e_t->rtt, cdg_data->minrtt_in_rtt); 589 590 if (new_measurement) { 591 slowstart = (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh)); 592 /* 593 * Update smoothed gradient measurements. Since we are only 594 * using one measurement per RTT, use max or min rtt_in_rtt. 595 * This is also less noisy than a sample RTT measurement. Max 596 * RTT measurements can have trouble due to OS issues. 597 */ 598 if (cdg_data->maxrtt_in_prevrtt) { 599 qdiff_max = ((long)(cdg_data->maxrtt_in_rtt - 600 cdg_data->maxrtt_in_prevrtt) << D_P_E ); 601 qdiff_min = ((long)(cdg_data->minrtt_in_rtt - 602 cdg_data->minrtt_in_prevrtt) << D_P_E ); 603 604 if (cdg_data->sample_q_size == 0) { 605 cdg_data->max_qtrend = qdiff_max; 606 cdg_data->min_qtrend = qdiff_min; 607 } else 608 calc_moving_average(cdg_data, qdiff_max, qdiff_min); 609 610 /* Probabilistic backoff with respect to gradient. */ 611 if (slowstart && qdiff_min > 0) 612 congestion = prob_backoff(qdiff_min); 613 else if (cdg_data->min_qtrend > 0) 614 congestion = prob_backoff(cdg_data->min_qtrend); 615 else if (slowstart && qdiff_max > 0) 616 congestion = prob_backoff(qdiff_max); 617 else if (cdg_data->max_qtrend > 0) 618 congestion = prob_backoff(cdg_data->max_qtrend); 619 620 /* Update estimate of queue state. */ 621 if (cdg_data->min_qtrend > 0 && 622 cdg_data->max_qtrend <= 0) { 623 cdg_data->queue_state = CDG_Q_FULL; 624 } else if (cdg_data->min_qtrend >= 0 && 625 cdg_data->max_qtrend < 0) { 626 cdg_data->queue_state = CDG_Q_EMPTY; 627 cdg_data->shadow_w = 0; 628 } else if (cdg_data->min_qtrend > 0 && 629 cdg_data->max_qtrend > 0) { 630 cdg_data->queue_state = CDG_Q_RISING; 631 } else if (cdg_data->min_qtrend < 0 && 632 cdg_data->max_qtrend < 0) { 633 cdg_data->queue_state = CDG_Q_FALLING; 634 } 635 636 if (cdg_data->min_qtrend < 0 || 637 cdg_data->max_qtrend < 0) 638 cdg_data->consec_cong_cnt = 0; 639 } 640 641 cdg_data->minrtt_in_prevrtt = cdg_data->minrtt_in_rtt; 642 cdg_data->minrtt_in_rtt = INT_MAX; 643 cdg_data->maxrtt_in_prevrtt = cdg_data->maxrtt_in_rtt; 644 cdg_data->maxrtt_in_rtt = 0; 645 e_t->flags &= ~ERTT_NEW_MEASUREMENT; 646 } 647 648 if (congestion) { 649 cdg_data->consec_cong_cnt++; 650 if (!IN_RECOVERY(CCV(ccv, t_flags))) { 651 if (cdg_data->consec_cong_cnt <= V_cdg_consec_cong) 652 cdg_cong_signal(ccv, CC_CDG_DELAY); 653 else 654 /* 655 * We have been backing off but the queue is not 656 * falling. Assume we are competing with 657 * loss-based flows and don't back off for the 658 * next V_cdg_hold_backoff RTT periods. 659 */ 660 if (cdg_data->consec_cong_cnt >= 661 V_cdg_consec_cong + V_cdg_hold_backoff) 662 cdg_data->consec_cong_cnt = 0; 663 664 /* Won't see effect until 2nd RTT. */ 665 cdg_data->maxrtt_in_prevrtt = 0; 666 /* 667 * Resync shadow window in case we are competing with a 668 * loss based flow 669 */ 670 cdg_data->shadow_w = ulmax(CCV(ccv, snd_cwnd), 671 cdg_data->shadow_w); 672 } 673 } else if (ack_type == CC_ACK) 674 cdg_window_increase(ccv, new_measurement); 675 } 676 677 /* When a vnet is created and being initialised, init the per-stack CDG vars. */ 678 VNET_SYSINIT(cdg_init_vnet, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 679 cdg_init_vnet, NULL); 680 681 SYSCTL_DECL(_net_inet_tcp_cc_cdg); 682 SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, cdg, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 683 "CAIA delay-gradient congestion control related settings"); 684 685 SYSCTL_STRING(_net_inet_tcp_cc_cdg, OID_AUTO, version, 686 CTLFLAG_RD, CDG_VERSION, sizeof(CDG_VERSION) - 1, 687 "Current algorithm/implementation version number"); 688 689 SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, alpha_inc, 690 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_alpha_inc), 0, 691 "Increment the window increase factor alpha by 1 MSS segment every " 692 "alpha_inc RTTs during congestion avoidance mode."); 693 694 SYSCTL_PROC(_net_inet_tcp_cc_cdg, OID_AUTO, beta_delay, 695 CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 696 &VNET_NAME(cdg_beta_delay), 70, &cdg_beta_handler, "IU", 697 "Delay-based window decrease factor as a percentage " 698 "(on delay-based backoff, w = w * beta_delay / 100)"); 699 700 SYSCTL_PROC(_net_inet_tcp_cc_cdg, OID_AUTO, beta_loss, 701 CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 702 &VNET_NAME(cdg_beta_loss), 50, &cdg_beta_handler, "IU", 703 "Loss-based window decrease factor as a percentage " 704 "(on loss-based backoff, w = w * beta_loss / 100)"); 705 706 SYSCTL_PROC(_net_inet_tcp_cc_cdg, OID_AUTO, exp_backoff_scale, 707 CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 708 &VNET_NAME(cdg_exp_backoff_scale), 2, &cdg_exp_backoff_scale_handler, "IU", 709 "Scaling parameter for the probabilistic exponential backoff"); 710 711 SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, smoothing_factor, 712 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_smoothing_factor), 8, 713 "Number of samples used for moving average smoothing (0 = no smoothing)"); 714 715 SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, loss_compete_consec_cong, 716 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_consec_cong), 5, 717 "Number of consecutive delay-gradient based congestion episodes which will " 718 "trigger loss based CC compatibility"); 719 720 SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, loss_compete_hold_backoff, 721 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_hold_backoff), 5, 722 "Number of consecutive delay-gradient based congestion episodes to hold " 723 "the window backoff for loss based CC compatibility"); 724 725 DECLARE_CC_MODULE(cdg, &cdg_cc_algo); 726 MODULE_VERSION(cdg, 2); 727 MODULE_DEPEND(cdg, ertt, 1, 1, 1); 728