cc_newreno.c revision 215166
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 215166 2010-11-12 06:41:55Z lstewart $"); 52 53#include <sys/param.h> 54#include <sys/kernel.h> 55#include <sys/module.h> 56#include <sys/socket.h> 57#include <sys/socketvar.h> 58#include <sys/sysctl.h> 59 60#include <net/if.h> 61#include <net/if_var.h> 62 63#include <netinet/cc.h> 64#include <netinet/in.h> 65#include <netinet/in_pcb.h> 66#include <netinet/tcp_seq.h> 67#include <netinet/tcp_var.h> 68 69#include <netinet/cc/cc_module.h> 70 71void newreno_ack_received(struct cc_var *ccv, uint16_t type); 72void newreno_cong_signal(struct cc_var *ccv, uint32_t type); 73void newreno_post_recovery(struct cc_var *ccv); 74void newreno_after_idle(struct cc_var *ccv); 75 76struct cc_algo newreno_cc_algo = { 77 .name = "newreno", 78 .ack_received = newreno_ack_received, 79 .cong_signal = newreno_cong_signal, 80 .post_recovery = newreno_post_recovery, 81 .after_idle = newreno_after_idle 82}; 83 84/* 85 * Increase cwnd on receipt of a successful ACK: 86 * if cwnd <= ssthresh, increases by 1 MSS per ACK 87 * if cwnd > ssthresh, increase by ~1 MSS per RTT 88 */ 89void 90newreno_ack_received(struct cc_var *ccv, uint16_t type) 91{ 92 if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && 93 (ccv->flags & CCF_CWND_LIMITED)) { 94 u_int cw = CCV(ccv, snd_cwnd); 95 u_int incr = CCV(ccv, t_maxseg); 96 97 /* 98 * Regular in-order ACK, open the congestion window. 99 * Method depends on which congestion control state we're 100 * in (slow start or cong avoid) and if ABC (RFC 3465) is 101 * enabled. 102 * 103 * slow start: cwnd <= ssthresh 104 * cong avoid: cwnd > ssthresh 105 * 106 * slow start and ABC (RFC 3465): 107 * Grow cwnd exponentially by the amount of data 108 * ACKed capping the max increment per ACK to 109 * (abc_l_var * maxseg) bytes. 110 * 111 * slow start without ABC (RFC 5681): 112 * Grow cwnd exponentially by maxseg per ACK. 113 * 114 * cong avoid and ABC (RFC 3465): 115 * Grow cwnd linearly by maxseg per RTT for each 116 * cwnd worth of ACKed data. 117 * 118 * cong avoid without ABC (RFC 5681): 119 * Grow cwnd linearly by approximately maxseg per RTT using 120 * maxseg^2 / cwnd per ACK as the increment. 121 * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to 122 * avoid capping cwnd. 123 */ 124 if (cw > CCV(ccv, snd_ssthresh)) { 125 if (V_tcp_do_rfc3465) { 126 if (ccv->flags & CCF_ABC_SENTAWND) 127 ccv->flags &= ~CCF_ABC_SENTAWND; 128 else 129 incr = 0; 130 } else 131 incr = max((incr * incr / cw), 1); 132 } else if (V_tcp_do_rfc3465) { 133 /* 134 * In slow-start with ABC enabled and no RTO in sight? 135 * (Must not use abc_l_var > 1 if slow starting after 136 * an RTO. On RTO, snd_nxt = snd_una, so the 137 * snd_nxt == snd_max check is sufficient to 138 * handle this). 139 * 140 * XXXLAS: Find a way to signal SS after RTO that 141 * doesn't rely on tcpcb vars. 142 */ 143 if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max)) 144 incr = min(ccv->bytes_this_ack, 145 V_tcp_abc_l_var * CCV(ccv, t_maxseg)); 146 else 147 incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg)); 148 } 149 /* ABC is on by default, so incr equals 0 frequently. */ 150 if (incr > 0) 151 CCV(ccv, snd_cwnd) = min(cw + incr, 152 TCP_MAXWIN << CCV(ccv, snd_scale)); 153 } 154} 155 156/* 157 * manage congestion signals 158 */ 159void 160newreno_cong_signal(struct cc_var *ccv, uint32_t type) 161{ 162 u_int win; 163 164 win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) * 165 CCV(ccv, t_maxseg); 166 167 switch (type) { 168 case CC_NDUPACK: 169 if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { 170 if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) 171 CCV(ccv, snd_ssthresh) = win; 172 ENTER_RECOVERY(CCV(ccv, t_flags)); 173 } 174 break; 175 case CC_ECN: 176 if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { 177 CCV(ccv, snd_ssthresh) = win; 178 CCV(ccv, snd_cwnd) = win; 179 ENTER_CONGRECOVERY(CCV(ccv, t_flags)); 180 } 181 break; 182 } 183} 184 185/* 186 * decrease the cwnd in response to packet loss or a transmit timeout. 187 * th can be null, in which case cwnd will be set according to reno instead 188 * of new reno. 189 */ 190void 191newreno_post_recovery(struct cc_var *ccv) 192{ 193 if (IN_FASTRECOVERY(CCV(ccv, t_flags))) { 194 /* 195 * Fast recovery will conclude after returning from this 196 * function. Window inflation should have left us with 197 * approximately snd_ssthresh outstanding data. But in case we 198 * would be inclined to send a burst, better to do it via the 199 * slow start mechanism. 200 * 201 * XXXLAS: Find a way to do this without needing curack 202 */ 203 if (SEQ_GT(ccv->curack + CCV(ccv, snd_ssthresh), 204 CCV(ccv, snd_max))) 205 CCV(ccv, snd_cwnd) = CCV(ccv, snd_max) - 206 ccv->curack + CCV(ccv, t_maxseg); 207 else 208 CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); 209 } 210} 211 212/* 213 * if a connection has been idle for a while and more data is ready to be sent, 214 * reset cwnd 215 */ 216void 217newreno_after_idle(struct cc_var *ccv) 218{ 219 /* 220 * We have been idle for "a while" and no acks are expected to clock out 221 * any data we send -- slow start to get ack "clock" running again. 222 */ 223 if (V_tcp_do_rfc3390) 224 CCV(ccv, snd_cwnd) = min(4 * CCV(ccv, t_maxseg), 225 max(2 * CCV(ccv, t_maxseg), 4380)); 226 else 227 CCV(ccv, snd_cwnd) = CCV(ccv, t_maxseg) * 2; 228} 229 230 231DECLARE_CC_MODULE(newreno, &newreno_cc_algo); 232