1218153Slstewart/*- 2218153Slstewart * Copyright (c) 2009-2010 3218153Slstewart * Swinburne University of Technology, Melbourne, Australia 4218153Slstewart * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org> 5218153Slstewart * Copyright (c) 2010-2011 The FreeBSD Foundation 6218153Slstewart * All rights reserved. 7218153Slstewart * 8218153Slstewart * This software was developed at the Centre for Advanced Internet 9220560Slstewart * Architectures, Swinburne University of Technology, by David Hayes and 10220560Slstewart * Lawrence Stewart, made possible in part by a grant from the Cisco University 11220560Slstewart * Research Program Fund at Community Foundation Silicon Valley. 12218153Slstewart * 13218153Slstewart * Portions of this software were developed at the Centre for Advanced Internet 14218153Slstewart * Architectures, Swinburne University of Technology, Melbourne, Australia by 15218153Slstewart * David Hayes under sponsorship from the FreeBSD Foundation. 16218153Slstewart * 17218153Slstewart * Redistribution and use in source and binary forms, with or without 18218153Slstewart * modification, are permitted provided that the following conditions 19218153Slstewart * are met: 20218153Slstewart * 1. Redistributions of source code must retain the above copyright 21218153Slstewart * notice, this list of conditions and the following disclaimer. 22218153Slstewart * 2. Redistributions in binary form must reproduce the above copyright 23218153Slstewart * notice, this list of conditions and the following disclaimer in the 24218153Slstewart * documentation and/or other materials provided with the distribution. 25218153Slstewart * 26218153Slstewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27218153Slstewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28218153Slstewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29218153Slstewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30218153Slstewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31218153Slstewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32218153Slstewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33218153Slstewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34218153Slstewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35218153Slstewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36218153Slstewart * SUCH DAMAGE. 37218153Slstewart */ 38218153Slstewart 39218153Slstewart/* 40218153Slstewart * An implementation of the Hamilton Institute's delay-based congestion control 41218153Slstewart * algorithm for FreeBSD, based on "A strategy for fair coexistence of loss and 42218153Slstewart * delay-based congestion control algorithms," by L. Budzisz, R. Stanojevic, R. 43218153Slstewart * Shorten, and F. Baker, IEEE Commun. Lett., vol. 13, no. 7, pp. 555--557, Jul. 44218153Slstewart * 2009. 45218153Slstewart * 46218153Slstewart * Originally released as part of the NewTCP research project at Swinburne 47220560Slstewart * University of Technology's Centre for Advanced Internet Architectures, 48220560Slstewart * Melbourne, Australia, which was made possible in part by a grant from the 49220560Slstewart * Cisco University Research Program Fund at Community Foundation Silicon 50220560Slstewart * Valley. More details are available at: 51218153Slstewart * http://caia.swin.edu.au/urp/newtcp/ 52218153Slstewart */ 53218153Slstewart 54218153Slstewart#include <sys/cdefs.h> 55218153Slstewart__FBSDID("$FreeBSD: releng/10.2/sys/netinet/cc/cc_hd.c 220560 2011-04-12 08:13:18Z lstewart $"); 56218153Slstewart 57218153Slstewart#include <sys/param.h> 58218153Slstewart#include <sys/kernel.h> 59218153Slstewart#include <sys/khelp.h> 60218153Slstewart#include <sys/limits.h> 61218153Slstewart#include <sys/malloc.h> 62218153Slstewart#include <sys/module.h> 63218153Slstewart#include <sys/queue.h> 64218153Slstewart#include <sys/socket.h> 65218153Slstewart#include <sys/socketvar.h> 66218153Slstewart#include <sys/sysctl.h> 67218153Slstewart#include <sys/systm.h> 68218153Slstewart 69218153Slstewart#include <net/if.h> 70218153Slstewart#include <net/vnet.h> 71218153Slstewart 72218153Slstewart#include <netinet/cc.h> 73218153Slstewart#include <netinet/tcp_seq.h> 74218153Slstewart#include <netinet/tcp_timer.h> 75218153Slstewart#include <netinet/tcp_var.h> 76218153Slstewart 77218153Slstewart#include <netinet/cc/cc_module.h> 78218153Slstewart 79218153Slstewart#include <netinet/khelp/h_ertt.h> 80218153Slstewart 81218153Slstewart#define CAST_PTR_INT(X) (*((int*)(X))) 82218153Slstewart 83218153Slstewart/* Largest possible number returned by random(). */ 84218153Slstewart#define RANDOM_MAX INT_MAX 85218153Slstewart 86218153Slstewartstatic void hd_ack_received(struct cc_var *ccv, uint16_t ack_type); 87218153Slstewartstatic int hd_mod_init(void); 88218153Slstewart 89218153Slstewartstatic int ertt_id; 90218153Slstewart 91218153Slstewartstatic VNET_DEFINE(uint32_t, hd_qthresh) = 20; 92218153Slstewartstatic VNET_DEFINE(uint32_t, hd_qmin) = 5; 93218153Slstewartstatic VNET_DEFINE(uint32_t, hd_pmax) = 5; 94218153Slstewart#define V_hd_qthresh VNET(hd_qthresh) 95218153Slstewart#define V_hd_qmin VNET(hd_qmin) 96218153Slstewart#define V_hd_pmax VNET(hd_pmax) 97218153Slstewart 98218153Slstewartstruct cc_algo hd_cc_algo = { 99218153Slstewart .name = "hd", 100218153Slstewart .ack_received = hd_ack_received, 101218153Slstewart .mod_init = hd_mod_init 102218153Slstewart}; 103218153Slstewart 104218153Slstewart/* 105218153Slstewart * Hamilton backoff function. Returns 1 if we should backoff or 0 otherwise. 106218153Slstewart */ 107218153Slstewartstatic __inline int 108218153Slstewartshould_backoff(int qdly, int maxqdly) 109218153Slstewart{ 110218153Slstewart unsigned long p; 111218153Slstewart 112218153Slstewart if (qdly < V_hd_qthresh) { 113218153Slstewart p = (((RANDOM_MAX / 100) * V_hd_pmax) / 114218153Slstewart (V_hd_qthresh - V_hd_qmin)) * (qdly - V_hd_qmin); 115218153Slstewart } else { 116218153Slstewart if (qdly > V_hd_qthresh) 117218153Slstewart p = (((RANDOM_MAX / 100) * V_hd_pmax) / 118218153Slstewart (maxqdly - V_hd_qthresh)) * (maxqdly - qdly); 119218153Slstewart else 120218153Slstewart p = (RANDOM_MAX / 100) * V_hd_pmax; 121218153Slstewart } 122218153Slstewart 123218153Slstewart return (random() < p); 124218153Slstewart} 125218153Slstewart 126218153Slstewart/* 127218153Slstewart * If the ack type is CC_ACK, and the inferred queueing delay is greater than 128218153Slstewart * the Qmin threshold, cwnd is reduced probabilistically. When backing off due 129218153Slstewart * to delay, HD behaves like NewReno when an ECN signal is received. HD behaves 130218153Slstewart * as NewReno in all other circumstances. 131218153Slstewart */ 132218153Slstewartstatic void 133218153Slstewarthd_ack_received(struct cc_var *ccv, uint16_t ack_type) 134218153Slstewart{ 135218153Slstewart struct ertt *e_t; 136218153Slstewart int qdly; 137218153Slstewart 138218153Slstewart if (ack_type == CC_ACK) { 139218153Slstewart e_t = khelp_get_osd(CCV(ccv, osd), ertt_id); 140218153Slstewart 141218153Slstewart if (e_t->rtt && e_t->minrtt && V_hd_qthresh > 0) { 142218153Slstewart qdly = e_t->rtt - e_t->minrtt; 143218153Slstewart 144218153Slstewart if (qdly > V_hd_qmin && 145218153Slstewart !IN_RECOVERY(CCV(ccv, t_flags))) { 146218153Slstewart /* Probabilistic backoff of cwnd. */ 147218153Slstewart if (should_backoff(qdly, 148218153Slstewart e_t->maxrtt - e_t->minrtt)) { 149218153Slstewart /* 150218153Slstewart * Update cwnd and ssthresh update to 151218153Slstewart * half cwnd and behave like an ECN (ie 152218153Slstewart * not a packet loss). 153218153Slstewart */ 154218153Slstewart newreno_cc_algo.cong_signal(ccv, 155218153Slstewart CC_ECN); 156218153Slstewart return; 157218153Slstewart } 158218153Slstewart } 159218153Slstewart } 160218153Slstewart } 161218153Slstewart newreno_cc_algo.ack_received(ccv, ack_type); /* As for NewReno. */ 162218153Slstewart} 163218153Slstewart 164218153Slstewartstatic int 165218153Slstewarthd_mod_init(void) 166218153Slstewart{ 167218153Slstewart 168218153Slstewart ertt_id = khelp_get_id("ertt"); 169218153Slstewart if (ertt_id <= 0) { 170218153Slstewart printf("%s: h_ertt module not found\n", __func__); 171218153Slstewart return (ENOENT); 172218153Slstewart } 173218153Slstewart 174218153Slstewart hd_cc_algo.after_idle = newreno_cc_algo.after_idle; 175218153Slstewart hd_cc_algo.cong_signal = newreno_cc_algo.cong_signal; 176218153Slstewart hd_cc_algo.post_recovery = newreno_cc_algo.post_recovery; 177218153Slstewart 178218153Slstewart return (0); 179218153Slstewart} 180218153Slstewart 181218153Slstewartstatic int 182218153Slstewarthd_pmax_handler(SYSCTL_HANDLER_ARGS) 183218153Slstewart{ 184218153Slstewart int error; 185218153Slstewart uint32_t new; 186218153Slstewart 187218153Slstewart new = V_hd_pmax; 188218153Slstewart error = sysctl_handle_int(oidp, &new, 0, req); 189218153Slstewart if (error == 0 && req->newptr != NULL) { 190218153Slstewart if (CAST_PTR_INT(req->newptr) == 0 || 191218153Slstewart CAST_PTR_INT(req->newptr) > 100) 192218153Slstewart error = EINVAL; 193218153Slstewart else 194218153Slstewart V_hd_pmax = new; 195218153Slstewart } 196218153Slstewart 197218153Slstewart return (error); 198218153Slstewart} 199218153Slstewart 200218153Slstewartstatic int 201218153Slstewarthd_qmin_handler(SYSCTL_HANDLER_ARGS) 202218153Slstewart{ 203218153Slstewart int error; 204218153Slstewart uint32_t new; 205218153Slstewart 206218153Slstewart new = V_hd_qmin; 207218153Slstewart error = sysctl_handle_int(oidp, &new, 0, req); 208218153Slstewart if (error == 0 && req->newptr != NULL) { 209218153Slstewart if (CAST_PTR_INT(req->newptr) > V_hd_qthresh) 210218153Slstewart error = EINVAL; 211218153Slstewart else 212218153Slstewart V_hd_qmin = new; 213218153Slstewart } 214218153Slstewart 215218153Slstewart return (error); 216218153Slstewart} 217218153Slstewart 218218153Slstewartstatic int 219218153Slstewarthd_qthresh_handler(SYSCTL_HANDLER_ARGS) 220218153Slstewart{ 221218153Slstewart int error; 222218153Slstewart uint32_t new; 223218153Slstewart 224218153Slstewart new = V_hd_qthresh; 225218153Slstewart error = sysctl_handle_int(oidp, &new, 0, req); 226218153Slstewart if (error == 0 && req->newptr != NULL) { 227218153Slstewart if (CAST_PTR_INT(req->newptr) < 1 || 228218153Slstewart CAST_PTR_INT(req->newptr) < V_hd_qmin) 229218153Slstewart error = EINVAL; 230218153Slstewart else 231218153Slstewart V_hd_qthresh = new; 232218153Slstewart } 233218153Slstewart 234218153Slstewart return (error); 235218153Slstewart} 236218153Slstewart 237218153SlstewartSYSCTL_DECL(_net_inet_tcp_cc_hd); 238218153SlstewartSYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, hd, CTLFLAG_RW, NULL, 239218153Slstewart "Hamilton delay-based congestion control related settings"); 240218153Slstewart 241218153SlstewartSYSCTL_VNET_PROC(_net_inet_tcp_cc_hd, OID_AUTO, queue_threshold, 242218153Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(hd_qthresh), 20, &hd_qthresh_handler, 243218153Slstewart "IU", "queueing congestion threshold (qth) in ticks"); 244218153Slstewart 245218153SlstewartSYSCTL_VNET_PROC(_net_inet_tcp_cc_hd, OID_AUTO, pmax, 246218153Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(hd_pmax), 5, &hd_pmax_handler, 247218153Slstewart "IU", "per packet maximum backoff probability as a percentage"); 248218153Slstewart 249218153SlstewartSYSCTL_VNET_PROC(_net_inet_tcp_cc_hd, OID_AUTO, queue_min, 250218153Slstewart CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(hd_qmin), 5, &hd_qmin_handler, 251218153Slstewart "IU", "minimum queueing delay threshold (qmin) in ticks"); 252218153Slstewart 253218153SlstewartDECLARE_CC_MODULE(hd, &hd_cc_algo); 254218153SlstewartMODULE_DEPEND(hd, ertt, 1, 1, 1); 255