/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2009-20104* Swinburne University of Technology, Melbourne, Australia5* Copyright (c) 2010 Lawrence Stewart <[email protected]>6* Copyright (c) 2010-2011 The FreeBSD Foundation7* All rights reserved.8*9* This software was developed at the Centre for Advanced Internet10* Architectures, Swinburne University of Technology, by David Hayes and11* Lawrence Stewart, made possible in part by a grant from the Cisco University12* Research Program Fund at Community Foundation Silicon Valley.13*14* Portions of this software were developed at the Centre for Advanced Internet15* Architectures, Swinburne University of Technology, Melbourne, Australia by16* David Hayes under sponsorship from the FreeBSD Foundation.17*18* Redistribution and use in source and binary forms, with or without19* modification, are permitted provided that the following conditions20* are met:21* 1. Redistributions of source code must retain the above copyright22* notice, this list of conditions and the following disclaimer.23* 2. Redistributions in binary form must reproduce the above copyright24* notice, this list of conditions and the following disclaimer in the25* documentation and/or other materials provided with the distribution.26*27* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND28* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE29* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE30* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE31* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL32* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS33* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)34* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT35* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY36* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF37* SUCH DAMAGE.38*/3940/*41* An implementation of the Hamilton Institute's delay-based congestion control42* algorithm for FreeBSD, based on "A strategy for fair coexistence of loss and43* delay-based congestion control algorithms," by L. Budzisz, R. Stanojevic, R.44* Shorten, and F. Baker, IEEE Commun. Lett., vol. 13, no. 7, pp. 555--557, Jul.45* 2009.46*47* Originally released as part of the NewTCP research project at Swinburne48* University of Technology's Centre for Advanced Internet Architectures,49* Melbourne, Australia, which was made possible in part by a grant from the50* Cisco University Research Program Fund at Community Foundation Silicon51* Valley. More details are available at:52* http://caia.swin.edu.au/urp/newtcp/53*/5455#include <sys/param.h>56#include <sys/kernel.h>57#include <sys/khelp.h>58#include <sys/limits.h>59#include <sys/malloc.h>60#include <sys/module.h>61#include <sys/prng.h>62#include <sys/queue.h>63#include <sys/socket.h>64#include <sys/socketvar.h>65#include <sys/sysctl.h>66#include <sys/systm.h>6768#include <net/vnet.h>6970#include <netinet/in.h>71#include <netinet/in_pcb.h>72#include <netinet/tcp_seq.h>73#include <netinet/tcp_timer.h>74#include <netinet/tcp_var.h>75#include <netinet/cc/cc.h>76#include <netinet/cc/cc_module.h>7778#include <netinet/khelp/h_ertt.h>7980/* Largest possible number returned by prng32(). */81#define RANDOM_MAX UINT32_MAX8283static void hd_ack_received(struct cc_var *ccv, ccsignal_t ack_type);84static int hd_mod_init(void);85static size_t hd_data_sz(void);8687static int ertt_id;8889VNET_DEFINE_STATIC(uint32_t, hd_qthresh) = 20;90VNET_DEFINE_STATIC(uint32_t, hd_qmin) = 5;91VNET_DEFINE_STATIC(uint32_t, hd_pmax) = 5;92#define V_hd_qthresh VNET(hd_qthresh)93#define V_hd_qmin VNET(hd_qmin)94#define V_hd_pmax VNET(hd_pmax)9596struct cc_algo hd_cc_algo = {97.name = "hd",98.ack_received = hd_ack_received,99.mod_init = hd_mod_init,100.cc_data_sz = hd_data_sz,101.after_idle = newreno_cc_after_idle,102.cong_signal = newreno_cc_cong_signal,103.post_recovery = newreno_cc_post_recovery,104};105106static size_t107hd_data_sz(void)108{109return (0);110}111112/*113* Hamilton backoff function. Returns 1 if we should backoff or 0 otherwise.114*/115static __inline int116should_backoff(int qdly, int maxqdly)117{118unsigned long p;119120if (qdly < V_hd_qthresh) {121p = (((RANDOM_MAX / 100) * V_hd_pmax) /122(V_hd_qthresh - V_hd_qmin)) * (qdly - V_hd_qmin);123} else {124if (qdly > V_hd_qthresh)125p = (((RANDOM_MAX / 100) * V_hd_pmax) /126(maxqdly - V_hd_qthresh)) * (maxqdly - qdly);127else128p = (RANDOM_MAX / 100) * V_hd_pmax;129}130131return (prng32() < p);132}133134/*135* If the ack type is CC_ACK, and the inferred queueing delay is greater than136* the Qmin threshold, cwnd is reduced probabilistically. When backing off due137* to delay, HD behaves like NewReno when an ECN signal is received. HD behaves138* as NewReno in all other circumstances.139*/140static void141hd_ack_received(struct cc_var *ccv, ccsignal_t ack_type)142{143struct ertt *e_t;144int qdly;145146if (ack_type == CC_ACK) {147e_t = khelp_get_osd(&CCV(ccv, t_osd), ertt_id);148149if (e_t->rtt && e_t->minrtt && V_hd_qthresh > 0) {150qdly = e_t->rtt - e_t->minrtt;151152if (qdly > V_hd_qmin &&153!IN_RECOVERY(CCV(ccv, t_flags))) {154/* Probabilistic backoff of cwnd. */155if (should_backoff(qdly,156e_t->maxrtt - e_t->minrtt)) {157/*158* Update cwnd and ssthresh update to159* half cwnd and behave like an ECN (ie160* not a packet loss).161*/162newreno_cc_cong_signal(ccv,163CC_ECN);164return;165}166}167}168}169newreno_cc_ack_received(ccv, ack_type);170}171172static int173hd_mod_init(void)174{175176ertt_id = khelp_get_id("ertt");177if (ertt_id <= 0) {178printf("%s: h_ertt module not found\n", __func__);179return (ENOENT);180}181return (0);182}183184static int185hd_pmax_handler(SYSCTL_HANDLER_ARGS)186{187int error;188uint32_t new;189190new = V_hd_pmax;191error = sysctl_handle_int(oidp, &new, 0, req);192if (error == 0 && req->newptr != NULL) {193if (new == 0 || new > 100)194error = EINVAL;195else196V_hd_pmax = new;197}198199return (error);200}201202static int203hd_qmin_handler(SYSCTL_HANDLER_ARGS)204{205int error;206uint32_t new;207208new = V_hd_qmin;209error = sysctl_handle_int(oidp, &new, 0, req);210if (error == 0 && req->newptr != NULL) {211if (new > V_hd_qthresh)212error = EINVAL;213else214V_hd_qmin = new;215}216217return (error);218}219220static int221hd_qthresh_handler(SYSCTL_HANDLER_ARGS)222{223int error;224uint32_t new;225226new = V_hd_qthresh;227error = sysctl_handle_int(oidp, &new, 0, req);228if (error == 0 && req->newptr != NULL) {229if (new == 0 || new < V_hd_qmin)230error = EINVAL;231else232V_hd_qthresh = new;233}234235return (error);236}237238SYSCTL_DECL(_net_inet_tcp_cc_hd);239SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, hd, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,240"Hamilton delay-based congestion control related settings");241242SYSCTL_PROC(_net_inet_tcp_cc_hd, OID_AUTO, queue_threshold,243CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,244&VNET_NAME(hd_qthresh), 20, &hd_qthresh_handler, "IU",245"queueing congestion threshold (qth) in ticks");246247SYSCTL_PROC(_net_inet_tcp_cc_hd, OID_AUTO, pmax,248CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,249&VNET_NAME(hd_pmax), 5, &hd_pmax_handler, "IU",250"per packet maximum backoff probability as a percentage");251252SYSCTL_PROC(_net_inet_tcp_cc_hd, OID_AUTO, queue_min,253CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,254&VNET_NAME(hd_qmin), 5, &hd_qmin_handler, "IU",255"minimum queueing delay threshold (qmin) in ticks");256257DECLARE_CC_MODULE(hd, &hd_cc_algo);258MODULE_VERSION(hd, 2);259MODULE_DEPEND(hd, ertt, 1, 1, 1);260261262