cc_newreno.c revision 218167
1/*- 2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 3 * The Regents of the University of California. 4 * Copyright (c) 2007-2008,2010 5 * Swinburne University of Technology, Melbourne, Australia. 6 * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org> 7 * Copyright (c) 2010 The FreeBSD Foundation 8 * All rights reserved. 9 * 10 * This software was developed at the Centre for Advanced Internet 11 * Architectures, Swinburne University, by Lawrence Stewart, James Healy and 12 * David Hayes, made possible in part by a grant from the Cisco University 13 * Research Program Fund at Community Foundation Silicon Valley. 14 * 15 * Portions of this software were developed at the Centre for Advanced 16 * Internet Architectures, Swinburne University of Technology, Melbourne, 17 * Australia by David Hayes under sponsorship from the FreeBSD Foundation. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in the 26 * documentation and/or other materials provided with the distribution. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41/* 42 * This software was first released in 2007 by James Healy and Lawrence Stewart 43 * whilst working on the NewTCP research project at Swinburne University's 44 * Centre for Advanced Internet Architectures, Melbourne, Australia, which was 45 * made possible in part by a grant from the Cisco University Research Program 46 * Fund at Community Foundation Silicon Valley. More details are available at: 47 * http://caia.swin.edu.au/urp/newtcp/ 48 */ 49 50#include <sys/cdefs.h> 51__FBSDID("$FreeBSD: head/sys/netinet/cc/cc_newreno.c 218167 2011-02-01 13:32:27Z lstewart $"); 52 53#include <sys/param.h> 54#include <sys/kernel.h> 55#include <sys/malloc.h> 56#include <sys/module.h> 57#include <sys/socket.h> 58#include <sys/socketvar.h> 59#include <sys/sysctl.h> 60#include <sys/systm.h> 61 62#include <net/vnet.h> 63 64#include <netinet/cc.h> 65#include <netinet/tcp_seq.h> 66#include <netinet/tcp_var.h> 67 68#include <netinet/cc/cc_module.h> 69 70static void newreno_ack_received(struct cc_var *ccv, uint16_t type); 71static void newreno_after_idle(struct cc_var *ccv); 72static void newreno_cong_signal(struct cc_var *ccv, uint32_t type); 73static void newreno_post_recovery(struct cc_var *ccv); 74 75struct cc_algo newreno_cc_algo = { 76 .name = "newreno", 77 .ack_received = newreno_ack_received, 78 .after_idle = newreno_after_idle, 79 .cong_signal = newreno_cong_signal, 80 .post_recovery = newreno_post_recovery, 81}; 82 83static void 84newreno_ack_received(struct cc_var *ccv, uint16_t type) 85{ 86 if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && 87 (ccv->flags & CCF_CWND_LIMITED)) { 88 u_int cw = CCV(ccv, snd_cwnd); 89 u_int incr = CCV(ccv, t_maxseg); 90 91 /* 92 * Regular in-order ACK, open the congestion window. 93 * Method depends on which congestion control state we're 94 * in (slow start or cong avoid) and if ABC (RFC 3465) is 95 * enabled. 96 * 97 * slow start: cwnd <= ssthresh 98 * cong avoid: cwnd > ssthresh 99 * 100 * slow start and ABC (RFC 3465): 101 * Grow cwnd exponentially by the amount of data 102 * ACKed capping the max increment per ACK to 103 * (abc_l_var * maxseg) bytes. 104 * 105 * slow start without ABC (RFC 5681): 106 * Grow cwnd exponentially by maxseg per ACK. 107 * 108 * cong avoid and ABC (RFC 3465): 109 * Grow cwnd linearly by maxseg per RTT for each 110 * cwnd worth of ACKed data. 111 * 112 * cong avoid without ABC (RFC 5681): 113 * Grow cwnd linearly by approximately maxseg per RTT using 114 * maxseg^2 / cwnd per ACK as the increment. 115 * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to 116 * avoid capping cwnd. 117 */ 118 if (cw > CCV(ccv, snd_ssthresh)) { 119 if (V_tcp_do_rfc3465) { 120 if (ccv->flags & CCF_ABC_SENTAWND) 121 ccv->flags &= ~CCF_ABC_SENTAWND; 122 else 123 incr = 0; 124 } else 125 incr = max((incr * incr / cw), 1); 126 } else if (V_tcp_do_rfc3465) { 127 /* 128 * In slow-start with ABC enabled and no RTO in sight? 129 * (Must not use abc_l_var > 1 if slow starting after 130 * an RTO. On RTO, snd_nxt = snd_una, so the 131 * snd_nxt == snd_max check is sufficient to 132 * handle this). 133 * 134 * XXXLAS: Find a way to signal SS after RTO that 135 * doesn't rely on tcpcb vars. 136 */ 137 if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max)) 138 incr = min(ccv->bytes_this_ack, 139 V_tcp_abc_l_var * CCV(ccv, t_maxseg)); 140 else 141 incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg)); 142 } 143 /* ABC is on by default, so incr equals 0 frequently. */ 144 if (incr > 0) 145 CCV(ccv, snd_cwnd) = min(cw + incr, 146 TCP_MAXWIN << CCV(ccv, snd_scale)); 147 } 148} 149 150static void 151newreno_after_idle(struct cc_var *ccv) 152{ 153 int rw; 154 155 /* 156 * If we've been idle for more than one retransmit timeout the old 157 * congestion window is no longer current and we have to reduce it to 158 * the restart window before we can transmit again. 159 * 160 * The restart window is the initial window or the last CWND, whichever 161 * is smaller. 162 * 163 * This is done to prevent us from flooding the path with a full CWND at 164 * wirespeed, overloading router and switch buffers along the way. 165 * 166 * See RFC5681 Section 4.1. "Restarting Idle Connections". 167 */ 168 if (V_tcp_do_rfc3390) 169 rw = min(4 * CCV(ccv, t_maxseg), 170 max(2 * CCV(ccv, t_maxseg), 4380)); 171 else 172 rw = CCV(ccv, t_maxseg) * 2; 173 174 CCV(ccv, snd_cwnd) = min(rw, CCV(ccv, snd_cwnd)); 175} 176 177/* 178 * Perform any necessary tasks before we enter congestion recovery. 179 */ 180static void 181newreno_cong_signal(struct cc_var *ccv, uint32_t type) 182{ 183 u_int win; 184 185 /* Catch algos which mistakenly leak private signal types. */ 186 KASSERT((type & CC_SIGPRIVMASK) == 0, 187 ("%s: congestion signal type 0x%08x is private\n", __func__, type)); 188 189 win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) * 190 CCV(ccv, t_maxseg); 191 192 switch (type) { 193 case CC_NDUPACK: 194 if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { 195 if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) 196 CCV(ccv, snd_ssthresh) = win; 197 ENTER_RECOVERY(CCV(ccv, t_flags)); 198 } 199 break; 200 case CC_ECN: 201 if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { 202 CCV(ccv, snd_ssthresh) = win; 203 CCV(ccv, snd_cwnd) = win; 204 ENTER_CONGRECOVERY(CCV(ccv, t_flags)); 205 } 206 break; 207 } 208} 209 210/* 211 * Perform any necessary tasks before we exit congestion recovery. 212 */ 213static void 214newreno_post_recovery(struct cc_var *ccv) 215{ 216 if (IN_FASTRECOVERY(CCV(ccv, t_flags))) { 217 /* 218 * Fast recovery will conclude after returning from this 219 * function. Window inflation should have left us with 220 * approximately snd_ssthresh outstanding data. But in case we 221 * would be inclined to send a burst, better to do it via the 222 * slow start mechanism. 223 * 224 * XXXLAS: Find a way to do this without needing curack 225 */ 226 if (SEQ_GT(ccv->curack + CCV(ccv, snd_ssthresh), 227 CCV(ccv, snd_max))) 228 CCV(ccv, snd_cwnd) = CCV(ccv, snd_max) - 229 ccv->curack + CCV(ccv, t_maxseg); 230 else 231 CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); 232 } 233} 234 235 236DECLARE_CC_MODULE(newreno, &newreno_cc_algo); 237