cc_chd.c revision 220592
1218155Slstewart/*- 2218155Slstewart * Copyright (c) 2009-2010 3218155Slstewart * Swinburne University of Technology, Melbourne, Australia 4218155Slstewart * Copyright (c) 2010-2011 The FreeBSD Foundation 5218155Slstewart * All rights reserved. 6218155Slstewart * 7218155Slstewart * This software was developed at the Centre for Advanced Internet 8220560Slstewart * Architectures, Swinburne University of Technology, by David Hayes and 9220560Slstewart * Lawrence Stewart, made possible in part by a grant from the Cisco University 10220560Slstewart * Research Program Fund at Community Foundation Silicon Valley. 11218155Slstewart * 12218155Slstewart * Portions of this software were developed at the Centre for Advanced Internet 13218155Slstewart * Architectures, Swinburne University of Technology, Melbourne, Australia by 14218155Slstewart * David Hayes under sponsorship from the FreeBSD Foundation. 15218155Slstewart * 16218155Slstewart * Redistribution and use in source and binary forms, with or without 17218155Slstewart * modification, are permitted provided that the following conditions 18218155Slstewart * are met: 19218155Slstewart * 1. Redistributions of source code must retain the above copyright 20218155Slstewart * notice, this list of conditions and the following disclaimer. 21218155Slstewart * 2. Redistributions in binary form must reproduce the above copyright 22218155Slstewart * notice, this list of conditions and the following disclaimer in the 23218155Slstewart * documentation and/or other materials provided with the distribution. 24218155Slstewart * 25218155Slstewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 26218155Slstewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27218155Slstewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28218155Slstewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 29218155Slstewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30218155Slstewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31218155Slstewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32218155Slstewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33218155Slstewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34218155Slstewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35218155Slstewart * SUCH DAMAGE. 36218155Slstewart */ 37218155Slstewart 38218155Slstewart/* 39218155Slstewart * An implementation of the CAIA-Hamilton delay based congestion control 40218155Slstewart * algorithm, based on "Improved coexistence and loss tolerance for delay based 41218155Slstewart * TCP congestion control" by D. A. Hayes and G. Armitage., in 35th Annual IEEE 42218155Slstewart * Conference on Local Computer Networks (LCN 2010), Denver, Colorado, USA, 43218155Slstewart * 11-14 October 2010. 44218155Slstewart * 45218155Slstewart * Originally released as part of the NewTCP research project at Swinburne 46220560Slstewart * University of Technology's Centre for Advanced Internet Architectures, 47220560Slstewart * Melbourne, Australia, which was made possible in part by a grant from the 48220560Slstewart * Cisco University Research Program Fund at Community Foundation Silicon 49220560Slstewart * Valley. More details are available at: 50218155Slstewart * http://caia.swin.edu.au/urp/newtcp/ 51218155Slstewart */ 52218155Slstewart 53218155Slstewart#include <sys/cdefs.h> 54218155Slstewart__FBSDID("$FreeBSD: head/sys/netinet/cc/cc_chd.c 220592 2011-04-13 11:28:46Z pluknet $"); 55218155Slstewart 56218155Slstewart#include <sys/param.h> 57218155Slstewart#include <sys/kernel.h> 58218155Slstewart#include <sys/khelp.h> 59218155Slstewart#include <sys/limits.h> 60218155Slstewart#include <sys/malloc.h> 61218155Slstewart#include <sys/module.h> 62218155Slstewart#include <sys/queue.h> 63218155Slstewart#include <sys/socket.h> 64218155Slstewart#include <sys/socketvar.h> 65218155Slstewart#include <sys/sysctl.h> 66218155Slstewart#include <sys/systm.h> 67218155Slstewart 68218155Slstewart#include <net/if.h> 69218155Slstewart#include <net/vnet.h> 70218155Slstewart 71218155Slstewart#include <netinet/cc.h> 72218155Slstewart#include <netinet/tcp_seq.h> 73218155Slstewart#include <netinet/tcp_timer.h> 74218155Slstewart#include <netinet/tcp_var.h> 75218155Slstewart 76218155Slstewart#include <netinet/cc/cc_module.h> 77218155Slstewart 78218155Slstewart#include <netinet/khelp/h_ertt.h> 79218155Slstewart 80218155Slstewart#define CAST_PTR_INT(X) (*((int*)(X))) 81218155Slstewart 82218155Slstewart/* 83218155Slstewart * Private signal type for rate based congestion signal. 84218155Slstewart * See <netinet/cc.h> for appropriate bit-range to use for private signals. 85218155Slstewart */ 86218155Slstewart#define CC_CHD_DELAY 0x02000000 87218155Slstewart 88218155Slstewart/* Largest possible number returned by random(). */ 89218155Slstewart#define RANDOM_MAX INT_MAX 90218155Slstewart 91218155Slstewartstatic void chd_ack_received(struct cc_var *ccv, uint16_t ack_type); 92218155Slstewartstatic void chd_cb_destroy(struct cc_var *ccv); 93218155Slstewartstatic int chd_cb_init(struct cc_var *ccv); 94218155Slstewartstatic void chd_cong_signal(struct cc_var *ccv, uint32_t signal_type); 95218155Slstewartstatic void chd_conn_init(struct cc_var *ccv); 96218155Slstewartstatic int chd_mod_init(void); 97218155Slstewart 98218155Slstewartstruct chd { 99218155Slstewart /* 100218155Slstewart * Shadow window - keeps track of what the NewReno congestion window 101218155Slstewart * would have been if delay-based cwnd backoffs had not been made. This 102218155Slstewart * functionality aids coexistence with loss-based TCP flows which may be 103218155Slstewart * sharing links along the path. 104218155Slstewart */ 105218155Slstewart unsigned long shadow_w; 106218155Slstewart /* 107218155Slstewart * Loss-based TCP compatibility flag - When set, it turns on the shadow 108218155Slstewart * window functionality. 109218155Slstewart */ 110218155Slstewart int loss_compete; 111218155Slstewart /* The maximum round trip time seen within a measured rtt period. */ 112218155Slstewart int maxrtt_in_rtt; 113218155Slstewart /* The previous qdly that caused cwnd to backoff. */ 114218155Slstewart int prev_backoff_qdly; 115218155Slstewart}; 116218155Slstewart 117218155Slstewartstatic int ertt_id; 118218155Slstewart 119218155Slstewartstatic VNET_DEFINE(uint32_t, chd_qmin) = 5; 120218155Slstewartstatic VNET_DEFINE(uint32_t, chd_pmax) = 50; 121218155Slstewartstatic VNET_DEFINE(uint32_t, chd_loss_fair) = 1; 122218155Slstewartstatic VNET_DEFINE(uint32_t, chd_use_max) = 1; 123218155Slstewartstatic VNET_DEFINE(uint32_t, chd_qthresh) = 20; 124218155Slstewart#define V_chd_qthresh VNET(chd_qthresh) 125218155Slstewart#define V_chd_qmin VNET(chd_qmin) 126218155Slstewart#define V_chd_pmax VNET(chd_pmax) 127218155Slstewart#define V_chd_loss_fair VNET(chd_loss_fair) 128218155Slstewart#define V_chd_use_max VNET(chd_use_max) 129218155Slstewart 130220592Spluknetstatic MALLOC_DEFINE(M_CHD, "chd data", 131218155Slstewart "Per connection data required for the CHD congestion control algorithm"); 132218155Slstewart 133218155Slstewartstruct cc_algo chd_cc_algo = { 134218155Slstewart .name = "chd", 135218155Slstewart .ack_received = chd_ack_received, 136218155Slstewart .cb_destroy = chd_cb_destroy, 137218155Slstewart .cb_init = chd_cb_init, 138218155Slstewart .cong_signal = chd_cong_signal, 139218155Slstewart .conn_init = chd_conn_init, 140218155Slstewart .mod_init = chd_mod_init 141218155Slstewart}; 142218155Slstewart 143218155Slstewartstatic __inline void 144218155Slstewartchd_window_decrease(struct cc_var *ccv) 145218155Slstewart{ 146218155Slstewart unsigned long win; 147218155Slstewart 148218155Slstewart win = min(CCV(ccv, snd_wnd), CCV(ccv, snd_cwnd)) / CCV(ccv, t_maxseg); 149218155Slstewart win -= max((win / 2), 1); 150218155Slstewart CCV(ccv, snd_ssthresh) = max(win, 2) * CCV(ccv, t_maxseg); 151218155Slstewart} 152218155Slstewart 153218155Slstewart/* 154218155Slstewart * Probabilistic backoff function. Returns 1 if we should backoff or 0 155218155Slstewart * otherwise. The calculation of p is similar to the calculation of p in cc_hd. 156218155Slstewart */ 157218155Slstewartstatic __inline int 158218155Slstewartshould_backoff(int qdly, int maxqdly, struct chd *chd_data) 159218155Slstewart{ 160218155Slstewart unsigned long p, rand; 161218155Slstewart 162218155Slstewart rand = random(); 163218155Slstewart 164218155Slstewart if (qdly < V_chd_qthresh) { 165218155Slstewart chd_data->loss_compete = 0; 166218155Slstewart p = (((RANDOM_MAX / 100) * V_chd_pmax) / 167218155Slstewart (V_chd_qthresh - V_chd_qmin)) * 168218155Slstewart (qdly - V_chd_qmin); 169218155Slstewart } else { 170218155Slstewart if (qdly > V_chd_qthresh) { 171218155Slstewart p = (((RANDOM_MAX / 100) * V_chd_pmax) / 172218155Slstewart (maxqdly - V_chd_qthresh)) * 173218155Slstewart (maxqdly - qdly); 174218155Slstewart if (V_chd_loss_fair && rand < p) 175218155Slstewart chd_data->loss_compete = 1; 176218155Slstewart } else { 177218155Slstewart p = (RANDOM_MAX / 100) * V_chd_pmax; 178218155Slstewart chd_data->loss_compete = 0; 179218155Slstewart } 180218155Slstewart } 181218155Slstewart 182218155Slstewart return (rand < p); 183218155Slstewart} 184218155Slstewart 185218155Slstewartstatic __inline void 186218155Slstewartchd_window_increase(struct cc_var *ccv, int new_measurement) 187218155Slstewart{ 188218155Slstewart struct chd *chd_data; 189218155Slstewart int incr; 190218155Slstewart 191218155Slstewart chd_data = ccv->cc_data; 192218155Slstewart incr = 0; 193218155Slstewart 194218155Slstewart if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh)) { 195218155Slstewart /* Adapted from NewReno slow start. */ 196218155Slstewart if (V_tcp_do_rfc3465) { 197218155Slstewart /* In slow-start with ABC enabled. */ 198218155Slstewart if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max)) { 199218155Slstewart /* Not due to RTO. */ 200218155Slstewart incr = min(ccv->bytes_this_ack, 201218155Slstewart V_tcp_abc_l_var * CCV(ccv, t_maxseg)); 202218155Slstewart } else { 203218155Slstewart /* Due to RTO. */ 204218155Slstewart incr = min(ccv->bytes_this_ack, 205218155Slstewart CCV(ccv, t_maxseg)); 206218155Slstewart } 207218155Slstewart } else 208218155Slstewart incr = CCV(ccv, t_maxseg); 209218155Slstewart 210218155Slstewart } else { /* Congestion avoidance. */ 211218155Slstewart if (V_tcp_do_rfc3465) { 212218155Slstewart if (ccv->flags & CCF_ABC_SENTAWND) { 213218155Slstewart ccv->flags &= ~CCF_ABC_SENTAWND; 214218155Slstewart incr = CCV(ccv, t_maxseg); 215218155Slstewart } 216218155Slstewart } else if (new_measurement) 217218155Slstewart incr = CCV(ccv, t_maxseg); 218218155Slstewart } 219218155Slstewart 220218155Slstewart if (chd_data->shadow_w > 0) { 221218155Slstewart /* Track NewReno window. */ 222218155Slstewart chd_data->shadow_w = min(chd_data->shadow_w + incr, 223218155Slstewart TCP_MAXWIN << CCV(ccv, snd_scale)); 224218155Slstewart } 225218155Slstewart 226218155Slstewart CCV(ccv,snd_cwnd) = min(CCV(ccv, snd_cwnd) + incr, 227218155Slstewart TCP_MAXWIN << CCV(ccv, snd_scale)); 228218155Slstewart} 229218155Slstewart 230218155Slstewart/* 231218155Slstewart * All ACK signals are used for timing measurements to determine delay-based 232218155Slstewart * congestion. However, window increases are only performed when 233218155Slstewart * ack_type == CC_ACK. 234218155Slstewart */ 235218155Slstewartstatic void 236218155Slstewartchd_ack_received(struct cc_var *ccv, uint16_t ack_type) 237218155Slstewart{ 238218155Slstewart struct chd *chd_data; 239218155Slstewart struct ertt *e_t; 240218155Slstewart int backoff, new_measurement, qdly, rtt; 241218155Slstewart 242218155Slstewart e_t = khelp_get_osd(CCV(ccv, osd), ertt_id); 243218155Slstewart chd_data = ccv->cc_data; 244218155Slstewart new_measurement = e_t->flags & ERTT_NEW_MEASUREMENT; 245218155Slstewart backoff = qdly = 0; 246218155Slstewart 247218155Slstewart chd_data->maxrtt_in_rtt = imax(e_t->rtt, chd_data->maxrtt_in_rtt); 248218155Slstewart 249218155Slstewart if (new_measurement) { 250218155Slstewart /* 251218155Slstewart * There is a new per RTT measurement, so check to see if there 252218155Slstewart * is delay based congestion. 253218155Slstewart */ 254218155Slstewart rtt = V_chd_use_max ? chd_data->maxrtt_in_rtt : e_t->rtt; 255218155Slstewart chd_data->maxrtt_in_rtt = 0; 256218155Slstewart 257218155Slstewart if (rtt && e_t->minrtt && !IN_RECOVERY(CCV(ccv, t_flags))) { 258218155Slstewart qdly = rtt - e_t->minrtt; 259218155Slstewart if (qdly > V_chd_qmin) { 260218155Slstewart /* 261218155Slstewart * Probabilistic delay based congestion 262218155Slstewart * indication. 263218155Slstewart */ 264218155Slstewart backoff = should_backoff(qdly, 265218155Slstewart e_t->maxrtt - e_t->minrtt, chd_data); 266218155Slstewart } else 267218155Slstewart chd_data->loss_compete = 0; 268218155Slstewart } 269218155Slstewart /* Reset per RTT measurement flag to start a new measurement. */ 270218155Slstewart e_t->flags &= ~ERTT_NEW_MEASUREMENT; 271218155Slstewart } 272218155Slstewart 273218155Slstewart if (backoff) { 274218155Slstewart /* 275218155Slstewart * Update shadow_w before delay based backoff. 276218155Slstewart */ 277218155Slstewart if (chd_data->loss_compete || 278218155Slstewart qdly > chd_data->prev_backoff_qdly) { 279218155Slstewart /* 280218155Slstewart * Delay is higher than when we backed off previously, 281218155Slstewart * so it is possible that this flow is competing with 282218155Slstewart * loss based flows. 283218155Slstewart */ 284218155Slstewart chd_data->shadow_w = max(CCV(ccv, snd_cwnd), 285218155Slstewart chd_data->shadow_w); 286218155Slstewart } else { 287218155Slstewart /* 288218155Slstewart * Reset shadow_w, as it is probable that this flow is 289218155Slstewart * not competing with loss based flows at the moment. 290218155Slstewart */ 291218155Slstewart chd_data->shadow_w = 0; 292218155Slstewart } 293218155Slstewart 294218155Slstewart chd_data->prev_backoff_qdly = qdly; 295218155Slstewart /* 296218155Slstewart * Send delay-based congestion signal to the congestion signal 297218155Slstewart * handler. 298218155Slstewart */ 299218155Slstewart chd_cong_signal(ccv, CC_CHD_DELAY); 300218155Slstewart 301218155Slstewart } else if (ack_type == CC_ACK) 302218155Slstewart chd_window_increase(ccv, new_measurement); 303218155Slstewart} 304218155Slstewart 305218155Slstewartstatic void 306218155Slstewartchd_cb_destroy(struct cc_var *ccv) 307218155Slstewart{ 308218155Slstewart 309218155Slstewart if (ccv->cc_data != NULL) 310218155Slstewart free(ccv->cc_data, M_CHD); 311218155Slstewart} 312218155Slstewart 313218155Slstewartstatic int 314218155Slstewartchd_cb_init(struct cc_var *ccv) 315218155Slstewart{ 316218155Slstewart struct chd *chd_data; 317218155Slstewart 318218155Slstewart chd_data = malloc(sizeof(struct chd), M_CHD, M_NOWAIT); 319218155Slstewart if (chd_data == NULL) 320218155Slstewart return (ENOMEM); 321218155Slstewart 322218155Slstewart chd_data->shadow_w = 0; 323218155Slstewart ccv->cc_data = chd_data; 324218155Slstewart 325218155Slstewart return (0); 326218155Slstewart} 327218155Slstewart 328218155Slstewartstatic void 329218155Slstewartchd_cong_signal(struct cc_var *ccv, uint32_t signal_type) 330218155Slstewart{ 331218155Slstewart struct ertt *e_t; 332218155Slstewart struct chd *chd_data; 333218155Slstewart int qdly; 334218155Slstewart 335218155Slstewart e_t = khelp_get_osd(CCV(ccv, osd), ertt_id); 336218155Slstewart chd_data = ccv->cc_data; 337218155Slstewart qdly = imax(e_t->rtt, chd_data->maxrtt_in_rtt) - e_t->minrtt; 338218155Slstewart 339218155Slstewart switch(signal_type) { 340218155Slstewart case CC_CHD_DELAY: 341218155Slstewart chd_window_decrease(ccv); /* Set new ssthresh. */ 342218155Slstewart CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); 343218155Slstewart CCV(ccv, snd_recover) = CCV(ccv, snd_max); 344218155Slstewart ENTER_CONGRECOVERY(CCV(ccv, t_flags)); 345218155Slstewart break; 346218155Slstewart 347218155Slstewart case CC_NDUPACK: /* Packet loss. */ 348218155Slstewart /* 349218155Slstewart * Only react to loss as a congestion signal if qdly > 350218155Slstewart * V_chd_qthresh. If qdly is less than qthresh, presume that 351218155Slstewart * this is a non congestion related loss. If qdly is greater 352218155Slstewart * than qthresh, assume that we are competing with loss based 353218155Slstewart * tcp flows and restore window from any unnecessary backoffs, 354218155Slstewart * before the decrease. 355218155Slstewart */ 356218155Slstewart if (!IN_RECOVERY(CCV(ccv, t_flags)) && qdly > V_chd_qthresh) { 357218155Slstewart if (chd_data->loss_compete) { 358218155Slstewart CCV(ccv, snd_cwnd) = max(CCV(ccv, snd_cwnd), 359218155Slstewart chd_data->shadow_w); 360218155Slstewart } 361218155Slstewart chd_window_decrease(ccv); 362218155Slstewart } else { 363218155Slstewart /* 364218155Slstewart * This loss isn't congestion related, or already 365218155Slstewart * recovering from congestion. 366218155Slstewart */ 367218155Slstewart CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd); 368218155Slstewart CCV(ccv, snd_recover) = CCV(ccv, snd_max); 369218155Slstewart } 370218155Slstewart 371218155Slstewart if (chd_data->shadow_w > 0) { 372218155Slstewart chd_data->shadow_w = max(chd_data->shadow_w / 373218155Slstewart CCV(ccv, t_maxseg) / 2, 2) * CCV(ccv, t_maxseg); 374218155Slstewart } 375218155Slstewart ENTER_FASTRECOVERY(CCV(ccv, t_flags)); 376218155Slstewart break; 377218155Slstewart 378218155Slstewart default: 379218155Slstewart newreno_cc_algo.cong_signal(ccv, signal_type); 380218155Slstewart } 381218155Slstewart} 382218155Slstewart 383218155Slstewartstatic void 384218155Slstewartchd_conn_init(struct cc_var *ccv) 385218155Slstewart{ 386218155Slstewart struct chd *chd_data; 387218155Slstewart 388218155Slstewart chd_data = ccv->cc_data; 389218155Slstewart chd_data->prev_backoff_qdly = 0; 390218155Slstewart chd_data->maxrtt_in_rtt = 0; 391218155Slstewart chd_data->loss_compete = 0; 392218155Slstewart /* 393218155Slstewart * Initialise the shadow_cwnd to be equal to snd_cwnd in case we are 394218155Slstewart * competing with loss based flows from the start. 395218155Slstewart */ 396218155Slstewart chd_data->shadow_w = CCV(ccv, snd_cwnd); 397218155Slstewart} 398218155Slstewart 399218155Slstewartstatic int 400218155Slstewartchd_mod_init(void) 401218155Slstewart{ 402218155Slstewart 403218155Slstewart ertt_id = khelp_get_id("ertt"); 404218155Slstewart if (ertt_id <= 0) { 405218155Slstewart printf("%s: h_ertt module not found\n", __func__); 406218155Slstewart return (ENOENT); 407218155Slstewart } 408218155Slstewart 409218155Slstewart chd_cc_algo.after_idle = newreno_cc_algo.after_idle; 410218155Slstewart chd_cc_algo.post_recovery = newreno_cc_algo.post_recovery; 411218155Slstewart 412218155Slstewart return (0); 413218155Slstewart} 414218155Slstewart 415218155Slstewartstatic int 416218155Slstewartchd_loss_fair_handler(SYSCTL_HANDLER_ARGS) 417218155Slstewart{ 418218155Slstewart int error; 419218155Slstewart uint32_t new; 420218155Slstewart 421218155Slstewart new = V_chd_loss_fair; 422218155Slstewart error = sysctl_handle_int(oidp, &new, 0, req); 423218155Slstewart if (error == 0 && req->newptr != NULL) { 424218155Slstewart if (CAST_PTR_INT(req->newptr) > 1) 425218155Slstewart error = EINVAL; 426218155Slstewart else 427218155Slstewart V_chd_loss_fair = new; 428218155Slstewart } 429218155Slstewart 430218155Slstewart return (error); 431218155Slstewart} 432218155Slstewart 433218155Slstewartstatic int 434218155Slstewartchd_pmax_handler(SYSCTL_HANDLER_ARGS) 435218155Slstewart{ 436218155Slstewart int error; 437218155Slstewart uint32_t new; 438218155Slstewart 439218155Slstewart new = V_chd_pmax; 440218155Slstewart error = sysctl_handle_int(oidp, &new, 0, req); 441218155Slstewart if (error == 0 && req->newptr != NULL) { 442218155Slstewart if (CAST_PTR_INT(req->newptr) == 0 || 443218155Slstewart CAST_PTR_INT(req->newptr) > 100) 444218155Slstewart error = EINVAL; 445218155Slstewart else 446218155Slstewart V_chd_pmax = new; 447218155Slstewart } 448218155Slstewart 449218155Slstewart return (error); 450218155Slstewart} 451218155Slstewart 452218155Slstewartstatic int 453218155Slstewartchd_qthresh_handler(SYSCTL_HANDLER_ARGS) 454218155Slstewart{ 455218155Slstewart int error; 456218155Slstewart uint32_t new; 457218155Slstewart 458218155Slstewart new = V_chd_qthresh; 459218155Slstewart error = sysctl_handle_int(oidp, &new, 0, req); 460218155Slstewart if (error == 0 && req->newptr != NULL) { 461218155Slstewart if (CAST_PTR_INT(req->newptr) <= V_chd_qmin) 462218155Slstewart error = EINVAL; 463218155Slstewart else 464218155Slstewart V_chd_qthresh = new; 465218155Slstewart } 466218155Slstewart 467218155Slstewart return (error); 468218155Slstewart} 469218155Slstewart 470218155SlstewartSYSCTL_DECL(_net_inet_tcp_cc_chd); 471218155SlstewartSYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, chd, CTLFLAG_RW, NULL, 472218155Slstewart "CAIA Hamilton delay-based congestion control related settings"); 473218155Slstewart 474218155SlstewartSYSCTL_VNET_PROC(_net_inet_tcp_cc_chd, OID_AUTO, loss_fair, 475218155Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(chd_loss_fair), 1, &chd_loss_fair_handler, 476218155Slstewart "IU", "Flag to enable shadow window functionality."); 477218155Slstewart 478218155SlstewartSYSCTL_VNET_PROC(_net_inet_tcp_cc_chd, OID_AUTO, pmax, 479218155Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(chd_pmax), 5, &chd_pmax_handler, 480218155Slstewart "IU", "Per RTT maximum backoff probability as a percentage"); 481218155Slstewart 482218155SlstewartSYSCTL_VNET_PROC(_net_inet_tcp_cc_chd, OID_AUTO, queue_threshold, 483218155Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(chd_qthresh), 20, &chd_qthresh_handler, 484218155Slstewart "IU", "Queueing congestion threshold in ticks"); 485218155Slstewart 486218155SlstewartSYSCTL_VNET_UINT(_net_inet_tcp_cc_chd, OID_AUTO, queue_min, 487218155Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(chd_qmin), 5, 488218155Slstewart "Minimum queueing delay threshold in ticks"); 489218155Slstewart 490218155SlstewartSYSCTL_VNET_UINT(_net_inet_tcp_cc_chd, OID_AUTO, use_max, 491218155Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(chd_use_max), 1, 492218155Slstewart "Use the maximum RTT seen within the measurement period (RTT) " 493218155Slstewart "as the basic delay measurement for the algorithm."); 494218155Slstewart 495218155SlstewartDECLARE_CC_MODULE(chd, &chd_cc_algo); 496218155SlstewartMODULE_DEPEND(chd, ertt, 1, 1, 1); 497