xref: /freebsd-src/sys/netinet/cc/cc_cdg.c (revision 22dcc81293854c4d39df639a329fecded175b2b0)
192a0637fSLawrence Stewart /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
492a0637fSLawrence Stewart  * Copyright (c) 2009-2013
592a0637fSLawrence Stewart  * 	Swinburne University of Technology, Melbourne, Australia
692a0637fSLawrence Stewart  * All rights reserved.
792a0637fSLawrence Stewart  *
892a0637fSLawrence Stewart  * This software was developed at the Centre for Advanced Internet
992a0637fSLawrence Stewart  * Architectures, Swinburne University of Technology, by David Hayes, made
1092a0637fSLawrence Stewart  * possible in part by a gift from The Cisco University Research Program Fund,
1192a0637fSLawrence Stewart  * a corporate advised fund of Silicon Valley Community Foundation. Development
1292a0637fSLawrence Stewart  * and testing were further assisted by a grant from the FreeBSD Foundation.
1392a0637fSLawrence Stewart  *
1492a0637fSLawrence Stewart  * Redistribution and use in source and binary forms, with or without
1592a0637fSLawrence Stewart  * modification, are permitted provided that the following conditions
1692a0637fSLawrence Stewart  * are met:
1792a0637fSLawrence Stewart  * 1. Redistributions of source code must retain the above copyright
1892a0637fSLawrence Stewart  *    notice, this list of conditions and the following disclaimer.
1992a0637fSLawrence Stewart  * 2. Redistributions in binary form must reproduce the above copyright
2092a0637fSLawrence Stewart  *    notice, this list of conditions and the following disclaimer in the
2192a0637fSLawrence Stewart  *    documentation and/or other materials provided with the distribution.
2292a0637fSLawrence Stewart  *
2392a0637fSLawrence Stewart  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2492a0637fSLawrence Stewart  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2592a0637fSLawrence Stewart  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2692a0637fSLawrence Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2792a0637fSLawrence Stewart  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2892a0637fSLawrence Stewart  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2992a0637fSLawrence Stewart  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3092a0637fSLawrence Stewart  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3192a0637fSLawrence Stewart  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3292a0637fSLawrence Stewart  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3392a0637fSLawrence Stewart  * SUCH DAMAGE.
3492a0637fSLawrence Stewart  */
3592a0637fSLawrence Stewart 
3692a0637fSLawrence Stewart /*
3792a0637fSLawrence Stewart  * CAIA Delay-Gradient (CDG) congestion control algorithm
3892a0637fSLawrence Stewart  *
3992a0637fSLawrence Stewart  * An implemention of the delay-gradient congestion control algorithm proposed
4092a0637fSLawrence Stewart  * in the following paper:
4192a0637fSLawrence Stewart  *
4292a0637fSLawrence Stewart  * D. A. Hayes and G. Armitage, "Revisiting TCP Congestion Control using Delay
4392a0637fSLawrence Stewart  * Gradients", in IFIP Networking, Valencia, Spain, 9-13 May 2011.
4492a0637fSLawrence Stewart  *
4592a0637fSLawrence Stewart  * Developed as part of the NewTCP research project at Swinburne University of
4692a0637fSLawrence Stewart  * Technology's Centre for Advanced Internet Architectures, Melbourne,
4792a0637fSLawrence Stewart  * Australia. More details are available at:
4892a0637fSLawrence Stewart  *   http://caia.swin.edu.au/urp/newtcp/
4992a0637fSLawrence Stewart  */
5092a0637fSLawrence Stewart 
5192a0637fSLawrence Stewart #include <sys/param.h>
5292a0637fSLawrence Stewart #include <sys/hhook.h>
5392a0637fSLawrence Stewart #include <sys/kernel.h>
5492a0637fSLawrence Stewart #include <sys/khelp.h>
5592a0637fSLawrence Stewart #include <sys/limits.h>
5692a0637fSLawrence Stewart #include <sys/lock.h>
5792a0637fSLawrence Stewart #include <sys/malloc.h>
5892a0637fSLawrence Stewart #include <sys/module.h>
5992a0637fSLawrence Stewart #include <sys/queue.h>
60674956e1SHenrich Hartzer #include <sys/prng.h>
6192a0637fSLawrence Stewart #include <sys/socket.h>
6292a0637fSLawrence Stewart #include <sys/socketvar.h>
6392a0637fSLawrence Stewart #include <sys/sysctl.h>
6492a0637fSLawrence Stewart #include <sys/systm.h>
6592a0637fSLawrence Stewart 
6692a0637fSLawrence Stewart #include <net/vnet.h>
6792a0637fSLawrence Stewart 
68b8d60729SRandall Stewart #include <net/route.h>
69b8d60729SRandall Stewart #include <net/route/nhop.h>
70b8d60729SRandall Stewart 
71b8d60729SRandall Stewart #include <netinet/in_pcb.h>
722de3e790SGleb Smirnoff #include <netinet/tcp.h>
7392a0637fSLawrence Stewart #include <netinet/tcp_seq.h>
7492a0637fSLawrence Stewart #include <netinet/tcp_timer.h>
7592a0637fSLawrence Stewart #include <netinet/tcp_var.h>
764644fda3SGleb Smirnoff #include <netinet/cc/cc.h>
7792a0637fSLawrence Stewart #include <netinet/cc/cc_module.h>
7892a0637fSLawrence Stewart 
7992a0637fSLawrence Stewart #include <netinet/khelp/h_ertt.h>
8092a0637fSLawrence Stewart 
8192a0637fSLawrence Stewart #include <vm/uma.h>
8292a0637fSLawrence Stewart 
8392a0637fSLawrence Stewart #define	CDG_VERSION "0.1"
8492a0637fSLawrence Stewart 
8592a0637fSLawrence Stewart /* Private delay-gradient induced congestion control signal. */
8692a0637fSLawrence Stewart #define	CC_CDG_DELAY 0x01000000
8792a0637fSLawrence Stewart 
8892a0637fSLawrence Stewart /* NewReno window deflation factor on loss (as a percentage). */
8992a0637fSLawrence Stewart #define	RENO_BETA 50
9092a0637fSLawrence Stewart 
9192a0637fSLawrence Stewart /* Queue states. */
9292a0637fSLawrence Stewart #define	CDG_Q_EMPTY	1
9392a0637fSLawrence Stewart #define	CDG_Q_RISING	2
9492a0637fSLawrence Stewart #define	CDG_Q_FALLING	3
9592a0637fSLawrence Stewart #define	CDG_Q_FULL	4
9692a0637fSLawrence Stewart #define	CDG_Q_UNKNOWN	9999
9792a0637fSLawrence Stewart 
9892a0637fSLawrence Stewart /* Number of bit shifts used in probexp lookup table. */
9992a0637fSLawrence Stewart #define	EXP_PREC 15
10092a0637fSLawrence Stewart 
10192a0637fSLawrence Stewart /* Largest gradient represented in probexp lookup table. */
10292a0637fSLawrence Stewart #define	MAXGRAD 5
10392a0637fSLawrence Stewart 
10492a0637fSLawrence Stewart /*
10592a0637fSLawrence Stewart  * Delay Precision Enhance - number of bit shifts used for qtrend related
10692a0637fSLawrence Stewart  * integer arithmetic precision.
10792a0637fSLawrence Stewart  */
10892a0637fSLawrence Stewart #define	D_P_E 7
10992a0637fSLawrence Stewart 
11092a0637fSLawrence Stewart struct qdiff_sample {
11192a0637fSLawrence Stewart 	long qdiff;
11292a0637fSLawrence Stewart 	STAILQ_ENTRY(qdiff_sample) qdiff_lnk;
11392a0637fSLawrence Stewart };
11492a0637fSLawrence Stewart 
11592a0637fSLawrence Stewart struct cdg {
11692a0637fSLawrence Stewart 	long max_qtrend;
11792a0637fSLawrence Stewart 	long min_qtrend;
11892a0637fSLawrence Stewart 	STAILQ_HEAD(minrtts_head, qdiff_sample) qdiffmin_q;
11992a0637fSLawrence Stewart 	STAILQ_HEAD(maxrtts_head, qdiff_sample) qdiffmax_q;
12092a0637fSLawrence Stewart 	long window_incr;
12192a0637fSLawrence Stewart 	/* rttcount for window increase when in congestion avoidance */
12292a0637fSLawrence Stewart 	long rtt_count;
12392a0637fSLawrence Stewart 	/* maximum measured rtt within an rtt period */
12492a0637fSLawrence Stewart 	int maxrtt_in_rtt;
12592a0637fSLawrence Stewart 	/* maximum measured rtt within prev rtt period */
12692a0637fSLawrence Stewart 	int maxrtt_in_prevrtt;
12792a0637fSLawrence Stewart 	/* minimum measured rtt within an rtt period */
12892a0637fSLawrence Stewart 	int minrtt_in_rtt;
12992a0637fSLawrence Stewart 	/* minimum measured rtt within prev rtt period */
13092a0637fSLawrence Stewart 	int minrtt_in_prevrtt;
13192a0637fSLawrence Stewart 	/* consecutive congestion episode counter */
13292a0637fSLawrence Stewart 	uint32_t consec_cong_cnt;
13392a0637fSLawrence Stewart 	/* when tracking a new reno type loss window */
13492a0637fSLawrence Stewart 	uint32_t shadow_w;
13592a0637fSLawrence Stewart 	/* maximum number of samples in the moving average queue */
13692a0637fSLawrence Stewart 	int sample_q_size;
13792a0637fSLawrence Stewart 	/* number of samples in the moving average queue */
13892a0637fSLawrence Stewart 	int num_samples;
13992a0637fSLawrence Stewart 	/* estimate of the queue state of the path */
14092a0637fSLawrence Stewart 	int queue_state;
14192a0637fSLawrence Stewart };
14292a0637fSLawrence Stewart 
14392a0637fSLawrence Stewart /*
14492a0637fSLawrence Stewart  * Lookup table for:
14592a0637fSLawrence Stewart  *   (1 - exp(-x)) << EXP_PREC, where x = [0,MAXGRAD] in 2^-7 increments
14692a0637fSLawrence Stewart  *
14792a0637fSLawrence Stewart  * Note: probexp[0] is set to 10 (not 0) as a safety for very low increase
14892a0637fSLawrence Stewart  * gradients.
14992a0637fSLawrence Stewart  */
15092a0637fSLawrence Stewart static const int probexp[641] = {
15192a0637fSLawrence Stewart    10,255,508,759,1008,1255,1501,1744,1985,2225,2463,2698,2932,3165,3395,3624,
15292a0637fSLawrence Stewart    3850,4075,4299,4520,4740,4958,5175,5389,5602,5814,6024,6232,6438,6643,6846,
15392a0637fSLawrence Stewart    7048,7248,7447,7644,7839,8033,8226,8417,8606,8794,8981,9166,9350,9532,9713,
15492a0637fSLawrence Stewart    9892,10070,10247,10422,10596,10769,10940,11110,11278,11445,11611,11776,11939,
15592a0637fSLawrence Stewart    12101,12262,12422,12580,12737,12893,13048,13201,13354,13505,13655,13803,13951,
15692a0637fSLawrence Stewart    14097,14243,14387,14530,14672,14813,14952,15091,15229,15365,15500,15635,15768,
15792a0637fSLawrence Stewart    15900,16032,16162,16291,16419,16547,16673,16798,16922,17046,17168,17289,17410,
15892a0637fSLawrence Stewart    17529,17648,17766,17882,17998,18113,18227,18340,18453,18564,18675,18784,18893,
15992a0637fSLawrence Stewart    19001,19108,19215,19320,19425,19529,19632,19734,19835,19936,20036,20135,20233,
16092a0637fSLawrence Stewart    20331,20427,20523,20619,20713,20807,20900,20993,21084,21175,21265,21355,21444,
16192a0637fSLawrence Stewart    21532,21619,21706,21792,21878,21962,22046,22130,22213,22295,22376,22457,22537,
16292a0637fSLawrence Stewart    22617,22696,22774,22852,22929,23006,23082,23157,23232,23306,23380,23453,23525,
16392a0637fSLawrence Stewart    23597,23669,23739,23810,23879,23949,24017,24085,24153,24220,24286,24352,24418,
16492a0637fSLawrence Stewart    24483,24547,24611,24675,24738,24800,24862,24924,24985,25045,25106,25165,25224,
16592a0637fSLawrence Stewart    25283,25341,25399,25456,25513,25570,25626,25681,25737,25791,25846,25899,25953,
16692a0637fSLawrence Stewart    26006,26059,26111,26163,26214,26265,26316,26366,26416,26465,26514,26563,26611,
16792a0637fSLawrence Stewart    26659,26707,26754,26801,26847,26893,26939,26984,27029,27074,27118,27162,27206,
16892a0637fSLawrence Stewart    27249,27292,27335,27377,27419,27460,27502,27543,27583,27624,27664,27703,27743,
16992a0637fSLawrence Stewart    27782,27821,27859,27897,27935,27973,28010,28047,28084,28121,28157,28193,28228,
17092a0637fSLawrence Stewart    28263,28299,28333,28368,28402,28436,28470,28503,28536,28569,28602,28634,28667,
17192a0637fSLawrence Stewart    28699,28730,28762,28793,28824,28854,28885,28915,28945,28975,29004,29034,29063,
17292a0637fSLawrence Stewart    29092,29120,29149,29177,29205,29232,29260,29287,29314,29341,29368,29394,29421,
17392a0637fSLawrence Stewart    29447,29472,29498,29524,29549,29574,29599,29623,29648,29672,29696,29720,29744,
17492a0637fSLawrence Stewart    29767,29791,29814,29837,29860,29882,29905,29927,29949,29971,29993,30014,30036,
17592a0637fSLawrence Stewart    30057,30078,30099,30120,30141,30161,30181,30201,30221,30241,30261,30280,30300,
17692a0637fSLawrence Stewart    30319,30338,30357,30376,30394,30413,30431,30449,30467,30485,30503,30521,30538,
17792a0637fSLawrence Stewart    30555,30573,30590,30607,30624,30640,30657,30673,30690,30706,30722,30738,30753,
17892a0637fSLawrence Stewart    30769,30785,30800,30815,30831,30846,30861,30876,30890,30905,30919,30934,30948,
17992a0637fSLawrence Stewart    30962,30976,30990,31004,31018,31031,31045,31058,31072,31085,31098,31111,31124,
18092a0637fSLawrence Stewart    31137,31149,31162,31174,31187,31199,31211,31223,31235,31247,31259,31271,31283,
18192a0637fSLawrence Stewart    31294,31306,31317,31328,31339,31351,31362,31373,31383,31394,31405,31416,31426,
18292a0637fSLawrence Stewart    31436,31447,31457,31467,31477,31487,31497,31507,31517,31527,31537,31546,31556,
18392a0637fSLawrence Stewart    31565,31574,31584,31593,31602,31611,31620,31629,31638,31647,31655,31664,31673,
18492a0637fSLawrence Stewart    31681,31690,31698,31706,31715,31723,31731,31739,31747,31755,31763,31771,31778,
18592a0637fSLawrence Stewart    31786,31794,31801,31809,31816,31824,31831,31838,31846,31853,31860,31867,31874,
18692a0637fSLawrence Stewart    31881,31888,31895,31902,31908,31915,31922,31928,31935,31941,31948,31954,31960,
18792a0637fSLawrence Stewart    31967,31973,31979,31985,31991,31997,32003,32009,32015,32021,32027,32033,32038,
18892a0637fSLawrence Stewart    32044,32050,32055,32061,32066,32072,32077,32083,32088,32093,32098,32104,32109,
18992a0637fSLawrence Stewart    32114,32119,32124,32129,32134,32139,32144,32149,32154,32158,32163,32168,32173,
19092a0637fSLawrence Stewart    32177,32182,32186,32191,32195,32200,32204,32209,32213,32217,32222,32226,32230,
19192a0637fSLawrence Stewart    32234,32238,32242,32247,32251,32255,32259,32263,32267,32270,32274,32278,32282,
19292a0637fSLawrence Stewart    32286,32290,32293,32297,32301,32304,32308,32311,32315,32318,32322,32325,32329,
19392a0637fSLawrence Stewart    32332,32336,32339,32342,32346,32349,32352,32356,32359,32362,32365,32368,32371,
19492a0637fSLawrence Stewart    32374,32377,32381,32384,32387,32389,32392,32395,32398,32401,32404,32407,32410,
19592a0637fSLawrence Stewart    32412,32415,32418,32421,32423,32426,32429,32431,32434,32437,32439,32442,32444,
19692a0637fSLawrence Stewart    32447,32449,32452,32454,32457,32459,32461,32464,32466,32469,32471,32473,32476,
19792a0637fSLawrence Stewart    32478,32480,32482,32485,32487,32489,32491,32493,32495,32497,32500,32502,32504,
19892a0637fSLawrence Stewart    32506,32508,32510,32512,32514,32516,32518,32520,32522,32524,32526,32527,32529,
19992a0637fSLawrence Stewart    32531,32533,32535,32537,32538,32540,32542,32544,32545,32547};
20092a0637fSLawrence Stewart 
20192a0637fSLawrence Stewart static uma_zone_t qdiffsample_zone;
20292a0637fSLawrence Stewart static int ertt_id;
20392a0637fSLawrence Stewart 
2045f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_alpha_inc);
2055f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_beta_delay);
2065f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_beta_loss);
2075f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_smoothing_factor);
2085f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_exp_backoff_scale);
2095f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_consec_cong);
2105f901c92SAndrew Turner VNET_DEFINE_STATIC(uint32_t, cdg_hold_backoff);
21192a0637fSLawrence Stewart #define	V_cdg_alpha_inc		VNET(cdg_alpha_inc)
21292a0637fSLawrence Stewart #define	V_cdg_beta_delay	VNET(cdg_beta_delay)
21392a0637fSLawrence Stewart #define	V_cdg_beta_loss		VNET(cdg_beta_loss)
21492a0637fSLawrence Stewart #define	V_cdg_smoothing_factor	VNET(cdg_smoothing_factor)
21592a0637fSLawrence Stewart #define	V_cdg_exp_backoff_scale	VNET(cdg_exp_backoff_scale)
21692a0637fSLawrence Stewart #define	V_cdg_consec_cong	VNET(cdg_consec_cong)
21792a0637fSLawrence Stewart #define	V_cdg_hold_backoff	VNET(cdg_hold_backoff)
21892a0637fSLawrence Stewart 
21992a0637fSLawrence Stewart /* Function prototypes. */
22092a0637fSLawrence Stewart static int cdg_mod_init(void);
2218b0fe327SLawrence Stewart static int cdg_mod_destroy(void);
22292a0637fSLawrence Stewart static void cdg_conn_init(struct cc_var *ccv);
223b8d60729SRandall Stewart static int cdg_cb_init(struct cc_var *ccv, void *ptr);
22492a0637fSLawrence Stewart static void cdg_cb_destroy(struct cc_var *ccv);
225f74352fbSRichard Scheffenegger static void cdg_cong_signal(struct cc_var *ccv, ccsignal_t signal_type);
226f74352fbSRichard Scheffenegger static void cdg_ack_received(struct cc_var *ccv, ccsignal_t ack_type);
227b8d60729SRandall Stewart static size_t cdg_data_sz(void);
22892a0637fSLawrence Stewart 
22992a0637fSLawrence Stewart struct cc_algo cdg_cc_algo = {
23092a0637fSLawrence Stewart 	.name = "cdg",
23192a0637fSLawrence Stewart 	.mod_init = cdg_mod_init,
23292a0637fSLawrence Stewart 	.ack_received = cdg_ack_received,
23392a0637fSLawrence Stewart 	.cb_destroy = cdg_cb_destroy,
23492a0637fSLawrence Stewart 	.cb_init = cdg_cb_init,
23592a0637fSLawrence Stewart 	.conn_init = cdg_conn_init,
2368b0fe327SLawrence Stewart 	.cong_signal = cdg_cong_signal,
237b8d60729SRandall Stewart 	.mod_destroy = cdg_mod_destroy,
238b8d60729SRandall Stewart 	.cc_data_sz = cdg_data_sz,
239b8d60729SRandall Stewart 	.post_recovery = newreno_cc_post_recovery,
240b8d60729SRandall Stewart 	.after_idle = newreno_cc_after_idle,
24192a0637fSLawrence Stewart };
24292a0637fSLawrence Stewart 
24392a0637fSLawrence Stewart /* Vnet created and being initialised. */
24492a0637fSLawrence Stewart static void
24592a0637fSLawrence Stewart cdg_init_vnet(const void *unused __unused)
24692a0637fSLawrence Stewart {
24792a0637fSLawrence Stewart 
24892a0637fSLawrence Stewart 	V_cdg_alpha_inc = 0;
24992a0637fSLawrence Stewart 	V_cdg_beta_delay = 70;
25092a0637fSLawrence Stewart 	V_cdg_beta_loss = 50;
25192a0637fSLawrence Stewart 	V_cdg_smoothing_factor = 8;
25292a0637fSLawrence Stewart 	V_cdg_exp_backoff_scale = 3;
25392a0637fSLawrence Stewart 	V_cdg_consec_cong = 5;
25492a0637fSLawrence Stewart 	V_cdg_hold_backoff = 5;
25592a0637fSLawrence Stewart }
25692a0637fSLawrence Stewart 
25792a0637fSLawrence Stewart static int
25892a0637fSLawrence Stewart cdg_mod_init(void)
25992a0637fSLawrence Stewart {
26092a0637fSLawrence Stewart 	VNET_ITERATOR_DECL(v);
26192a0637fSLawrence Stewart 
26292a0637fSLawrence Stewart 	ertt_id = khelp_get_id("ertt");
26392a0637fSLawrence Stewart 	if (ertt_id <= 0)
26492a0637fSLawrence Stewart 		return (EINVAL);
26592a0637fSLawrence Stewart 
26692a0637fSLawrence Stewart 	qdiffsample_zone = uma_zcreate("cdg_qdiffsample",
26792a0637fSLawrence Stewart 	    sizeof(struct qdiff_sample), NULL, NULL, NULL, NULL, 0, 0);
26892a0637fSLawrence Stewart 
26992a0637fSLawrence Stewart 	VNET_LIST_RLOCK();
27092a0637fSLawrence Stewart 	VNET_FOREACH(v) {
27192a0637fSLawrence Stewart 		CURVNET_SET(v);
27292a0637fSLawrence Stewart 		cdg_init_vnet(NULL);
27392a0637fSLawrence Stewart 		CURVNET_RESTORE();
27492a0637fSLawrence Stewart 	}
27592a0637fSLawrence Stewart 	VNET_LIST_RUNLOCK();
27692a0637fSLawrence Stewart 	return (0);
27792a0637fSLawrence Stewart }
27892a0637fSLawrence Stewart 
27992a0637fSLawrence Stewart static int
2808b0fe327SLawrence Stewart cdg_mod_destroy(void)
2818b0fe327SLawrence Stewart {
2828b0fe327SLawrence Stewart 
2838b0fe327SLawrence Stewart 	uma_zdestroy(qdiffsample_zone);
2848b0fe327SLawrence Stewart 	return (0);
2858b0fe327SLawrence Stewart }
2868b0fe327SLawrence Stewart 
287b8d60729SRandall Stewart static size_t
288b8d60729SRandall Stewart cdg_data_sz(void)
289b8d60729SRandall Stewart {
290b8d60729SRandall Stewart 	return (sizeof(struct cdg));
291b8d60729SRandall Stewart }
292b8d60729SRandall Stewart 
2938b0fe327SLawrence Stewart static int
294b8d60729SRandall Stewart cdg_cb_init(struct cc_var *ccv, void *ptr)
29592a0637fSLawrence Stewart {
29692a0637fSLawrence Stewart 	struct cdg *cdg_data;
29792a0637fSLawrence Stewart 
29800d3b744SMichael Tuexen 	INP_WLOCK_ASSERT(tptoinpcb(ccv->tp));
299b8d60729SRandall Stewart 	if (ptr == NULL) {
300b8d60729SRandall Stewart 		cdg_data = malloc(sizeof(struct cdg), M_CC_MEM, M_NOWAIT);
30192a0637fSLawrence Stewart 		if (cdg_data == NULL)
30292a0637fSLawrence Stewart 			return (ENOMEM);
303b8d60729SRandall Stewart 	} else {
304b8d60729SRandall Stewart 		cdg_data = ptr;
305b8d60729SRandall Stewart 	}
30692a0637fSLawrence Stewart 	cdg_data->shadow_w = 0;
30792a0637fSLawrence Stewart 	cdg_data->max_qtrend = 0;
30892a0637fSLawrence Stewart 	cdg_data->min_qtrend = 0;
30992a0637fSLawrence Stewart 	cdg_data->queue_state = CDG_Q_UNKNOWN;
31092a0637fSLawrence Stewart 	cdg_data->maxrtt_in_rtt = 0;
31192a0637fSLawrence Stewart 	cdg_data->maxrtt_in_prevrtt = 0;
31292a0637fSLawrence Stewart 	cdg_data->minrtt_in_rtt = INT_MAX;
31392a0637fSLawrence Stewart 	cdg_data->minrtt_in_prevrtt = 0;
31492a0637fSLawrence Stewart 	cdg_data->window_incr = 0;
31592a0637fSLawrence Stewart 	cdg_data->rtt_count = 0;
31692a0637fSLawrence Stewart 	cdg_data->consec_cong_cnt = 0;
31792a0637fSLawrence Stewart 	cdg_data->sample_q_size = V_cdg_smoothing_factor;
31892a0637fSLawrence Stewart 	cdg_data->num_samples = 0;
31992a0637fSLawrence Stewart 	STAILQ_INIT(&cdg_data->qdiffmin_q);
32092a0637fSLawrence Stewart 	STAILQ_INIT(&cdg_data->qdiffmax_q);
32192a0637fSLawrence Stewart 
32292a0637fSLawrence Stewart 	ccv->cc_data = cdg_data;
32392a0637fSLawrence Stewart 
32492a0637fSLawrence Stewart 	return (0);
32592a0637fSLawrence Stewart }
32692a0637fSLawrence Stewart 
32792a0637fSLawrence Stewart static void
32892a0637fSLawrence Stewart cdg_conn_init(struct cc_var *ccv)
32992a0637fSLawrence Stewart {
33092a0637fSLawrence Stewart 	struct cdg *cdg_data = ccv->cc_data;
33192a0637fSLawrence Stewart 
33292a0637fSLawrence Stewart 	/*
33392a0637fSLawrence Stewart 	 * Initialise the shadow_cwnd in case we are competing with loss based
33492a0637fSLawrence Stewart 	 * flows from the start
33592a0637fSLawrence Stewart 	 */
33692a0637fSLawrence Stewart 	cdg_data->shadow_w = CCV(ccv, snd_cwnd);
33792a0637fSLawrence Stewart }
33892a0637fSLawrence Stewart 
33992a0637fSLawrence Stewart static void
34092a0637fSLawrence Stewart cdg_cb_destroy(struct cc_var *ccv)
34192a0637fSLawrence Stewart {
34292a0637fSLawrence Stewart 	struct cdg *cdg_data;
34392a0637fSLawrence Stewart 	struct qdiff_sample *qds, *qds_n;
34492a0637fSLawrence Stewart 
34592a0637fSLawrence Stewart 	cdg_data = ccv->cc_data;
34692a0637fSLawrence Stewart 
34792a0637fSLawrence Stewart 	qds = STAILQ_FIRST(&cdg_data->qdiffmin_q);
34892a0637fSLawrence Stewart 	while (qds != NULL) {
34992a0637fSLawrence Stewart 		qds_n = STAILQ_NEXT(qds, qdiff_lnk);
35092a0637fSLawrence Stewart 		uma_zfree(qdiffsample_zone,qds);
35192a0637fSLawrence Stewart 		qds = qds_n;
35292a0637fSLawrence Stewart 	}
35392a0637fSLawrence Stewart 
35492a0637fSLawrence Stewart 	qds = STAILQ_FIRST(&cdg_data->qdiffmax_q);
35592a0637fSLawrence Stewart 	while (qds != NULL) {
35692a0637fSLawrence Stewart 		qds_n = STAILQ_NEXT(qds, qdiff_lnk);
35792a0637fSLawrence Stewart 		uma_zfree(qdiffsample_zone,qds);
35892a0637fSLawrence Stewart 		qds = qds_n;
35992a0637fSLawrence Stewart 	}
36092a0637fSLawrence Stewart 
361b8d60729SRandall Stewart 	free(ccv->cc_data, M_CC_MEM);
36292a0637fSLawrence Stewart }
36392a0637fSLawrence Stewart 
36492a0637fSLawrence Stewart static int
36592a0637fSLawrence Stewart cdg_beta_handler(SYSCTL_HANDLER_ARGS)
36692a0637fSLawrence Stewart {
367855acb84SBrooks Davis 	int error;
368855acb84SBrooks Davis 	uint32_t new;
36992a0637fSLawrence Stewart 
370855acb84SBrooks Davis 	new = *(uint32_t *)arg1;
371855acb84SBrooks Davis 	error = sysctl_handle_int(oidp, &new, 0, req);
372855acb84SBrooks Davis 	if (error == 0 && req->newptr != NULL) {
373855acb84SBrooks Davis 		if (new == 0 || new > 100)
374855acb84SBrooks Davis 			error = EINVAL;
375855acb84SBrooks Davis 		else
376855acb84SBrooks Davis 			*(uint32_t *)arg1 = new;
377855acb84SBrooks Davis 	}
37892a0637fSLawrence Stewart 
379855acb84SBrooks Davis 	return (error);
38092a0637fSLawrence Stewart }
38192a0637fSLawrence Stewart 
38292a0637fSLawrence Stewart static int
38392a0637fSLawrence Stewart cdg_exp_backoff_scale_handler(SYSCTL_HANDLER_ARGS)
38492a0637fSLawrence Stewart {
385855acb84SBrooks Davis 	int error;
386855acb84SBrooks Davis 	uint32_t new;
38792a0637fSLawrence Stewart 
388855acb84SBrooks Davis 	new = *(uint32_t *)arg1;
389855acb84SBrooks Davis 	error = sysctl_handle_int(oidp, &new, 0, req);
390855acb84SBrooks Davis 	if (error == 0 && req->newptr != NULL) {
391855acb84SBrooks Davis 		if (new < 1)
392855acb84SBrooks Davis 			error = EINVAL;
393855acb84SBrooks Davis 		else
394855acb84SBrooks Davis 			*(uint32_t *)arg1 = new;
395855acb84SBrooks Davis 	}
39692a0637fSLawrence Stewart 
397855acb84SBrooks Davis 	return (error);
39892a0637fSLawrence Stewart }
39992a0637fSLawrence Stewart 
4003ac12506SJonathan T. Looney static inline uint32_t
40192a0637fSLawrence Stewart cdg_window_decrease(struct cc_var *ccv, unsigned long owin, unsigned int beta)
40292a0637fSLawrence Stewart {
40392a0637fSLawrence Stewart 
40492a0637fSLawrence Stewart 	return ((ulmin(CCV(ccv, snd_wnd), owin) * beta) / 100);
40592a0637fSLawrence Stewart }
40692a0637fSLawrence Stewart 
40792a0637fSLawrence Stewart /*
40892a0637fSLawrence Stewart  * Window increase function
40992a0637fSLawrence Stewart  * This window increase function is independent of the initial window size
41092a0637fSLawrence Stewart  * to ensure small window flows are not discriminated against (i.e. fairness).
41192a0637fSLawrence Stewart  * It increases at 1pkt/rtt like Reno for alpha_inc rtts, and then 2pkts/rtt for
41292a0637fSLawrence Stewart  * the next alpha_inc rtts, etc.
41392a0637fSLawrence Stewart  */
41492a0637fSLawrence Stewart static void
41592a0637fSLawrence Stewart cdg_window_increase(struct cc_var *ccv, int new_measurement)
41692a0637fSLawrence Stewart {
41792a0637fSLawrence Stewart 	struct cdg *cdg_data;
41892a0637fSLawrence Stewart 	int incr, s_w_incr;
419*22dcc812SRichard Scheffenegger 	uint32_t mss = tcp_fixed_maxseg(ccv->tp);
42092a0637fSLawrence Stewart 
42192a0637fSLawrence Stewart 	cdg_data = ccv->cc_data;
42292a0637fSLawrence Stewart 	incr = s_w_incr = 0;
42392a0637fSLawrence Stewart 
42492a0637fSLawrence Stewart 	if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh)) {
42592a0637fSLawrence Stewart 		/* Slow start. */
426*22dcc812SRichard Scheffenegger 		incr = mss;
42792a0637fSLawrence Stewart 		s_w_incr = incr;
42892a0637fSLawrence Stewart 		cdg_data->window_incr = cdg_data->rtt_count = 0;
42992a0637fSLawrence Stewart 	} else {
43092a0637fSLawrence Stewart 		/* Congestion avoidance. */
43192a0637fSLawrence Stewart 		if (new_measurement) {
432*22dcc812SRichard Scheffenegger 			s_w_incr = mss;
43392a0637fSLawrence Stewart 			if (V_cdg_alpha_inc == 0) {
434*22dcc812SRichard Scheffenegger 				incr = mss;
43592a0637fSLawrence Stewart 			} else {
43692a0637fSLawrence Stewart 				if (++cdg_data->rtt_count >= V_cdg_alpha_inc) {
43792a0637fSLawrence Stewart 					cdg_data->window_incr++;
43892a0637fSLawrence Stewart 					cdg_data->rtt_count = 0;
43992a0637fSLawrence Stewart 				}
440*22dcc812SRichard Scheffenegger 				incr = mss *
44192a0637fSLawrence Stewart 				    cdg_data->window_incr;
44292a0637fSLawrence Stewart 			}
44392a0637fSLawrence Stewart 		}
44492a0637fSLawrence Stewart 	}
44592a0637fSLawrence Stewart 
44692a0637fSLawrence Stewart 	if (cdg_data->shadow_w > 0)
44792a0637fSLawrence Stewart 		cdg_data->shadow_w = ulmin(cdg_data->shadow_w + s_w_incr,
44892a0637fSLawrence Stewart 		    TCP_MAXWIN << CCV(ccv, snd_scale));
44992a0637fSLawrence Stewart 
45092a0637fSLawrence Stewart 	CCV(ccv, snd_cwnd) = ulmin(CCV(ccv, snd_cwnd) + incr,
45192a0637fSLawrence Stewart 	    TCP_MAXWIN << CCV(ccv, snd_scale));
45292a0637fSLawrence Stewart }
45392a0637fSLawrence Stewart 
45492a0637fSLawrence Stewart static void
455f74352fbSRichard Scheffenegger cdg_cong_signal(struct cc_var *ccv, ccsignal_t signal_type)
45692a0637fSLawrence Stewart {
45792a0637fSLawrence Stewart 	struct cdg *cdg_data = ccv->cc_data;
45892a0637fSLawrence Stewart 
459f74352fbSRichard Scheffenegger 	switch((int)signal_type) {
46092a0637fSLawrence Stewart 	case CC_CDG_DELAY:
46192a0637fSLawrence Stewart 		CCV(ccv, snd_ssthresh) = cdg_window_decrease(ccv,
46292a0637fSLawrence Stewart 		    CCV(ccv, snd_cwnd), V_cdg_beta_delay);
46392a0637fSLawrence Stewart 		CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
46492a0637fSLawrence Stewart 		CCV(ccv, snd_recover) = CCV(ccv, snd_max);
46592a0637fSLawrence Stewart 		cdg_data->window_incr = cdg_data->rtt_count = 0;
46692a0637fSLawrence Stewart 		ENTER_CONGRECOVERY(CCV(ccv, t_flags));
46792a0637fSLawrence Stewart 		break;
46892a0637fSLawrence Stewart 	case CC_NDUPACK:
46992a0637fSLawrence Stewart 		/*
47092a0637fSLawrence Stewart 		 * If already responding to congestion OR we have guessed no
47192a0637fSLawrence Stewart 		 * queue in the path is full.
47292a0637fSLawrence Stewart 		 */
47392a0637fSLawrence Stewart 		if (IN_CONGRECOVERY(CCV(ccv, t_flags)) ||
47492a0637fSLawrence Stewart 		    cdg_data->queue_state < CDG_Q_FULL) {
47543053c12SSean Bruno 			CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd);
47692a0637fSLawrence Stewart 			CCV(ccv, snd_recover) = CCV(ccv, snd_max);
47792a0637fSLawrence Stewart 		} else {
47892a0637fSLawrence Stewart 			/*
47992a0637fSLawrence Stewart 			 * Loss is likely to be congestion related. We have
48092a0637fSLawrence Stewart 			 * inferred a queue full state, so have shadow window
48192a0637fSLawrence Stewart 			 * react to loss as NewReno would.
48292a0637fSLawrence Stewart 			 */
48392a0637fSLawrence Stewart 			if (cdg_data->shadow_w > 0)
48492a0637fSLawrence Stewart 				cdg_data->shadow_w = cdg_window_decrease(ccv,
48592a0637fSLawrence Stewart 				    cdg_data->shadow_w, RENO_BETA);
48692a0637fSLawrence Stewart 
4873ac12506SJonathan T. Looney 			CCV(ccv, snd_ssthresh) = max(cdg_data->shadow_w,
48843053c12SSean Bruno 			    cdg_window_decrease(ccv, CCV(ccv, snd_cwnd),
48943053c12SSean Bruno 			    V_cdg_beta_loss));
49092a0637fSLawrence Stewart 
49192a0637fSLawrence Stewart 			cdg_data->window_incr = cdg_data->rtt_count = 0;
49292a0637fSLawrence Stewart 		}
49392a0637fSLawrence Stewart 		ENTER_RECOVERY(CCV(ccv, t_flags));
49492a0637fSLawrence Stewart 		break;
49592a0637fSLawrence Stewart 	default:
496b8d60729SRandall Stewart 		newreno_cc_cong_signal(ccv, signal_type);
49792a0637fSLawrence Stewart 		break;
49892a0637fSLawrence Stewart 	}
49992a0637fSLawrence Stewart }
50092a0637fSLawrence Stewart 
50192a0637fSLawrence Stewart /*
50292a0637fSLawrence Stewart  * Using a negative exponential probabilistic backoff so that sources with
50392a0637fSLawrence Stewart  * varying RTTs which share the same link will, on average, have the same
50492a0637fSLawrence Stewart  * probability of backoff over time.
50592a0637fSLawrence Stewart  *
50692a0637fSLawrence Stewart  * Prob_backoff = 1 - exp(-qtrend / V_cdg_exp_backoff_scale), where
50792a0637fSLawrence Stewart  * V_cdg_exp_backoff_scale is the average qtrend for the exponential backoff.
50892a0637fSLawrence Stewart  */
50992a0637fSLawrence Stewart static inline int
51092a0637fSLawrence Stewart prob_backoff(long qtrend)
51192a0637fSLawrence Stewart {
512674956e1SHenrich Hartzer 	int backoff, idx;
513674956e1SHenrich Hartzer 	uint32_t p;
51492a0637fSLawrence Stewart 
51592a0637fSLawrence Stewart 	backoff = (qtrend > ((MAXGRAD * V_cdg_exp_backoff_scale) << D_P_E));
51692a0637fSLawrence Stewart 
51792a0637fSLawrence Stewart 	if (!backoff) {
51892a0637fSLawrence Stewart 		if (V_cdg_exp_backoff_scale > 1)
51992a0637fSLawrence Stewart 			idx = (qtrend + V_cdg_exp_backoff_scale / 2) /
52092a0637fSLawrence Stewart 			    V_cdg_exp_backoff_scale;
52192a0637fSLawrence Stewart 		else
52292a0637fSLawrence Stewart 			idx = qtrend;
52392a0637fSLawrence Stewart 
52492a0637fSLawrence Stewart 		/* Backoff probability proportional to rate of queue growth. */
525674956e1SHenrich Hartzer 		p = (UINT32_MAX / (1 << EXP_PREC)) * probexp[idx];
526674956e1SHenrich Hartzer 		backoff = (prng32() < p);
52792a0637fSLawrence Stewart 	}
52892a0637fSLawrence Stewart 
52992a0637fSLawrence Stewart 	return (backoff);
53092a0637fSLawrence Stewart }
53192a0637fSLawrence Stewart 
53292a0637fSLawrence Stewart static inline void
53392a0637fSLawrence Stewart calc_moving_average(struct cdg *cdg_data, long qdiff_max, long qdiff_min)
53492a0637fSLawrence Stewart {
53592a0637fSLawrence Stewart 	struct qdiff_sample *qds;
53692a0637fSLawrence Stewart 
53792a0637fSLawrence Stewart 	++cdg_data->num_samples;
53892a0637fSLawrence Stewart 	if (cdg_data->num_samples > cdg_data->sample_q_size) {
53992a0637fSLawrence Stewart 		/* Minimum RTT. */
54092a0637fSLawrence Stewart 		qds = STAILQ_FIRST(&cdg_data->qdiffmin_q);
54192a0637fSLawrence Stewart 		cdg_data->min_qtrend =  cdg_data->min_qtrend +
54292a0637fSLawrence Stewart 		    (qdiff_min - qds->qdiff) / cdg_data->sample_q_size;
54392a0637fSLawrence Stewart 		STAILQ_REMOVE_HEAD(&cdg_data->qdiffmin_q, qdiff_lnk);
54492a0637fSLawrence Stewart 		qds->qdiff = qdiff_min;
54592a0637fSLawrence Stewart 		STAILQ_INSERT_TAIL(&cdg_data->qdiffmin_q, qds, qdiff_lnk);
54692a0637fSLawrence Stewart 
54792a0637fSLawrence Stewart 		/* Maximum RTT. */
54892a0637fSLawrence Stewart 		qds = STAILQ_FIRST(&cdg_data->qdiffmax_q);
54992a0637fSLawrence Stewart 		cdg_data->max_qtrend =  cdg_data->max_qtrend +
55092a0637fSLawrence Stewart 		    (qdiff_max - qds->qdiff) / cdg_data->sample_q_size;
55192a0637fSLawrence Stewart 		STAILQ_REMOVE_HEAD(&cdg_data->qdiffmax_q, qdiff_lnk);
55292a0637fSLawrence Stewart 		qds->qdiff = qdiff_max;
55392a0637fSLawrence Stewart 		STAILQ_INSERT_TAIL(&cdg_data->qdiffmax_q, qds, qdiff_lnk);
55492a0637fSLawrence Stewart 		--cdg_data->num_samples;
55592a0637fSLawrence Stewart 	} else {
55692a0637fSLawrence Stewart 		qds = uma_zalloc(qdiffsample_zone, M_NOWAIT);
55792a0637fSLawrence Stewart 		if (qds != NULL) {
55892a0637fSLawrence Stewart 			cdg_data->min_qtrend = cdg_data->min_qtrend +
55992a0637fSLawrence Stewart 			    qdiff_min / cdg_data->sample_q_size;
56092a0637fSLawrence Stewart 			qds->qdiff = qdiff_min;
56192a0637fSLawrence Stewart 			STAILQ_INSERT_TAIL(&cdg_data->qdiffmin_q, qds,
56292a0637fSLawrence Stewart 			    qdiff_lnk);
56392a0637fSLawrence Stewart 		}
56492a0637fSLawrence Stewart 
56592a0637fSLawrence Stewart 		qds = uma_zalloc(qdiffsample_zone, M_NOWAIT);
56692a0637fSLawrence Stewart 		if (qds) {
56792a0637fSLawrence Stewart 			cdg_data->max_qtrend = cdg_data->max_qtrend +
56892a0637fSLawrence Stewart 			    qdiff_max / cdg_data->sample_q_size;
56992a0637fSLawrence Stewart 			qds->qdiff = qdiff_max;
57092a0637fSLawrence Stewart 			STAILQ_INSERT_TAIL(&cdg_data->qdiffmax_q, qds,
57192a0637fSLawrence Stewart 			    qdiff_lnk);
57292a0637fSLawrence Stewart 		}
57392a0637fSLawrence Stewart 	}
57492a0637fSLawrence Stewart }
57592a0637fSLawrence Stewart 
57692a0637fSLawrence Stewart static void
577f74352fbSRichard Scheffenegger cdg_ack_received(struct cc_var *ccv, ccsignal_t ack_type)
57892a0637fSLawrence Stewart {
57992a0637fSLawrence Stewart 	struct cdg *cdg_data;
58092a0637fSLawrence Stewart 	struct ertt *e_t;
58192a0637fSLawrence Stewart 	long qdiff_max, qdiff_min;
58292a0637fSLawrence Stewart 	int congestion, new_measurement, slowstart;
58392a0637fSLawrence Stewart 
58492a0637fSLawrence Stewart 	cdg_data = ccv->cc_data;
585e68b3792SGleb Smirnoff 	e_t = (struct ertt *)khelp_get_osd(&CCV(ccv, t_osd), ertt_id);
58692a0637fSLawrence Stewart 	new_measurement = e_t->flags & ERTT_NEW_MEASUREMENT;
58792a0637fSLawrence Stewart 	congestion = 0;
58892a0637fSLawrence Stewart 	cdg_data->maxrtt_in_rtt = imax(e_t->rtt, cdg_data->maxrtt_in_rtt);
58992a0637fSLawrence Stewart 	cdg_data->minrtt_in_rtt = imin(e_t->rtt, cdg_data->minrtt_in_rtt);
59092a0637fSLawrence Stewart 
59192a0637fSLawrence Stewart 	if (new_measurement) {
59292a0637fSLawrence Stewart 		slowstart = (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh));
59392a0637fSLawrence Stewart 		/*
59492a0637fSLawrence Stewart 		 * Update smoothed gradient measurements. Since we are only
59592a0637fSLawrence Stewart 		 * using one measurement per RTT, use max or min rtt_in_rtt.
59692a0637fSLawrence Stewart 		 * This is also less noisy than a sample RTT measurement. Max
59792a0637fSLawrence Stewart 		 * RTT measurements can have trouble due to OS issues.
59892a0637fSLawrence Stewart 		 */
59992a0637fSLawrence Stewart 		if (cdg_data->maxrtt_in_prevrtt) {
60092a0637fSLawrence Stewart 			qdiff_max = ((long)(cdg_data->maxrtt_in_rtt -
60192a0637fSLawrence Stewart 			    cdg_data->maxrtt_in_prevrtt) << D_P_E );
60292a0637fSLawrence Stewart 			qdiff_min = ((long)(cdg_data->minrtt_in_rtt -
60392a0637fSLawrence Stewart 			    cdg_data->minrtt_in_prevrtt) << D_P_E );
60492a0637fSLawrence Stewart 
605aa36fbd6SMichael Tuexen 			if (cdg_data->sample_q_size == 0) {
606aa36fbd6SMichael Tuexen 				cdg_data->max_qtrend = qdiff_max;
607aa36fbd6SMichael Tuexen 				cdg_data->min_qtrend = qdiff_min;
608aa36fbd6SMichael Tuexen 			} else
60992a0637fSLawrence Stewart 				calc_moving_average(cdg_data, qdiff_max, qdiff_min);
61092a0637fSLawrence Stewart 
61192a0637fSLawrence Stewart 			/* Probabilistic backoff with respect to gradient. */
61292a0637fSLawrence Stewart 			if (slowstart && qdiff_min > 0)
61392a0637fSLawrence Stewart 				congestion = prob_backoff(qdiff_min);
61492a0637fSLawrence Stewart 			else if (cdg_data->min_qtrend > 0)
61592a0637fSLawrence Stewart 				congestion = prob_backoff(cdg_data->min_qtrend);
61692a0637fSLawrence Stewart 			else if (slowstart && qdiff_max > 0)
61792a0637fSLawrence Stewart 				congestion = prob_backoff(qdiff_max);
61892a0637fSLawrence Stewart 			else if (cdg_data->max_qtrend > 0)
61992a0637fSLawrence Stewart 				congestion = prob_backoff(cdg_data->max_qtrend);
62092a0637fSLawrence Stewart 
62192a0637fSLawrence Stewart 			/* Update estimate of queue state. */
62292a0637fSLawrence Stewart 			if (cdg_data->min_qtrend > 0 &&
62392a0637fSLawrence Stewart 			    cdg_data->max_qtrend <= 0) {
62492a0637fSLawrence Stewart 				cdg_data->queue_state = CDG_Q_FULL;
62592a0637fSLawrence Stewart 			} else if (cdg_data->min_qtrend >= 0 &&
62692a0637fSLawrence Stewart 			    cdg_data->max_qtrend < 0) {
62792a0637fSLawrence Stewart 				cdg_data->queue_state = CDG_Q_EMPTY;
62892a0637fSLawrence Stewart 				cdg_data->shadow_w = 0;
62992a0637fSLawrence Stewart 			} else if (cdg_data->min_qtrend > 0 &&
63092a0637fSLawrence Stewart 			    cdg_data->max_qtrend > 0) {
63192a0637fSLawrence Stewart 				cdg_data->queue_state = CDG_Q_RISING;
63292a0637fSLawrence Stewart 			} else if (cdg_data->min_qtrend < 0 &&
63392a0637fSLawrence Stewart 			    cdg_data->max_qtrend < 0) {
63492a0637fSLawrence Stewart 				cdg_data->queue_state = CDG_Q_FALLING;
63592a0637fSLawrence Stewart 			}
63692a0637fSLawrence Stewart 
63792a0637fSLawrence Stewart 			if (cdg_data->min_qtrend < 0 ||
63892a0637fSLawrence Stewart 			    cdg_data->max_qtrend < 0)
63992a0637fSLawrence Stewart 				cdg_data->consec_cong_cnt = 0;
64092a0637fSLawrence Stewart 		}
64192a0637fSLawrence Stewart 
64292a0637fSLawrence Stewart 		cdg_data->minrtt_in_prevrtt = cdg_data->minrtt_in_rtt;
64392a0637fSLawrence Stewart 		cdg_data->minrtt_in_rtt = INT_MAX;
64492a0637fSLawrence Stewart 		cdg_data->maxrtt_in_prevrtt = cdg_data->maxrtt_in_rtt;
64592a0637fSLawrence Stewart 		cdg_data->maxrtt_in_rtt = 0;
64692a0637fSLawrence Stewart 		e_t->flags &= ~ERTT_NEW_MEASUREMENT;
64792a0637fSLawrence Stewart 	}
64892a0637fSLawrence Stewart 
64992a0637fSLawrence Stewart 	if (congestion) {
65092a0637fSLawrence Stewart 		cdg_data->consec_cong_cnt++;
65192a0637fSLawrence Stewart 		if (!IN_RECOVERY(CCV(ccv, t_flags))) {
65292a0637fSLawrence Stewart 			if (cdg_data->consec_cong_cnt <= V_cdg_consec_cong)
65392a0637fSLawrence Stewart 				cdg_cong_signal(ccv, CC_CDG_DELAY);
65492a0637fSLawrence Stewart 			else
65592a0637fSLawrence Stewart 				/*
65692a0637fSLawrence Stewart 				 * We have been backing off but the queue is not
65792a0637fSLawrence Stewart 				 * falling. Assume we are competing with
65892a0637fSLawrence Stewart 				 * loss-based flows and don't back off for the
65992a0637fSLawrence Stewart 				 * next V_cdg_hold_backoff RTT periods.
66092a0637fSLawrence Stewart 				 */
66192a0637fSLawrence Stewart 				if (cdg_data->consec_cong_cnt >=
66292a0637fSLawrence Stewart 				    V_cdg_consec_cong + V_cdg_hold_backoff)
66392a0637fSLawrence Stewart 					cdg_data->consec_cong_cnt = 0;
66492a0637fSLawrence Stewart 
66592a0637fSLawrence Stewart 			/* Won't see effect until 2nd RTT. */
66692a0637fSLawrence Stewart 			cdg_data->maxrtt_in_prevrtt = 0;
66792a0637fSLawrence Stewart 			/*
66892a0637fSLawrence Stewart 			 * Resync shadow window in case we are competing with a
66992a0637fSLawrence Stewart 			 * loss based flow
67092a0637fSLawrence Stewart 			 */
67192a0637fSLawrence Stewart 			cdg_data->shadow_w = ulmax(CCV(ccv, snd_cwnd),
67292a0637fSLawrence Stewart 			    cdg_data->shadow_w);
67392a0637fSLawrence Stewart 		}
67492a0637fSLawrence Stewart 	} else if (ack_type == CC_ACK)
67592a0637fSLawrence Stewart 		cdg_window_increase(ccv, new_measurement);
67692a0637fSLawrence Stewart }
67792a0637fSLawrence Stewart 
67892a0637fSLawrence Stewart /* When a vnet is created and being initialised, init the per-stack CDG vars. */
67992a0637fSLawrence Stewart VNET_SYSINIT(cdg_init_vnet, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST,
68092a0637fSLawrence Stewart     cdg_init_vnet, NULL);
68192a0637fSLawrence Stewart 
68292a0637fSLawrence Stewart SYSCTL_DECL(_net_inet_tcp_cc_cdg);
6837029da5cSPawel Biernacki SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, cdg, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
68492a0637fSLawrence Stewart     "CAIA delay-gradient congestion control related settings");
68592a0637fSLawrence Stewart 
68692a0637fSLawrence Stewart SYSCTL_STRING(_net_inet_tcp_cc_cdg, OID_AUTO, version,
68792a0637fSLawrence Stewart     CTLFLAG_RD, CDG_VERSION, sizeof(CDG_VERSION) - 1,
68892a0637fSLawrence Stewart     "Current algorithm/implementation version number");
68992a0637fSLawrence Stewart 
6906df8a710SGleb Smirnoff SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, alpha_inc,
6916df8a710SGleb Smirnoff     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_alpha_inc), 0,
69292a0637fSLawrence Stewart     "Increment the window increase factor alpha by 1 MSS segment every "
69392a0637fSLawrence Stewart     "alpha_inc RTTs during congestion avoidance mode.");
69492a0637fSLawrence Stewart 
6956df8a710SGleb Smirnoff SYSCTL_PROC(_net_inet_tcp_cc_cdg, OID_AUTO, beta_delay,
6967029da5cSPawel Biernacki     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
6977029da5cSPawel Biernacki     &VNET_NAME(cdg_beta_delay), 70, &cdg_beta_handler, "IU",
69892a0637fSLawrence Stewart     "Delay-based window decrease factor as a percentage "
69992a0637fSLawrence Stewart     "(on delay-based backoff, w = w * beta_delay / 100)");
70092a0637fSLawrence Stewart 
7016df8a710SGleb Smirnoff SYSCTL_PROC(_net_inet_tcp_cc_cdg, OID_AUTO, beta_loss,
7027029da5cSPawel Biernacki     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7037029da5cSPawel Biernacki     &VNET_NAME(cdg_beta_loss), 50, &cdg_beta_handler, "IU",
70492a0637fSLawrence Stewart     "Loss-based window decrease factor as a percentage "
70592a0637fSLawrence Stewart     "(on loss-based backoff, w = w * beta_loss / 100)");
70692a0637fSLawrence Stewart 
7076df8a710SGleb Smirnoff SYSCTL_PROC(_net_inet_tcp_cc_cdg, OID_AUTO, exp_backoff_scale,
7087029da5cSPawel Biernacki     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
7096df8a710SGleb Smirnoff     &VNET_NAME(cdg_exp_backoff_scale), 2, &cdg_exp_backoff_scale_handler, "IU",
71092a0637fSLawrence Stewart     "Scaling parameter for the probabilistic exponential backoff");
71192a0637fSLawrence Stewart 
7126df8a710SGleb Smirnoff SYSCTL_UINT(_net_inet_tcp_cc_cdg,  OID_AUTO, smoothing_factor,
7136df8a710SGleb Smirnoff     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_smoothing_factor), 8,
71492a0637fSLawrence Stewart     "Number of samples used for moving average smoothing (0 = no smoothing)");
71592a0637fSLawrence Stewart 
7166df8a710SGleb Smirnoff SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, loss_compete_consec_cong,
7176df8a710SGleb Smirnoff     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_consec_cong), 5,
71892a0637fSLawrence Stewart     "Number of consecutive delay-gradient based congestion episodes which will "
71992a0637fSLawrence Stewart     "trigger loss based CC compatibility");
72092a0637fSLawrence Stewart 
7216df8a710SGleb Smirnoff SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, loss_compete_hold_backoff,
7226df8a710SGleb Smirnoff     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(cdg_hold_backoff), 5,
72392a0637fSLawrence Stewart     "Number of consecutive delay-gradient based congestion episodes to hold "
72492a0637fSLawrence Stewart     "the window backoff for loss based CC compatibility");
72592a0637fSLawrence Stewart 
72692a0637fSLawrence Stewart DECLARE_CC_MODULE(cdg, &cdg_cc_algo);
727b8d60729SRandall Stewart MODULE_VERSION(cdg, 2);
72892a0637fSLawrence Stewart MODULE_DEPEND(cdg, ertt, 1, 1, 1);
729