The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/cc/cc_newreno.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
    5  *      The Regents of the University of California.
    6  * Copyright (c) 2007-2008,2010,2014
    7  *      Swinburne University of Technology, Melbourne, Australia.
    8  * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
    9  * Copyright (c) 2010 The FreeBSD Foundation
   10  * All rights reserved.
   11  *
   12  * This software was developed at the Centre for Advanced Internet
   13  * Architectures, Swinburne University of Technology, by Lawrence Stewart, James
   14  * Healy and David Hayes, made possible in part by a grant from the Cisco
   15  * University Research Program Fund at Community Foundation Silicon Valley.
   16  *
   17  * Portions of this software were developed at the Centre for Advanced
   18  * Internet Architectures, Swinburne University of Technology, Melbourne,
   19  * Australia by David Hayes under sponsorship from the FreeBSD Foundation.
   20  *
   21  * Redistribution and use in source and binary forms, with or without
   22  * modification, are permitted provided that the following conditions
   23  * are met:
   24  * 1. Redistributions of source code must retain the above copyright
   25  *    notice, this list of conditions and the following disclaimer.
   26  * 2. Redistributions in binary form must reproduce the above copyright
   27  *    notice, this list of conditions and the following disclaimer in the
   28  *    documentation and/or other materials provided with the distribution.
   29  *
   30  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   33  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   40  * SUCH DAMAGE.
   41  */
   42 
   43 /*
   44  * This software was first released in 2007 by James Healy and Lawrence Stewart
   45  * whilst working on the NewTCP research project at Swinburne University of
   46  * Technology's Centre for Advanced Internet Architectures, Melbourne,
   47  * Australia, which was made possible in part by a grant from the Cisco
   48  * University Research Program Fund at Community Foundation Silicon Valley.
   49  * More details are available at:
   50  *   http://caia.swin.edu.au/urp/newtcp/
   51  *
   52  * Dec 2014 garmitage@swin.edu.au
   53  * Borrowed code fragments from cc_cdg.c to add modifiable beta
   54  * via sysctls.
   55  *
   56  */
   57 
   58 #include <sys/cdefs.h>
   59 __FBSDID("$FreeBSD$");
   60 
   61 #include <sys/param.h>
   62 #include <sys/kernel.h>
   63 #include <sys/malloc.h>
   64 #include <sys/module.h>
   65 #include <sys/socket.h>
   66 #include <sys/lock.h>
   67 #include <sys/mutex.h>
   68 #include <sys/socketvar.h>
   69 #include <sys/sysctl.h>
   70 #include <sys/systm.h>
   71 
   72 #include <net/vnet.h>
   73 
   74 #include <net/route.h>
   75 #include <net/route/nhop.h>
   76 
   77 #include <netinet/in_pcb.h>
   78 #include <netinet/in.h>
   79 #include <netinet/in_pcb.h>
   80 #include <netinet/tcp.h>
   81 #include <netinet/tcp_seq.h>
   82 #include <netinet/tcp_var.h>
   83 #include <netinet/tcp_log_buf.h>
   84 #include <netinet/tcp_hpts.h>
   85 #include <netinet/cc/cc.h>
   86 #include <netinet/cc/cc_module.h>
   87 #include <netinet/cc/cc_newreno.h>
   88 
   89 static void     newreno_cb_destroy(struct cc_var *ccv);
   90 static void     newreno_ack_received(struct cc_var *ccv, uint16_t type);
   91 static void     newreno_after_idle(struct cc_var *ccv);
   92 static void     newreno_cong_signal(struct cc_var *ccv, uint32_t type);
   93 static int newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf);
   94 static void     newreno_newround(struct cc_var *ccv, uint32_t round_cnt);
   95 static void     newreno_rttsample(struct cc_var *ccv, uint32_t usec_rtt, uint32_t rxtcnt, uint32_t fas);
   96 static  int     newreno_cb_init(struct cc_var *ccv, void *);
   97 static size_t   newreno_data_sz(void);
   98 
   99 
  100 VNET_DECLARE(uint32_t, newreno_beta);
  101 #define V_newreno_beta VNET(newreno_beta)
  102 VNET_DECLARE(uint32_t, newreno_beta_ecn);
  103 #define V_newreno_beta_ecn VNET(newreno_beta_ecn)
  104 
  105 struct cc_algo newreno_cc_algo = {
  106         .name = "newreno",
  107         .cb_destroy = newreno_cb_destroy,
  108         .ack_received = newreno_ack_received,
  109         .after_idle = newreno_after_idle,
  110         .cong_signal = newreno_cong_signal,
  111         .post_recovery = newreno_cc_post_recovery,
  112         .ctl_output = newreno_ctl_output,
  113         .newround = newreno_newround,
  114         .rttsample = newreno_rttsample,
  115         .cb_init = newreno_cb_init,
  116         .cc_data_sz = newreno_data_sz,
  117 };
  118 
  119 static void
  120 newreno_log_hystart_event(struct cc_var *ccv, struct newreno *nreno, uint8_t mod, uint32_t flex1)
  121 {
  122         /*
  123          * Types of logs (mod value)
  124          * 1 - rtt_thresh in flex1, checking to see if RTT is to great.
  125          * 2 - rtt is too great, rtt_thresh in flex1.
  126          * 3 - CSS is active incr in flex1
  127          * 4 - A new round is beginning flex1 is round count
  128          * 5 - A new RTT measurement flex1 is the new measurement.
  129          * 6 - We enter CA ssthresh is also in flex1.
  130          * 7 - Socket option to change hystart executed opt.val in flex1.
  131          * 8 - Back out of CSS into SS, flex1 is the css_baseline_minrtt
  132          * 9 - We enter CA, via an ECN mark.
  133          * 10 - We enter CA, via a loss.
  134          * 11 - We have slipped out of SS into CA via cwnd growth.
  135          * 12 - After idle has re-enabled hystart++
  136          */
  137         struct tcpcb *tp;
  138 
  139         if (hystart_bblogs == 0)
  140                 return;
  141         tp = ccv->ccvc.tcp;
  142         if (tp->t_logstate != TCP_LOG_STATE_OFF) {
  143                 union tcp_log_stackspecific log;
  144                 struct timeval tv;
  145 
  146                 memset(&log, 0, sizeof(log));
  147                 log.u_bbr.flex1 = flex1;
  148                 log.u_bbr.flex2 = nreno->css_current_round_minrtt;
  149                 log.u_bbr.flex3 = nreno->css_lastround_minrtt;
  150                 log.u_bbr.flex4 = nreno->css_rttsample_count;
  151                 log.u_bbr.flex5 = nreno->css_entered_at_round;
  152                 log.u_bbr.flex6 = nreno->css_baseline_minrtt;
  153                 /* We only need bottom 16 bits of flags */
  154                 log.u_bbr.flex7 = nreno->newreno_flags & 0x0000ffff;
  155                 log.u_bbr.flex8 = mod;
  156                 log.u_bbr.epoch = nreno->css_current_round;
  157                 log.u_bbr.timeStamp = tcp_get_usecs(&tv);
  158                 log.u_bbr.lt_epoch = nreno->css_fas_at_css_entry;
  159                 log.u_bbr.pkts_out = nreno->css_last_fas;
  160                 log.u_bbr.delivered = nreno->css_lowrtt_fas;
  161                 log.u_bbr.pkt_epoch = ccv->flags;
  162                 TCP_LOG_EVENTP(tp, NULL,
  163                     &tptosocket(tp)->so_rcv,
  164                     &tptosocket(tp)->so_snd,
  165                     TCP_HYSTART, 0,
  166                     0, &log, false, &tv);
  167         }
  168 }
  169 
  170 static size_t
  171 newreno_data_sz(void)
  172 {
  173         return (sizeof(struct newreno));
  174 }
  175 
  176 static int
  177 newreno_cb_init(struct cc_var *ccv, void *ptr)
  178 {
  179         struct newreno *nreno;
  180 
  181         INP_WLOCK_ASSERT(tptoinpcb(ccv->ccvc.tcp));
  182         if (ptr == NULL) {
  183                 ccv->cc_data = malloc(sizeof(struct newreno), M_CC_MEM, M_NOWAIT);
  184                 if (ccv->cc_data == NULL)
  185                         return (ENOMEM);
  186         } else
  187                 ccv->cc_data = ptr;
  188         nreno = (struct newreno *)ccv->cc_data;
  189         /* NB: nreno is not zeroed, so initialise all fields. */
  190         nreno->beta = V_newreno_beta;
  191         nreno->beta_ecn = V_newreno_beta_ecn;
  192         /*
  193          * We set the enabled flag so that if
  194          * the socket option gets strobed and
  195          * we have not hit a loss
  196          */
  197         nreno->newreno_flags = CC_NEWRENO_HYSTART_ENABLED;
  198         /* At init set both to infinity */
  199         nreno->css_lastround_minrtt = 0xffffffff;
  200         nreno->css_current_round_minrtt = 0xffffffff;
  201         nreno->css_current_round = 0;
  202         nreno->css_baseline_minrtt = 0xffffffff;
  203         nreno->css_rttsample_count = 0;
  204         nreno->css_entered_at_round = 0;
  205         nreno->css_fas_at_css_entry = 0;
  206         nreno->css_lowrtt_fas = 0;
  207         nreno->css_last_fas = 0;
  208         return (0);
  209 }
  210 
  211 static void
  212 newreno_cb_destroy(struct cc_var *ccv)
  213 {
  214         free(ccv->cc_data, M_CC_MEM);
  215 }
  216 
  217 static void
  218 newreno_ack_received(struct cc_var *ccv, uint16_t type)
  219 {
  220         struct newreno *nreno;
  221 
  222         nreno = ccv->cc_data;
  223         if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) &&
  224             (ccv->flags & CCF_CWND_LIMITED)) {
  225                 u_int cw = CCV(ccv, snd_cwnd);
  226                 u_int incr = CCV(ccv, t_maxseg);
  227 
  228                 /*
  229                  * Regular in-order ACK, open the congestion window.
  230                  * Method depends on which congestion control state we're
  231                  * in (slow start or cong avoid) and if ABC (RFC 3465) is
  232                  * enabled.
  233                  *
  234                  * slow start: cwnd <= ssthresh
  235                  * cong avoid: cwnd > ssthresh
  236                  *
  237                  * slow start and ABC (RFC 3465):
  238                  *   Grow cwnd exponentially by the amount of data
  239                  *   ACKed capping the max increment per ACK to
  240                  *   (abc_l_var * maxseg) bytes.
  241                  *
  242                  * slow start without ABC (RFC 5681):
  243                  *   Grow cwnd exponentially by maxseg per ACK.
  244                  *
  245                  * cong avoid and ABC (RFC 3465):
  246                  *   Grow cwnd linearly by maxseg per RTT for each
  247                  *   cwnd worth of ACKed data.
  248                  *
  249                  * cong avoid without ABC (RFC 5681):
  250                  *   Grow cwnd linearly by approximately maxseg per RTT using
  251                  *   maxseg^2 / cwnd per ACK as the increment.
  252                  *   If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
  253                  *   avoid capping cwnd.
  254                  */
  255                 if (cw > CCV(ccv, snd_ssthresh)) {
  256                         if (nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) {
  257                                 /*
  258                                  * We have slipped into CA with
  259                                  * CSS active. Deactivate all.
  260                                  */
  261                                 /* Turn off the CSS flag */
  262                                 nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
  263                                 /* Disable use of CSS in the future except long idle  */
  264                                 nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
  265                                 newreno_log_hystart_event(ccv, nreno, 11, CCV(ccv, snd_ssthresh));
  266                         }
  267                         if (V_tcp_do_rfc3465) {
  268                                 if (ccv->flags & CCF_ABC_SENTAWND)
  269                                         ccv->flags &= ~CCF_ABC_SENTAWND;
  270                                 else
  271                                         incr = 0;
  272                         } else
  273                                 incr = max((incr * incr / cw), 1);
  274                 } else if (V_tcp_do_rfc3465) {
  275                         /*
  276                          * In slow-start with ABC enabled and no RTO in sight?
  277                          * (Must not use abc_l_var > 1 if slow starting after
  278                          * an RTO. On RTO, snd_nxt = snd_una, so the
  279                          * snd_nxt == snd_max check is sufficient to
  280                          * handle this).
  281                          *
  282                          * XXXLAS: Find a way to signal SS after RTO that
  283                          * doesn't rely on tcpcb vars.
  284                          */
  285                         uint16_t abc_val;
  286 
  287                         if (ccv->flags & CCF_USE_LOCAL_ABC)
  288                                 abc_val = ccv->labc;
  289                         else
  290                                 abc_val = V_tcp_abc_l_var;
  291                         if ((ccv->flags & CCF_HYSTART_ALLOWED) &&
  292                             (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) &&
  293                             ((nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) == 0)) {
  294                                 /*
  295                                  * Hystart is allowed and still enabled and we are not yet
  296                                  * in CSS. Lets check to see if we can make a decision on
  297                                  * if we need to go into CSS.
  298                                  */
  299                                 if ((nreno->css_rttsample_count >= hystart_n_rttsamples) &&
  300                                     (nreno->css_current_round_minrtt != 0xffffffff) &&
  301                                     (nreno->css_lastround_minrtt != 0xffffffff)) {
  302                                         uint32_t rtt_thresh;
  303 
  304                                         /* Clamp (minrtt_thresh, lastround/8, maxrtt_thresh) */
  305                                         rtt_thresh = (nreno->css_lastround_minrtt >> 3);
  306                                         if (rtt_thresh < hystart_minrtt_thresh)
  307                                                 rtt_thresh = hystart_minrtt_thresh;
  308                                         if (rtt_thresh > hystart_maxrtt_thresh)
  309                                                 rtt_thresh = hystart_maxrtt_thresh;
  310                                         newreno_log_hystart_event(ccv, nreno, 1, rtt_thresh);
  311                                         if (nreno->css_current_round_minrtt >= (nreno->css_lastround_minrtt + rtt_thresh)) {
  312                                                 /* Enter CSS */
  313                                                 nreno->newreno_flags |= CC_NEWRENO_HYSTART_IN_CSS;
  314                                                 nreno->css_fas_at_css_entry = nreno->css_lowrtt_fas;
  315                                                 /*
  316                                                  * The draft (v4) calls for us to set baseline to css_current_round_min
  317                                                  * but that can cause an oscillation. We probably shoudl be using
  318                                                  * css_lastround_minrtt, but the authors insist that will cause
  319                                                  * issues on exiting early. We will leave the draft version for now
  320                                                  * but I suspect this is incorrect.
  321                                                  */
  322                                                 nreno->css_baseline_minrtt = nreno->css_current_round_minrtt;
  323                                                 nreno->css_entered_at_round = nreno->css_current_round;
  324                                                 newreno_log_hystart_event(ccv, nreno, 2, rtt_thresh);
  325                                         }
  326                                 }
  327                         }
  328                         if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max))
  329                                 incr = min(ccv->bytes_this_ack,
  330                                     ccv->nsegs * abc_val *
  331                                     CCV(ccv, t_maxseg));
  332                         else
  333                                 incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg));
  334 
  335                         /* Only if Hystart is enabled will the flag get set */
  336                         if (nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) {
  337                                 incr /= hystart_css_growth_div;
  338                                 newreno_log_hystart_event(ccv, nreno, 3, incr);
  339                         }
  340                 }
  341                 /* ABC is on by default, so incr equals 0 frequently. */
  342                 if (incr > 0)
  343                         CCV(ccv, snd_cwnd) = min(cw + incr,
  344                             TCP_MAXWIN << CCV(ccv, snd_scale));
  345         }
  346 }
  347 
  348 static void
  349 newreno_after_idle(struct cc_var *ccv)
  350 {
  351         struct newreno *nreno;
  352 
  353         nreno = ccv->cc_data;
  354         newreno_cc_after_idle(ccv);
  355         if ((nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) == 0) {
  356                 /*
  357                  * Re-enable hystart if we have been idle.
  358                  */
  359                 nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
  360                 nreno->newreno_flags |= CC_NEWRENO_HYSTART_ENABLED;
  361                 newreno_log_hystart_event(ccv, nreno, 12, CCV(ccv, snd_ssthresh));
  362         }
  363 }
  364 
  365 /*
  366  * Perform any necessary tasks before we enter congestion recovery.
  367  */
  368 static void
  369 newreno_cong_signal(struct cc_var *ccv, uint32_t type)
  370 {
  371         struct newreno *nreno;
  372         uint32_t beta, beta_ecn, cwin, factor;
  373         u_int mss;
  374 
  375         cwin = CCV(ccv, snd_cwnd);
  376         mss = tcp_fixed_maxseg(ccv->ccvc.tcp);
  377         nreno = ccv->cc_data;
  378         beta = (nreno == NULL) ? V_newreno_beta : nreno->beta;;
  379         beta_ecn = (nreno == NULL) ? V_newreno_beta_ecn : nreno->beta_ecn;
  380         /*
  381          * Note that we only change the backoff for ECN if the
  382          * global sysctl V_cc_do_abe is set <or> the stack itself
  383          * has set a flag in our newreno_flags (due to pacing) telling
  384          * us to use the lower valued back-off.
  385          */
  386         if ((type == CC_ECN) &&
  387             (V_cc_do_abe ||
  388             ((nreno != NULL) && (nreno->newreno_flags & CC_NEWRENO_BETA_ECN_ENABLED))))
  389                 factor = beta_ecn;
  390         else
  391                 factor = beta;
  392 
  393         /* Catch algos which mistakenly leak private signal types. */
  394         KASSERT((type & CC_SIGPRIVMASK) == 0,
  395             ("%s: congestion signal type 0x%08x is private\n", __func__, type));
  396 
  397         cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss),
  398             2) * mss;
  399 
  400         switch (type) {
  401         case CC_NDUPACK:
  402                 if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) {
  403                         /* Make sure the flags are all off we had a loss */
  404                         nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
  405                         nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
  406                         newreno_log_hystart_event(ccv, nreno, 10, CCV(ccv, snd_ssthresh));
  407                 }
  408                 if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
  409                         if (IN_CONGRECOVERY(CCV(ccv, t_flags) &&
  410                             V_cc_do_abe && V_cc_abe_frlossreduce)) {
  411                                 CCV(ccv, snd_ssthresh) =
  412                                     ((uint64_t)CCV(ccv, snd_ssthresh) *
  413                                      (uint64_t)beta) / (uint64_t)beta_ecn;
  414                         }
  415                         if (!IN_CONGRECOVERY(CCV(ccv, t_flags)))
  416                                 CCV(ccv, snd_ssthresh) = cwin;
  417                         ENTER_RECOVERY(CCV(ccv, t_flags));
  418                 }
  419                 break;
  420         case CC_ECN:
  421                 if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) {
  422                         /* Make sure the flags are all off we had a loss */
  423                         nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
  424                         nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
  425                         newreno_log_hystart_event(ccv, nreno, 9, CCV(ccv, snd_ssthresh));
  426                 }
  427                 if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
  428                         CCV(ccv, snd_ssthresh) = cwin;
  429                         CCV(ccv, snd_cwnd) = cwin;
  430                         ENTER_CONGRECOVERY(CCV(ccv, t_flags));
  431                 }
  432                 break;
  433         case CC_RTO:
  434                 CCV(ccv, snd_ssthresh) = max(min(CCV(ccv, snd_wnd),
  435                                                  CCV(ccv, snd_cwnd)) / 2 / mss,
  436                                              2) * mss;
  437                 CCV(ccv, snd_cwnd) = mss;
  438                 break;
  439         }
  440 }
  441 
  442 static int
  443 newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf)
  444 {
  445         struct newreno *nreno;
  446         struct cc_newreno_opts *opt;
  447 
  448         if (sopt->sopt_valsize != sizeof(struct cc_newreno_opts))
  449                 return (EMSGSIZE);
  450 
  451         if (CC_ALGO(ccv->ccvc.tcp) != &newreno_cc_algo)
  452                 return (ENOPROTOOPT);
  453 
  454         nreno = (struct newreno *)ccv->cc_data;
  455         opt = buf;
  456         switch (sopt->sopt_dir) {
  457         case SOPT_SET:
  458                 switch (opt->name) {
  459                 case CC_NEWRENO_BETA:
  460                         nreno->beta = opt->val;
  461                         break;
  462                 case CC_NEWRENO_BETA_ECN:
  463                         nreno->beta_ecn = opt->val;
  464                         nreno->newreno_flags |= CC_NEWRENO_BETA_ECN_ENABLED;
  465                         break;
  466                 default:
  467                         return (ENOPROTOOPT);
  468                 }
  469                 break;
  470         case SOPT_GET:
  471                 switch (opt->name) {
  472                 case CC_NEWRENO_BETA:
  473                         opt->val =  nreno->beta;
  474                         break;
  475                 case CC_NEWRENO_BETA_ECN:
  476                         opt->val = nreno->beta_ecn;
  477                         break;
  478                 default:
  479                         return (ENOPROTOOPT);
  480                 }
  481                 break;
  482         default:
  483                 return (EINVAL);
  484         }
  485 
  486         return (0);
  487 }
  488 
  489 static int
  490 newreno_beta_handler(SYSCTL_HANDLER_ARGS)
  491 {
  492         int error;
  493         uint32_t new;
  494 
  495         new = *(uint32_t *)arg1;
  496         error = sysctl_handle_int(oidp, &new, 0, req);
  497         if (error == 0 && req->newptr != NULL ) {
  498                 if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe)
  499                         error = EACCES;
  500                 else if (new == 0 || new > 100)
  501                         error = EINVAL;
  502                 else
  503                         *(uint32_t *)arg1 = new;
  504         }
  505 
  506         return (error);
  507 }
  508 
  509 static void
  510 newreno_newround(struct cc_var *ccv, uint32_t round_cnt)
  511 {
  512         struct newreno *nreno;
  513 
  514         nreno = (struct newreno *)ccv->cc_data;
  515         /* We have entered a new round */
  516         nreno->css_lastround_minrtt = nreno->css_current_round_minrtt;
  517         nreno->css_current_round_minrtt = 0xffffffff;
  518         nreno->css_rttsample_count = 0;
  519         nreno->css_current_round = round_cnt;
  520         if ((nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) &&
  521             ((round_cnt - nreno->css_entered_at_round) >= hystart_css_rounds)) {
  522                 /* Enter CA */
  523                 if (ccv->flags & CCF_HYSTART_CAN_SH_CWND) {
  524                         /*
  525                          * We engage more than snd_ssthresh, engage
  526                          * the brakes!! Though we will stay in SS to
  527                          * creep back up again, so lets leave CSS active
  528                          * and give us hystart_css_rounds more rounds.
  529                          */
  530                         if (ccv->flags & CCF_HYSTART_CONS_SSTH) {
  531                                 CCV(ccv, snd_ssthresh) = ((nreno->css_lowrtt_fas + nreno->css_fas_at_css_entry) / 2);
  532                         } else {
  533                                 CCV(ccv, snd_ssthresh) = nreno->css_lowrtt_fas;
  534                         }
  535                         CCV(ccv, snd_cwnd) = nreno->css_fas_at_css_entry;
  536                         nreno->css_entered_at_round = round_cnt;
  537                 } else {
  538                         CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd);
  539                         /* Turn off the CSS flag */
  540                         nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
  541                         /* Disable use of CSS in the future except long idle  */
  542                         nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED;
  543                 }
  544                 newreno_log_hystart_event(ccv, nreno, 6, CCV(ccv, snd_ssthresh));
  545         }
  546         if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED)
  547                 newreno_log_hystart_event(ccv, nreno, 4, round_cnt);
  548 }
  549 
  550 static void
  551 newreno_rttsample(struct cc_var *ccv, uint32_t usec_rtt, uint32_t rxtcnt, uint32_t fas)
  552 {
  553         struct newreno *nreno;
  554 
  555         nreno = (struct newreno *)ccv->cc_data;
  556         if (rxtcnt > 1) {
  557                 /*
  558                  * Only look at RTT's that are non-ambiguous.
  559                  */
  560                 return;
  561         }
  562         nreno->css_rttsample_count++;
  563         nreno->css_last_fas = fas;
  564         if (nreno->css_current_round_minrtt > usec_rtt) {
  565                 nreno->css_current_round_minrtt = usec_rtt;
  566                 nreno->css_lowrtt_fas = nreno->css_last_fas;
  567         }
  568         if ((nreno->css_rttsample_count >= hystart_n_rttsamples) &&
  569             (nreno->css_current_round_minrtt != 0xffffffff) &&
  570             (nreno->css_current_round_minrtt < nreno->css_baseline_minrtt) &&
  571             (nreno->css_lastround_minrtt != 0xffffffff)) {
  572                 /*
  573                  * We were in CSS and the RTT is now less, we
  574                  * entered CSS erroneously.
  575                  */
  576                 nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS;
  577                 newreno_log_hystart_event(ccv, nreno, 8, nreno->css_baseline_minrtt);
  578                 nreno->css_baseline_minrtt = 0xffffffff;
  579         }
  580         if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED)
  581                 newreno_log_hystart_event(ccv, nreno, 5, usec_rtt);
  582 }
  583 
  584 SYSCTL_DECL(_net_inet_tcp_cc_newreno);
  585 SYSCTL_NODE(_net_inet_tcp_cc, OID_AUTO, newreno,
  586     CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
  587     "New Reno related settings");
  588 
  589 SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta,
  590     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  591     &VNET_NAME(newreno_beta), 3, &newreno_beta_handler, "IU",
  592     "New Reno beta, specified as number between 1 and 100");
  593 
  594 SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta_ecn,
  595     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
  596     &VNET_NAME(newreno_beta_ecn), 3, &newreno_beta_handler, "IU",
  597     "New Reno beta ecn, specified as number between 1 and 100");
  598 
  599 DECLARE_CC_MODULE(newreno, &newreno_cc_algo);
  600 MODULE_VERSION(newreno, 2);

Cache object: a622ecb30f3d5cebdb57af175194027e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.