1dbc42409SLawrence Stewart /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4dbc42409SLawrence Stewart * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
5dbc42409SLawrence Stewart * The Regents of the University of California.
6370efe5aSLawrence Stewart * Copyright (c) 2007-2008,2010,2014
7dbc42409SLawrence Stewart * Swinburne University of Technology, Melbourne, Australia.
8dbc42409SLawrence Stewart * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
9dbc42409SLawrence Stewart * Copyright (c) 2010 The FreeBSD Foundation
10dbc42409SLawrence Stewart * All rights reserved.
11dbc42409SLawrence Stewart *
12dbc42409SLawrence Stewart * This software was developed at the Centre for Advanced Internet
13891b8ed4SLawrence Stewart * Architectures, Swinburne University of Technology, by Lawrence Stewart, James
14891b8ed4SLawrence Stewart * Healy and David Hayes, made possible in part by a grant from the Cisco
15891b8ed4SLawrence Stewart * University Research Program Fund at Community Foundation Silicon Valley.
16dbc42409SLawrence Stewart *
17dbc42409SLawrence Stewart * Portions of this software were developed at the Centre for Advanced
18dbc42409SLawrence Stewart * Internet Architectures, Swinburne University of Technology, Melbourne,
19dbc42409SLawrence Stewart * Australia by David Hayes under sponsorship from the FreeBSD Foundation.
20dbc42409SLawrence Stewart *
21dbc42409SLawrence Stewart * Redistribution and use in source and binary forms, with or without
22dbc42409SLawrence Stewart * modification, are permitted provided that the following conditions
23dbc42409SLawrence Stewart * are met:
24dbc42409SLawrence Stewart * 1. Redistributions of source code must retain the above copyright
25dbc42409SLawrence Stewart * notice, this list of conditions and the following disclaimer.
26dbc42409SLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright
27dbc42409SLawrence Stewart * notice, this list of conditions and the following disclaimer in the
28dbc42409SLawrence Stewart * documentation and/or other materials provided with the distribution.
29dbc42409SLawrence Stewart *
30dbc42409SLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
31dbc42409SLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32dbc42409SLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33dbc42409SLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
34dbc42409SLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35dbc42409SLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36dbc42409SLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37dbc42409SLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38dbc42409SLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39dbc42409SLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40dbc42409SLawrence Stewart * SUCH DAMAGE.
41dbc42409SLawrence Stewart */
42dbc42409SLawrence Stewart
43dbc42409SLawrence Stewart /*
44dbc42409SLawrence Stewart * This software was first released in 2007 by James Healy and Lawrence Stewart
45891b8ed4SLawrence Stewart * whilst working on the NewTCP research project at Swinburne University of
46891b8ed4SLawrence Stewart * Technology's Centre for Advanced Internet Architectures, Melbourne,
47891b8ed4SLawrence Stewart * Australia, which was made possible in part by a grant from the Cisco
48891b8ed4SLawrence Stewart * University Research Program Fund at Community Foundation Silicon Valley.
49891b8ed4SLawrence Stewart * More details are available at:
50dbc42409SLawrence Stewart * http://caia.swin.edu.au/urp/newtcp/
51370efe5aSLawrence Stewart *
52370efe5aSLawrence Stewart * Dec 2014 garmitage@swin.edu.au
53370efe5aSLawrence Stewart * Borrowed code fragments from cc_cdg.c to add modifiable beta
54370efe5aSLawrence Stewart * via sysctls.
55370efe5aSLawrence Stewart *
56dbc42409SLawrence Stewart */
57dbc42409SLawrence Stewart
58dbc42409SLawrence Stewart #include <sys/param.h>
59dbc42409SLawrence Stewart #include <sys/kernel.h>
6074a5a194SLawrence Stewart #include <sys/malloc.h>
61dbc42409SLawrence Stewart #include <sys/module.h>
62dbc42409SLawrence Stewart #include <sys/socket.h>
634e4c84f8SRandall Stewart #include <sys/lock.h>
644e4c84f8SRandall Stewart #include <sys/mutex.h>
65dbc42409SLawrence Stewart #include <sys/socketvar.h>
66dbc42409SLawrence Stewart #include <sys/sysctl.h>
6774a5a194SLawrence Stewart #include <sys/systm.h>
68dbc42409SLawrence Stewart
6974a5a194SLawrence Stewart #include <net/vnet.h>
70dbc42409SLawrence Stewart
71b8d60729SRandall Stewart #include <net/route.h>
72b8d60729SRandall Stewart #include <net/route/nhop.h>
73b8d60729SRandall Stewart
74b8d60729SRandall Stewart #include <netinet/in_pcb.h>
754e4c84f8SRandall Stewart #include <netinet/in.h>
764e4c84f8SRandall Stewart #include <netinet/in_pcb.h>
772de3e790SGleb Smirnoff #include <netinet/tcp.h>
78dbc42409SLawrence Stewart #include <netinet/tcp_seq.h>
79dbc42409SLawrence Stewart #include <netinet/tcp_var.h>
804e4c84f8SRandall Stewart #include <netinet/tcp_log_buf.h>
814e4c84f8SRandall Stewart #include <netinet/tcp_hpts.h>
824644fda3SGleb Smirnoff #include <netinet/cc/cc.h>
83dbc42409SLawrence Stewart #include <netinet/cc/cc_module.h>
84370efe5aSLawrence Stewart #include <netinet/cc/cc_newreno.h>
85dbc42409SLawrence Stewart
869891578aSLawrence Stewart static void newreno_cb_destroy(struct cc_var *ccv);
87f74352fbSRichard Scheffenegger static void newreno_ack_received(struct cc_var *ccv, ccsignal_t type);
8874a5a194SLawrence Stewart static void newreno_after_idle(struct cc_var *ccv);
89f74352fbSRichard Scheffenegger static void newreno_cong_signal(struct cc_var *ccv, ccsignal_t type);
90370efe5aSLawrence Stewart static int newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf);
914e4c84f8SRandall Stewart static void newreno_newround(struct cc_var *ccv, uint32_t round_cnt);
924e4c84f8SRandall Stewart static void newreno_rttsample(struct cc_var *ccv, uint32_t usec_rtt, uint32_t rxtcnt, uint32_t fas);
93b8d60729SRandall Stewart static int newreno_cb_init(struct cc_var *ccv, void *);
94b8d60729SRandall Stewart static size_t newreno_data_sz(void);
95370efe5aSLawrence Stewart
96b8d60729SRandall Stewart
97b8d60729SRandall Stewart VNET_DECLARE(uint32_t, newreno_beta);
98370efe5aSLawrence Stewart #define V_newreno_beta VNET(newreno_beta)
990fdc2472SMichael Tuexen VNET_DECLARE(uint32_t, newreno_beta_ecn);
100370efe5aSLawrence Stewart #define V_newreno_beta_ecn VNET(newreno_beta_ecn)
101dbc42409SLawrence Stewart
102dbc42409SLawrence Stewart struct cc_algo newreno_cc_algo = {
103dbc42409SLawrence Stewart .name = "newreno",
1049891578aSLawrence Stewart .cb_destroy = newreno_cb_destroy,
105dbc42409SLawrence Stewart .ack_received = newreno_ack_received,
10674a5a194SLawrence Stewart .after_idle = newreno_after_idle,
107dbc42409SLawrence Stewart .cong_signal = newreno_cong_signal,
108b8d60729SRandall Stewart .post_recovery = newreno_cc_post_recovery,
109370efe5aSLawrence Stewart .ctl_output = newreno_ctl_output,
1104e4c84f8SRandall Stewart .newround = newreno_newround,
1114e4c84f8SRandall Stewart .rttsample = newreno_rttsample,
1124e4c84f8SRandall Stewart .cb_init = newreno_cb_init,
113b8d60729SRandall Stewart .cc_data_sz = newreno_data_sz,
114dbc42409SLawrence Stewart };
115dbc42409SLawrence Stewart
1164e4c84f8SRandall Stewart static void
newreno_log_hystart_event(struct cc_var * ccv,struct newreno * nreno,uint8_t mod,uint32_t flex1)1174e4c84f8SRandall Stewart newreno_log_hystart_event(struct cc_var *ccv, struct newreno *nreno, uint8_t mod, uint32_t flex1)
1184e4c84f8SRandall Stewart {
1194e4c84f8SRandall Stewart /*
1204e4c84f8SRandall Stewart * Types of logs (mod value)
1214e4c84f8SRandall Stewart * 1 - rtt_thresh in flex1, checking to see if RTT is to great.
1224e4c84f8SRandall Stewart * 2 - rtt is too great, rtt_thresh in flex1.
1234e4c84f8SRandall Stewart * 3 - CSS is active incr in flex1
1244e4c84f8SRandall Stewart * 4 - A new round is beginning flex1 is round count
1254e4c84f8SRandall Stewart * 5 - A new RTT measurement flex1 is the new measurement.
1264e4c84f8SRandall Stewart * 6 - We enter CA ssthresh is also in flex1.
1274e4c84f8SRandall Stewart * 7 - Socket option to change hystart executed opt.val in flex1.
1284e4c84f8SRandall Stewart * 8 - Back out of CSS into SS, flex1 is the css_baseline_minrtt
129a9696510SRandall Stewart * 9 - We enter CA, via an ECN mark.
130a9696510SRandall Stewart * 10 - We enter CA, via a loss.
131a9696510SRandall Stewart * 11 - We have slipped out of SS into CA via cwnd growth.
132a9696510SRandall Stewart * 12 - After idle has re-enabled hystart++
1334e4c84f8SRandall Stewart */
1344e4c84f8SRandall Stewart struct tcpcb *tp;
1354e4c84f8SRandall Stewart
1364e4c84f8SRandall Stewart if (hystart_bblogs == 0)
1374e4c84f8SRandall Stewart return;
13800d3b744SMichael Tuexen tp = ccv->tp;
13969c7c811SRandall Stewart if (tcp_bblogging_on(tp)) {
1404e4c84f8SRandall Stewart union tcp_log_stackspecific log;
1414e4c84f8SRandall Stewart struct timeval tv;
1424e4c84f8SRandall Stewart
1434e4c84f8SRandall Stewart memset(&log, 0, sizeof(log));
1444e4c84f8SRandall Stewart log.u_bbr.flex1 = flex1;
1454e4c84f8SRandall Stewart log.u_bbr.flex2 = nreno->css_current_round_minrtt;
1464e4c84f8SRandall Stewart log.u_bbr.flex3 = nreno->css_lastround_minrtt;
1474e4c84f8SRandall Stewart log.u_bbr.flex4 = nreno->css_rttsample_count;
1484e4c84f8SRandall Stewart log.u_bbr.flex5 = nreno->css_entered_at_round;
1494e4c84f8SRandall Stewart log.u_bbr.flex6 = nreno->css_baseline_minrtt;
1504e4c84f8SRandall Stewart /* We only need bottom 16 bits of flags */
1514e4c84f8SRandall Stewart log.u_bbr.flex7 = nreno->newreno_flags & 0x0000ffff;
1524e4c84f8SRandall Stewart log.u_bbr.flex8 = mod;
1534e4c84f8SRandall Stewart log.u_bbr.epoch = nreno->css_current_round;
1544e4c84f8SRandall Stewart log.u_bbr.timeStamp = tcp_get_usecs(&tv);
1554e4c84f8SRandall Stewart log.u_bbr.lt_epoch = nreno->css_fas_at_css_entry;
1564e4c84f8SRandall Stewart log.u_bbr.pkts_out = nreno->css_last_fas;
1574e4c84f8SRandall Stewart log.u_bbr.delivered = nreno->css_lowrtt_fas;
158a9696510SRandall Stewart log.u_bbr.pkt_epoch = ccv->flags;
1594e4c84f8SRandall Stewart TCP_LOG_EVENTP(tp, NULL,
1609eb0e832SGleb Smirnoff &tptosocket(tp)->so_rcv,
1619eb0e832SGleb Smirnoff &tptosocket(tp)->so_snd,
1624e4c84f8SRandall Stewart TCP_HYSTART, 0,
1634e4c84f8SRandall Stewart 0, &log, false, &tv);
1644e4c84f8SRandall Stewart }
1654e4c84f8SRandall Stewart }
1664e4c84f8SRandall Stewart
167b8d60729SRandall Stewart static size_t
newreno_data_sz(void)168b8d60729SRandall Stewart newreno_data_sz(void)
169b8d60729SRandall Stewart {
170b8d60729SRandall Stewart return (sizeof(struct newreno));
171b8d60729SRandall Stewart }
172b8d60729SRandall Stewart
1734e4c84f8SRandall Stewart static int
newreno_cb_init(struct cc_var * ccv,void * ptr)174b8d60729SRandall Stewart newreno_cb_init(struct cc_var *ccv, void *ptr)
175370efe5aSLawrence Stewart {
176370efe5aSLawrence Stewart struct newreno *nreno;
177370efe5aSLawrence Stewart
17800d3b744SMichael Tuexen INP_WLOCK_ASSERT(tptoinpcb(ccv->tp));
179b8d60729SRandall Stewart if (ptr == NULL) {
180b8d60729SRandall Stewart ccv->cc_data = malloc(sizeof(struct newreno), M_CC_MEM, M_NOWAIT);
1814e4c84f8SRandall Stewart if (ccv->cc_data == NULL)
1824e4c84f8SRandall Stewart return (ENOMEM);
183b8d60729SRandall Stewart } else
184b8d60729SRandall Stewart ccv->cc_data = ptr;
1854e4c84f8SRandall Stewart nreno = (struct newreno *)ccv->cc_data;
1869891578aSLawrence Stewart /* NB: nreno is not zeroed, so initialise all fields. */
187370efe5aSLawrence Stewart nreno->beta = V_newreno_beta;
188370efe5aSLawrence Stewart nreno->beta_ecn = V_newreno_beta_ecn;
1894e4c84f8SRandall Stewart /*
1904e4c84f8SRandall Stewart * We set the enabled flag so that if
1914e4c84f8SRandall Stewart * the socket option gets strobed and
1924e4c84f8SRandall Stewart * we have not hit a loss
1934e4c84f8SRandall Stewart */
1944e4c84f8SRandall Stewart nreno->newreno_flags = CC_NEWRENO_HYSTART_ENABLED;
1954e4c84f8SRandall Stewart /* At init set both to infinity */
1964e4c84f8SRandall Stewart nreno->css_lastround_minrtt = 0xffffffff;
1974e4c84f8SRandall Stewart nreno->css_current_round_minrtt = 0xffffffff;
1984e4c84f8SRandall Stewart nreno->css_current_round = 0;
1994e4c84f8SRandall Stewart nreno->css_baseline_minrtt = 0xffffffff;
2004e4c84f8SRandall Stewart nreno->css_rttsample_count = 0;
2014e4c84f8SRandall Stewart nreno->css_entered_at_round = 0;
2024e4c84f8SRandall Stewart nreno->css_fas_at_css_entry = 0;
2034e4c84f8SRandall Stewart nreno->css_lowrtt_fas = 0;
2044e4c84f8SRandall Stewart nreno->css_last_fas = 0;
2054e4c84f8SRandall Stewart return (0);
2069891578aSLawrence Stewart }
2079891578aSLawrence Stewart
2089891578aSLawrence Stewart static void
newreno_cb_destroy(struct cc_var * ccv)2099891578aSLawrence Stewart newreno_cb_destroy(struct cc_var *ccv)
2109891578aSLawrence Stewart {
211b8d60729SRandall Stewart free(ccv->cc_data, M_CC_MEM);
212370efe5aSLawrence Stewart }
213370efe5aSLawrence Stewart
21474a5a194SLawrence Stewart static void
newreno_ack_received(struct cc_var * ccv,ccsignal_t type)215f74352fbSRichard Scheffenegger newreno_ack_received(struct cc_var *ccv, ccsignal_t type)
216dbc42409SLawrence Stewart {
2174e4c84f8SRandall Stewart struct newreno *nreno;
218*22dcc812SRichard Scheffenegger uint32_t mss = tcp_fixed_maxseg(ccv->tp);
2194e4c84f8SRandall Stewart
220b8d60729SRandall Stewart nreno = ccv->cc_data;
221dbc42409SLawrence Stewart if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) &&
222dbc42409SLawrence Stewart (ccv->flags & CCF_CWND_LIMITED)) {
223dbc42409SLawrence Stewart u_int cw = CCV(ccv, snd_cwnd);
224*22dcc812SRichard Scheffenegger u_int incr = mss;
225dbc42409SLawrence Stewart
226dbc42409SLawrence Stewart /*
227dbc42409SLawrence Stewart * Regular in-order ACK, open the congestion window.
228dbc42409SLawrence Stewart * Method depends on which congestion control state we're
229dbc42409SLawrence Stewart * in (slow start or cong avoid) and if ABC (RFC 3465) is
230dbc42409SLawrence Stewart * enabled.
231dbc42409SLawrence Stewart *
232dbc42409SLawrence Stewart * slow start: cwnd <= ssthresh
233dbc42409SLawrence Stewart * cong avoid: cwnd > ssthresh
234dbc42409SLawrence Stewart *
235dbc42409SLawrence Stewart * slow start and ABC (RFC 3465):
236dbc42409SLawrence Stewart * Grow cwnd exponentially by the amount of data
237dbc42409SLawrence Stewart * ACKed capping the max increment per ACK to
238dbc42409SLawrence Stewart * (abc_l_var * maxseg) bytes.
239dbc42409SLawrence Stewart *
240dbc42409SLawrence Stewart * slow start without ABC (RFC 5681):
241dbc42409SLawrence Stewart * Grow cwnd exponentially by maxseg per ACK.
242dbc42409SLawrence Stewart *
243dbc42409SLawrence Stewart * cong avoid and ABC (RFC 3465):
244dbc42409SLawrence Stewart * Grow cwnd linearly by maxseg per RTT for each
245dbc42409SLawrence Stewart * cwnd worth of ACKed data.
246dbc42409SLawrence Stewart *
247dbc42409SLawrence Stewart * cong avoid without ABC (RFC 5681):
248dbc42409SLawrence Stewart * Grow cwnd linearly by approximately maxseg per RTT using
249dbc42409SLawrence Stewart * maxseg^2 / cwnd per ACK as the increment.
250dbc42409SLawrence Stewart * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
251dbc42409SLawrence Stewart * avoid capping cwnd.
252dbc42409SLawrence Stewart */
253dbc42409SLawrence Stewart if (cw > CCV(ccv, snd_ssthresh)) {
254b8d60729SRandall Stewart if (nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) {
2554e4c84f8SRandall Stewart /*
2564e4c84f8SRandall Stewart * We have slipped into CA with
2574e4c84f8SRandall Stewart * CSS active. Deactivate all.
2584e4c84f8SRandall Stewart */
2594e4c84f8SRandall Stewart /* Turn off the CSS flag */
2604e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
2614e4c84f8SRandall Stewart /* Disable use of CSS in the future except long idle */
2624e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
263a9696510SRandall Stewart newreno_log_hystart_event(ccv, nreno, 11, CCV(ccv, snd_ssthresh));
2644e4c84f8SRandall Stewart }
265dbc42409SLawrence Stewart if (V_tcp_do_rfc3465) {
266dbc42409SLawrence Stewart if (ccv->flags & CCF_ABC_SENTAWND)
267dbc42409SLawrence Stewart ccv->flags &= ~CCF_ABC_SENTAWND;
268dbc42409SLawrence Stewart else
269dbc42409SLawrence Stewart incr = 0;
270dbc42409SLawrence Stewart } else
271dbc42409SLawrence Stewart incr = max((incr * incr / cw), 1);
272dbc42409SLawrence Stewart } else if (V_tcp_do_rfc3465) {
273dbc42409SLawrence Stewart /*
274dbc42409SLawrence Stewart * In slow-start with ABC enabled and no RTO in sight?
275dbc42409SLawrence Stewart * (Must not use abc_l_var > 1 if slow starting after
276dbc42409SLawrence Stewart * an RTO. On RTO, snd_nxt = snd_una, so the
277dbc42409SLawrence Stewart * snd_nxt == snd_max check is sufficient to
278dbc42409SLawrence Stewart * handle this).
279dbc42409SLawrence Stewart *
280dbc42409SLawrence Stewart * XXXLAS: Find a way to signal SS after RTO that
281dbc42409SLawrence Stewart * doesn't rely on tcpcb vars.
282dbc42409SLawrence Stewart */
2835d8fd932SRandall Stewart uint16_t abc_val;
2845d8fd932SRandall Stewart
2855d8fd932SRandall Stewart if (ccv->flags & CCF_USE_LOCAL_ABC)
2865d8fd932SRandall Stewart abc_val = ccv->labc;
2875d8fd932SRandall Stewart else
2885d8fd932SRandall Stewart abc_val = V_tcp_abc_l_var;
289a9696510SRandall Stewart if ((ccv->flags & CCF_HYSTART_ALLOWED) &&
2904e4c84f8SRandall Stewart (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) &&
2914e4c84f8SRandall Stewart ((nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) == 0)) {
2924e4c84f8SRandall Stewart /*
2934e4c84f8SRandall Stewart * Hystart is allowed and still enabled and we are not yet
2944e4c84f8SRandall Stewart * in CSS. Lets check to see if we can make a decision on
2954e4c84f8SRandall Stewart * if we need to go into CSS.
2964e4c84f8SRandall Stewart */
2974e4c84f8SRandall Stewart if ((nreno->css_rttsample_count >= hystart_n_rttsamples) &&
298a9696510SRandall Stewart (nreno->css_current_round_minrtt != 0xffffffff) &&
299a9696510SRandall Stewart (nreno->css_lastround_minrtt != 0xffffffff)) {
3004e4c84f8SRandall Stewart uint32_t rtt_thresh;
3014e4c84f8SRandall Stewart
3024e4c84f8SRandall Stewart /* Clamp (minrtt_thresh, lastround/8, maxrtt_thresh) */
3034e4c84f8SRandall Stewart rtt_thresh = (nreno->css_lastround_minrtt >> 3);
3044e4c84f8SRandall Stewart if (rtt_thresh < hystart_minrtt_thresh)
3054e4c84f8SRandall Stewart rtt_thresh = hystart_minrtt_thresh;
3064e4c84f8SRandall Stewart if (rtt_thresh > hystart_maxrtt_thresh)
3074e4c84f8SRandall Stewart rtt_thresh = hystart_maxrtt_thresh;
3084e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 1, rtt_thresh);
3094e4c84f8SRandall Stewart if (nreno->css_current_round_minrtt >= (nreno->css_lastround_minrtt + rtt_thresh)) {
3104e4c84f8SRandall Stewart /* Enter CSS */
3114e4c84f8SRandall Stewart nreno->newreno_flags |= CC_NEWRENO_HYSTART_IN_CSS;
3124e4c84f8SRandall Stewart nreno->css_fas_at_css_entry = nreno->css_lowrtt_fas;
313a9696510SRandall Stewart /*
314a9696510SRandall Stewart * The draft (v4) calls for us to set baseline to css_current_round_min
315a9696510SRandall Stewart * but that can cause an oscillation. We probably shoudl be using
316a9696510SRandall Stewart * css_lastround_minrtt, but the authors insist that will cause
317a9696510SRandall Stewart * issues on exiting early. We will leave the draft version for now
318a9696510SRandall Stewart * but I suspect this is incorrect.
319a9696510SRandall Stewart */
3204e4c84f8SRandall Stewart nreno->css_baseline_minrtt = nreno->css_current_round_minrtt;
3214e4c84f8SRandall Stewart nreno->css_entered_at_round = nreno->css_current_round;
3224e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 2, rtt_thresh);
3234e4c84f8SRandall Stewart }
3244e4c84f8SRandall Stewart }
3254e4c84f8SRandall Stewart }
326dbc42409SLawrence Stewart if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max))
327dbc42409SLawrence Stewart incr = min(ccv->bytes_this_ack,
328*22dcc812SRichard Scheffenegger ccv->nsegs * abc_val * mss);
329dbc42409SLawrence Stewart else
330*22dcc812SRichard Scheffenegger incr = min(ccv->bytes_this_ack, mss);
3314e4c84f8SRandall Stewart
3324e4c84f8SRandall Stewart /* Only if Hystart is enabled will the flag get set */
333b8d60729SRandall Stewart if (nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) {
3344e4c84f8SRandall Stewart incr /= hystart_css_growth_div;
3354e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 3, incr);
3364e4c84f8SRandall Stewart }
337dbc42409SLawrence Stewart }
338dbc42409SLawrence Stewart /* ABC is on by default, so incr equals 0 frequently. */
339dbc42409SLawrence Stewart if (incr > 0)
340dbc42409SLawrence Stewart CCV(ccv, snd_cwnd) = min(cw + incr,
341dbc42409SLawrence Stewart TCP_MAXWIN << CCV(ccv, snd_scale));
342dbc42409SLawrence Stewart }
343dbc42409SLawrence Stewart }
344dbc42409SLawrence Stewart
34574a5a194SLawrence Stewart static void
newreno_after_idle(struct cc_var * ccv)34674a5a194SLawrence Stewart newreno_after_idle(struct cc_var *ccv)
34774a5a194SLawrence Stewart {
3484e4c84f8SRandall Stewart struct newreno *nreno;
34974a5a194SLawrence Stewart
350b8d60729SRandall Stewart nreno = ccv->cc_data;
351b8d60729SRandall Stewart newreno_cc_after_idle(ccv);
352b8d60729SRandall Stewart if ((nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) == 0) {
3534e4c84f8SRandall Stewart /*
354a9696510SRandall Stewart * Re-enable hystart if we have been idle.
3554e4c84f8SRandall Stewart */
3564e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
3574e4c84f8SRandall Stewart nreno->newreno_flags |= CC_NEWRENO_HYSTART_ENABLED;
358a9696510SRandall Stewart newreno_log_hystart_event(ccv, nreno, 12, CCV(ccv, snd_ssthresh));
3594e4c84f8SRandall Stewart }
36074a5a194SLawrence Stewart }
36174a5a194SLawrence Stewart
36274a5a194SLawrence Stewart /*
36374a5a194SLawrence Stewart * Perform any necessary tasks before we enter congestion recovery.
36474a5a194SLawrence Stewart */
36574a5a194SLawrence Stewart static void
newreno_cong_signal(struct cc_var * ccv,ccsignal_t type)366f74352fbSRichard Scheffenegger newreno_cong_signal(struct cc_var *ccv, ccsignal_t type)
367dbc42409SLawrence Stewart {
368370efe5aSLawrence Stewart struct newreno *nreno;
36932a6df57SRichard Scheffenegger uint32_t beta, beta_ecn, cwin, factor, mss, pipe;
370370efe5aSLawrence Stewart
371370efe5aSLawrence Stewart cwin = CCV(ccv, snd_cwnd);
37200d3b744SMichael Tuexen mss = tcp_fixed_maxseg(ccv->tp);
373b8d60729SRandall Stewart nreno = ccv->cc_data;
3742f395cfdSZhenlei Huang beta = (nreno == NULL) ? V_newreno_beta : nreno->beta;
375b15b0535SMichael Tuexen beta_ecn = (nreno == NULL) ? V_newreno_beta_ecn : nreno->beta_ecn;
3765d8fd932SRandall Stewart /*
3775d8fd932SRandall Stewart * Note that we only change the backoff for ECN if the
3785d8fd932SRandall Stewart * global sysctl V_cc_do_abe is set <or> the stack itself
3795d8fd932SRandall Stewart * has set a flag in our newreno_flags (due to pacing) telling
3805d8fd932SRandall Stewart * us to use the lower valued back-off.
3815d8fd932SRandall Stewart */
382fa3746beSMichael Tuexen if ((type == CC_ECN) &&
383fa3746beSMichael Tuexen (V_cc_do_abe ||
3844e4c84f8SRandall Stewart ((nreno != NULL) && (nreno->newreno_flags & CC_NEWRENO_BETA_ECN_ENABLED))))
3859891578aSLawrence Stewart factor = beta_ecn;
3869891578aSLawrence Stewart else
3879891578aSLawrence Stewart factor = beta;
388dbc42409SLawrence Stewart
38903f0843bSLawrence Stewart /* Catch algos which mistakenly leak private signal types. */
39003f0843bSLawrence Stewart KASSERT((type & CC_SIGPRIVMASK) == 0,
39103f0843bSLawrence Stewart ("%s: congestion signal type 0x%08x is private\n", __func__, type));
39203f0843bSLawrence Stewart
393370efe5aSLawrence Stewart cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss),
394370efe5aSLawrence Stewart 2) * mss;
395dbc42409SLawrence Stewart
396dbc42409SLawrence Stewart switch (type) {
397dbc42409SLawrence Stewart case CC_NDUPACK:
398b8d60729SRandall Stewart if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) {
3994e4c84f8SRandall Stewart /* Make sure the flags are all off we had a loss */
4004e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
4014e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
402a9696510SRandall Stewart newreno_log_hystart_event(ccv, nreno, 10, CCV(ccv, snd_ssthresh));
4034e4c84f8SRandall Stewart }
404dbc42409SLawrence Stewart if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
405370efe5aSLawrence Stewart if (IN_CONGRECOVERY(CCV(ccv, t_flags) &&
406370efe5aSLawrence Stewart V_cc_do_abe && V_cc_abe_frlossreduce)) {
407370efe5aSLawrence Stewart CCV(ccv, snd_ssthresh) =
408370efe5aSLawrence Stewart ((uint64_t)CCV(ccv, snd_ssthresh) *
4095d8fd932SRandall Stewart (uint64_t)beta) / (uint64_t)beta_ecn;
410370efe5aSLawrence Stewart }
41143053c12SSean Bruno if (!IN_CONGRECOVERY(CCV(ccv, t_flags)))
412370efe5aSLawrence Stewart CCV(ccv, snd_ssthresh) = cwin;
413dbc42409SLawrence Stewart ENTER_RECOVERY(CCV(ccv, t_flags));
414dbc42409SLawrence Stewart }
415dbc42409SLawrence Stewart break;
416dbc42409SLawrence Stewart case CC_ECN:
417b8d60729SRandall Stewart if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) {
4184e4c84f8SRandall Stewart /* Make sure the flags are all off we had a loss */
4194e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
4204e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
421a9696510SRandall Stewart newreno_log_hystart_event(ccv, nreno, 9, CCV(ccv, snd_ssthresh));
4224e4c84f8SRandall Stewart }
423dbc42409SLawrence Stewart if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
424370efe5aSLawrence Stewart CCV(ccv, snd_ssthresh) = cwin;
425370efe5aSLawrence Stewart CCV(ccv, snd_cwnd) = cwin;
426dbc42409SLawrence Stewart ENTER_CONGRECOVERY(CCV(ccv, t_flags));
427dbc42409SLawrence Stewart }
428dbc42409SLawrence Stewart break;
42939a12f01SRichard Scheffenegger case CC_RTO:
43032a6df57SRichard Scheffenegger if (CCV(ccv, t_rxtshift) == 1) {
43132a6df57SRichard Scheffenegger if (V_tcp_do_newsack) {
43200d3b744SMichael Tuexen pipe = tcp_compute_pipe(ccv->tp);
43332a6df57SRichard Scheffenegger } else {
434fcea1cc9SRichard Scheffenegger pipe = CCV(ccv, snd_max) -
43532a6df57SRichard Scheffenegger CCV(ccv, snd_fack) +
43632a6df57SRichard Scheffenegger CCV(ccv, sackhint.sack_bytes_rexmit);
43732a6df57SRichard Scheffenegger }
43832a6df57SRichard Scheffenegger CCV(ccv, snd_ssthresh) = max(2,
43932a6df57SRichard Scheffenegger ((uint64_t)min(CCV(ccv, snd_wnd), pipe) *
44032a6df57SRichard Scheffenegger (uint64_t)factor) /
44132a6df57SRichard Scheffenegger (100ULL * (uint64_t)mss)) * mss;
44232a6df57SRichard Scheffenegger }
44339a12f01SRichard Scheffenegger CCV(ccv, snd_cwnd) = mss;
44439a12f01SRichard Scheffenegger break;
445f74352fbSRichard Scheffenegger default:
446f74352fbSRichard Scheffenegger break;
447dbc42409SLawrence Stewart }
448dbc42409SLawrence Stewart }
449dbc42409SLawrence Stewart
4509891578aSLawrence Stewart static int
newreno_ctl_output(struct cc_var * ccv,struct sockopt * sopt,void * buf)451370efe5aSLawrence Stewart newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf)
452370efe5aSLawrence Stewart {
453370efe5aSLawrence Stewart struct newreno *nreno;
454370efe5aSLawrence Stewart struct cc_newreno_opts *opt;
455370efe5aSLawrence Stewart
456370efe5aSLawrence Stewart if (sopt->sopt_valsize != sizeof(struct cc_newreno_opts))
457370efe5aSLawrence Stewart return (EMSGSIZE);
458370efe5aSLawrence Stewart
45900d3b744SMichael Tuexen if (CC_ALGO(ccv->tp) != &newreno_cc_algo)
460c358f185SRichard Scheffenegger return (ENOPROTOOPT);
461c358f185SRichard Scheffenegger
4624e4c84f8SRandall Stewart nreno = (struct newreno *)ccv->cc_data;
463370efe5aSLawrence Stewart opt = buf;
464370efe5aSLawrence Stewart switch (sopt->sopt_dir) {
465370efe5aSLawrence Stewart case SOPT_SET:
466370efe5aSLawrence Stewart switch (opt->name) {
467370efe5aSLawrence Stewart case CC_NEWRENO_BETA:
468370efe5aSLawrence Stewart nreno->beta = opt->val;
469370efe5aSLawrence Stewart break;
470370efe5aSLawrence Stewart case CC_NEWRENO_BETA_ECN:
471370efe5aSLawrence Stewart nreno->beta_ecn = opt->val;
4724e4c84f8SRandall Stewart nreno->newreno_flags |= CC_NEWRENO_BETA_ECN_ENABLED;
4734e4c84f8SRandall Stewart break;
474370efe5aSLawrence Stewart default:
475370efe5aSLawrence Stewart return (ENOPROTOOPT);
476370efe5aSLawrence Stewart }
4779891578aSLawrence Stewart break;
478370efe5aSLawrence Stewart case SOPT_GET:
479370efe5aSLawrence Stewart switch (opt->name) {
480370efe5aSLawrence Stewart case CC_NEWRENO_BETA:
481e2e088aeSRandall Stewart opt->val = nreno->beta;
482370efe5aSLawrence Stewart break;
483370efe5aSLawrence Stewart case CC_NEWRENO_BETA_ECN:
484e2e088aeSRandall Stewart opt->val = nreno->beta_ecn;
485370efe5aSLawrence Stewart break;
486370efe5aSLawrence Stewart default:
487370efe5aSLawrence Stewart return (ENOPROTOOPT);
488370efe5aSLawrence Stewart }
4899891578aSLawrence Stewart break;
490370efe5aSLawrence Stewart default:
491370efe5aSLawrence Stewart return (EINVAL);
492370efe5aSLawrence Stewart }
493370efe5aSLawrence Stewart
494370efe5aSLawrence Stewart return (0);
495370efe5aSLawrence Stewart }
496370efe5aSLawrence Stewart
497370efe5aSLawrence Stewart static int
newreno_beta_handler(SYSCTL_HANDLER_ARGS)498370efe5aSLawrence Stewart newreno_beta_handler(SYSCTL_HANDLER_ARGS)
499370efe5aSLawrence Stewart {
500855acb84SBrooks Davis int error;
501855acb84SBrooks Davis uint32_t new;
5029891578aSLawrence Stewart
503855acb84SBrooks Davis new = *(uint32_t *)arg1;
504855acb84SBrooks Davis error = sysctl_handle_int(oidp, &new, 0, req);
505855acb84SBrooks Davis if (error == 0 && req->newptr != NULL ) {
506370efe5aSLawrence Stewart if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe)
507855acb84SBrooks Davis error = EACCES;
508855acb84SBrooks Davis else if (new == 0 || new > 100)
509855acb84SBrooks Davis error = EINVAL;
510855acb84SBrooks Davis else
511855acb84SBrooks Davis *(uint32_t *)arg1 = new;
512370efe5aSLawrence Stewart }
513370efe5aSLawrence Stewart
514855acb84SBrooks Davis return (error);
515370efe5aSLawrence Stewart }
516370efe5aSLawrence Stewart
5174e4c84f8SRandall Stewart static void
newreno_newround(struct cc_var * ccv,uint32_t round_cnt)5184e4c84f8SRandall Stewart newreno_newround(struct cc_var *ccv, uint32_t round_cnt)
5194e4c84f8SRandall Stewart {
5204e4c84f8SRandall Stewart struct newreno *nreno;
5214e4c84f8SRandall Stewart
5224e4c84f8SRandall Stewart nreno = (struct newreno *)ccv->cc_data;
5234e4c84f8SRandall Stewart /* We have entered a new round */
5244e4c84f8SRandall Stewart nreno->css_lastround_minrtt = nreno->css_current_round_minrtt;
5254e4c84f8SRandall Stewart nreno->css_current_round_minrtt = 0xffffffff;
5264e4c84f8SRandall Stewart nreno->css_rttsample_count = 0;
5274e4c84f8SRandall Stewart nreno->css_current_round = round_cnt;
5284e4c84f8SRandall Stewart if ((nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) &&
5294e4c84f8SRandall Stewart ((round_cnt - nreno->css_entered_at_round) >= hystart_css_rounds)) {
5304e4c84f8SRandall Stewart /* Enter CA */
531a9696510SRandall Stewart if (ccv->flags & CCF_HYSTART_CAN_SH_CWND) {
5324e4c84f8SRandall Stewart /*
5334e4c84f8SRandall Stewart * We engage more than snd_ssthresh, engage
5344e4c84f8SRandall Stewart * the brakes!! Though we will stay in SS to
5354e4c84f8SRandall Stewart * creep back up again, so lets leave CSS active
5364e4c84f8SRandall Stewart * and give us hystart_css_rounds more rounds.
5374e4c84f8SRandall Stewart */
538a9696510SRandall Stewart if (ccv->flags & CCF_HYSTART_CONS_SSTH) {
5394e4c84f8SRandall Stewart CCV(ccv, snd_ssthresh) = ((nreno->css_lowrtt_fas + nreno->css_fas_at_css_entry) / 2);
5404e4c84f8SRandall Stewart } else {
5414e4c84f8SRandall Stewart CCV(ccv, snd_ssthresh) = nreno->css_lowrtt_fas;
5424e4c84f8SRandall Stewart }
5434e4c84f8SRandall Stewart CCV(ccv, snd_cwnd) = nreno->css_fas_at_css_entry;
5444e4c84f8SRandall Stewart nreno->css_entered_at_round = round_cnt;
5454e4c84f8SRandall Stewart } else {
5464e4c84f8SRandall Stewart CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd);
5474e4c84f8SRandall Stewart /* Turn off the CSS flag */
5484e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
5494e4c84f8SRandall Stewart /* Disable use of CSS in the future except long idle */
5504e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
5514e4c84f8SRandall Stewart }
5524e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 6, CCV(ccv, snd_ssthresh));
5534e4c84f8SRandall Stewart }
554a9696510SRandall Stewart if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED)
5554e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 4, round_cnt);
5564e4c84f8SRandall Stewart }
5574e4c84f8SRandall Stewart
5584e4c84f8SRandall Stewart static void
newreno_rttsample(struct cc_var * ccv,uint32_t usec_rtt,uint32_t rxtcnt,uint32_t fas)5594e4c84f8SRandall Stewart newreno_rttsample(struct cc_var *ccv, uint32_t usec_rtt, uint32_t rxtcnt, uint32_t fas)
5604e4c84f8SRandall Stewart {
5614e4c84f8SRandall Stewart struct newreno *nreno;
5624e4c84f8SRandall Stewart
5634e4c84f8SRandall Stewart nreno = (struct newreno *)ccv->cc_data;
5644e4c84f8SRandall Stewart if (rxtcnt > 1) {
5654e4c84f8SRandall Stewart /*
5664e4c84f8SRandall Stewart * Only look at RTT's that are non-ambiguous.
5674e4c84f8SRandall Stewart */
5684e4c84f8SRandall Stewart return;
5694e4c84f8SRandall Stewart }
5704e4c84f8SRandall Stewart nreno->css_rttsample_count++;
5714e4c84f8SRandall Stewart nreno->css_last_fas = fas;
5724e4c84f8SRandall Stewart if (nreno->css_current_round_minrtt > usec_rtt) {
5734e4c84f8SRandall Stewart nreno->css_current_round_minrtt = usec_rtt;
5744e4c84f8SRandall Stewart nreno->css_lowrtt_fas = nreno->css_last_fas;
5754e4c84f8SRandall Stewart }
576a9696510SRandall Stewart if ((nreno->css_rttsample_count >= hystart_n_rttsamples) &&
577a9696510SRandall Stewart (nreno->css_current_round_minrtt != 0xffffffff) &&
578653cf466SRandall Stewart (nreno->css_current_round_minrtt < nreno->css_baseline_minrtt) &&
579a9696510SRandall Stewart (nreno->css_lastround_minrtt != 0xffffffff)) {
5804e4c84f8SRandall Stewart /*
5814e4c84f8SRandall Stewart * We were in CSS and the RTT is now less, we
5824e4c84f8SRandall Stewart * entered CSS erroneously.
5834e4c84f8SRandall Stewart */
5844e4c84f8SRandall Stewart nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
5854e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 8, nreno->css_baseline_minrtt);
5864e4c84f8SRandall Stewart nreno->css_baseline_minrtt = 0xffffffff;
5874e4c84f8SRandall Stewart }
588a9696510SRandall Stewart if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED)
5894e4c84f8SRandall Stewart newreno_log_hystart_event(ccv, nreno, 5, usec_rtt);
5904e4c84f8SRandall Stewart }
5914e4c84f8SRandall Stewart
592370efe5aSLawrence Stewart SYSCTL_DECL(_net_inet_tcp_cc_newreno);
5937029da5cSPawel Biernacki SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, newreno,
5947029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
595370efe5aSLawrence Stewart "New Reno related settings");
596370efe5aSLawrence Stewart
597370efe5aSLawrence Stewart SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta,
5987029da5cSPawel Biernacki CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
599370efe5aSLawrence Stewart &VNET_NAME(newreno_beta), 3, &newreno_beta_handler, "IU",
600370efe5aSLawrence Stewart "New Reno beta, specified as number between 1 and 100");
601370efe5aSLawrence Stewart
602370efe5aSLawrence Stewart SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta_ecn,
6037029da5cSPawel Biernacki CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
604370efe5aSLawrence Stewart &VNET_NAME(newreno_beta_ecn), 3, &newreno_beta_handler, "IU",
605370efe5aSLawrence Stewart "New Reno beta ecn, specified as number between 1 and 100");
606dbc42409SLawrence Stewart
607dbc42409SLawrence Stewart DECLARE_CC_MODULE(newreno, &newreno_cc_algo);
608b8d60729SRandall Stewart MODULE_VERSION(newreno, 2);
609