tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

congestion_control_vegas.c (20253B)


      1 /* Copyright (c) 2019-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file congestion_control_vegas.c
      6 * \brief Code that implements the TOR_VEGAS congestion control algorithm
      7 *        from Proposal #324.
      8 */
      9 
     10 #define TOR_CONGESTION_CONTROL_VEGAS_PRIVATE
     11 
     12 #include "core/or/or.h"
     13 
     14 #include "core/or/crypt_path.h"
     15 #include "core/or/or_circuit_st.h"
     16 #include "core/or/sendme.h"
     17 #include "core/or/congestion_control_st.h"
     18 #include "core/or/congestion_control_common.h"
     19 #include "core/or/congestion_control_vegas.h"
     20 #include "core/or/circuitlist.h"
     21 #include "core/or/circuituse.h"
     22 #include "core/or/origin_circuit_st.h"
     23 #include "core/or/channel.h"
     24 #include "feature/nodelist/networkstatus.h"
     25 #include "feature/control/control_events.h"
     26 #include "lib/math/stats.h"
     27 
     28 #define OUTBUF_CELLS (2*TLS_RECORD_MAX_CELLS)
     29 
     30 #define SS_CWND_MAX_DFLT (5000)
     31 
     32 /* sbws circs are two hops, so params are based on 2 outbufs of cells */
     33 #define VEGAS_ALPHA_SBWS_DFLT (2*OUTBUF_CELLS-TLS_RECORD_MAX_CELLS)
     34 #define VEGAS_BETA_SBWS_DFLT (2*OUTBUF_CELLS+TLS_RECORD_MAX_CELLS)
     35 #define VEGAS_GAMMA_SBWS_DFLT (2*OUTBUF_CELLS)
     36 #define VEGAS_DELTA_SBWS_DFLT (4*OUTBUF_CELLS)
     37 #define VEGAS_SSCAP_SBWS_DFLT (400)
     38 
     39 /* Exits are three hops, so params are based on 3 outbufs of cells */
     40 #define VEGAS_ALPHA_EXIT_DFLT (3*OUTBUF_CELLS)
     41 #define VEGAS_BETA_EXIT_DFLT (4*OUTBUF_CELLS)
     42 #define VEGAS_GAMMA_EXIT_DFLT (3*OUTBUF_CELLS)
     43 #define VEGAS_DELTA_EXIT_DFLT (5*OUTBUF_CELLS)
     44 #define VEGAS_SSCAP_EXIT_DFLT (600)
     45 
     46 /* Onion rends are six hops, so params are based on 6 outbufs of cells */
     47 #define VEGAS_ALPHA_ONION_DFLT (3*OUTBUF_CELLS)
     48 #define VEGAS_BETA_ONION_DFLT (6*OUTBUF_CELLS)
     49 #define VEGAS_GAMMA_ONION_DFLT (4*OUTBUF_CELLS)
     50 #define VEGAS_DELTA_ONION_DFLT (7*OUTBUF_CELLS)
     51 #define VEGAS_SSCAP_ONION_DFLT (475)
     52 
     53 /**
     54 * Number of sendme_incs between cwnd and inflight for cwnd to be
     55 * still considered full */
     56 #define VEGAS_CWND_FULL_GAP_DFLT (4)
     57 static int cc_vegas_cwnd_full_gap = VEGAS_CWND_FULL_GAP_DFLT;
     58 
     59 /**
     60 * If the cwnd becomes less than this percent full at any point,
     61 * we declare it not full immediately.
     62 */
     63 #define VEGAS_CWND_FULL_MINPCT_DFLT (25)
     64 static int cc_vegas_cwnd_full_minpct = VEGAS_CWND_FULL_MINPCT_DFLT;
     65 
     66 /**
     67 * Param to decide when to reset the cwnd.
     68 */
     69 #define VEGAS_CWND_FULL_PER_CWND_DFLT (1)
     70 static int cc_cwnd_full_per_cwnd = VEGAS_CWND_FULL_PER_CWND_DFLT;
     71 
     72 /** Moving average of the cc->cwnd from each circuit exiting slowstart. */
     73 double cc_stats_vegas_exit_ss_cwnd_ma = 0;
     74 double cc_stats_vegas_exit_ss_bdp_ma = 0;
     75 double cc_stats_vegas_exit_ss_inc_ma = 0;
     76 double cc_stats_vegas_gamma_drop_ma = 0;
     77 double cc_stats_vegas_delta_drop_ma = 0;
     78 double cc_stats_vegas_ss_csig_blocked_ma = 0;
     79 double cc_stats_vegas_csig_blocked_ma = 0;
     80 double cc_stats_vegas_csig_alpha_ma = 0;
     81 double cc_stats_vegas_csig_beta_ma = 0;
     82 double cc_stats_vegas_csig_delta_ma = 0;
     83 
     84 double cc_stats_vegas_ss_queue_ma = 0;
     85 double cc_stats_vegas_queue_ma = 0;
     86 double cc_stats_vegas_bdp_ma = 0;
     87 
     88 /** Stats on how many times we reached "delta" param. */
     89 uint64_t cc_stats_vegas_above_delta = 0;
     90 /** Stats on how many times we reached "ss_cwnd_max" param. */
     91 uint64_t cc_stats_vegas_above_ss_cwnd_max = 0;
     92 uint64_t cc_stats_vegas_below_ss_inc_floor = 0;
     93 uint64_t cc_stats_vegas_circ_exited_ss = 0;
     94 
     95 /**
     96 * The original TCP Vegas congestion window BDP estimator.
     97 */
     98 static inline uint64_t
     99 vegas_bdp(const congestion_control_t *cc)
    100 {
    101  return cc->bdp;
    102 }
    103 
    104 /**
    105 * Cache Vegas consensus parameters.
    106 */
    107 void
    108 congestion_control_vegas_set_params(congestion_control_t *cc,
    109                                    cc_path_t path)
    110 {
    111  tor_assert(cc->cc_alg == CC_ALG_VEGAS);
    112  const char *alpha_str = NULL, *beta_str = NULL, *gamma_str = NULL;
    113  const char *delta_str = NULL, *sscap_str = NULL;
    114  int alpha, beta, gamma, delta, ss_cwnd_cap;
    115 
    116  switch (path) {
    117    case CC_PATH_SBWS:
    118      alpha_str = "cc_vegas_alpha_sbws";
    119      beta_str = "cc_vegas_beta_sbws";
    120      gamma_str = "cc_vegas_gamma_sbws";
    121      delta_str = "cc_vegas_delta_sbws";
    122      sscap_str = "cc_sscap_sbws";
    123      alpha = VEGAS_ALPHA_SBWS_DFLT;
    124      beta = VEGAS_BETA_SBWS_DFLT;
    125      gamma = VEGAS_GAMMA_SBWS_DFLT;
    126      delta = VEGAS_DELTA_SBWS_DFLT;
    127      ss_cwnd_cap = VEGAS_SSCAP_SBWS_DFLT;
    128      break;
    129    case CC_PATH_EXIT:
    130    case CC_PATH_ONION_SOS:
    131      alpha_str = "cc_vegas_alpha_exit";
    132      beta_str = "cc_vegas_beta_exit";
    133      gamma_str = "cc_vegas_gamma_exit";
    134      delta_str = "cc_vegas_delta_exit";
    135      sscap_str = "cc_sscap_exit";
    136      alpha = VEGAS_ALPHA_EXIT_DFLT;
    137      beta = VEGAS_BETA_EXIT_DFLT;
    138      gamma = VEGAS_GAMMA_EXIT_DFLT;
    139      delta = VEGAS_DELTA_EXIT_DFLT;
    140      ss_cwnd_cap = VEGAS_SSCAP_EXIT_DFLT;
    141      break;
    142    case CC_PATH_ONION:
    143    case CC_PATH_ONION_VG:
    144      alpha_str = "cc_vegas_alpha_onion";
    145      beta_str = "cc_vegas_beta_onion";
    146      gamma_str = "cc_vegas_gamma_onion";
    147      delta_str = "cc_vegas_delta_onion";
    148      sscap_str = "cc_sscap_onion";
    149      alpha = VEGAS_ALPHA_ONION_DFLT;
    150      beta = VEGAS_BETA_ONION_DFLT;
    151      gamma = VEGAS_GAMMA_ONION_DFLT;
    152      delta = VEGAS_DELTA_ONION_DFLT;
    153      ss_cwnd_cap = VEGAS_SSCAP_ONION_DFLT;
    154      break;
    155    default:
    156      tor_assert(0);
    157      break;
    158  }
    159 
    160  cc->vegas_params.ss_cwnd_cap =
    161   networkstatus_get_param(NULL, sscap_str,
    162      ss_cwnd_cap,
    163      100,
    164      INT32_MAX);
    165 
    166  cc->vegas_params.ss_cwnd_max =
    167   networkstatus_get_param(NULL, "cc_ss_max",
    168      SS_CWND_MAX_DFLT,
    169      500,
    170      INT32_MAX);
    171 
    172  cc->vegas_params.alpha =
    173   networkstatus_get_param(NULL, alpha_str,
    174      alpha,
    175      0,
    176      1000);
    177 
    178  cc->vegas_params.beta =
    179   networkstatus_get_param(NULL, beta_str,
    180      beta,
    181      0,
    182      1000);
    183 
    184  cc->vegas_params.gamma =
    185   networkstatus_get_param(NULL, gamma_str,
    186      gamma,
    187      0,
    188      1000);
    189 
    190  cc->vegas_params.delta =
    191   networkstatus_get_param(NULL, delta_str,
    192      delta,
    193      0,
    194      INT32_MAX);
    195 
    196  cc_vegas_cwnd_full_minpct =
    197   networkstatus_get_param(NULL, "cc_cwnd_full_minpct",
    198      VEGAS_CWND_FULL_MINPCT_DFLT,
    199      0,
    200      100);
    201 
    202  cc_vegas_cwnd_full_gap =
    203   networkstatus_get_param(NULL, "cc_cwnd_full_gap",
    204      VEGAS_CWND_FULL_GAP_DFLT,
    205      0,
    206      INT16_MAX);
    207 
    208  cc_cwnd_full_per_cwnd =
    209   networkstatus_get_param(NULL, "cc_cwnd_full_per_cwnd",
    210      VEGAS_CWND_FULL_PER_CWND_DFLT,
    211      0,
    212      1);
    213 }
    214 
    215 /**
    216 * Common log function for tracking all vegas state.
    217 */
    218 static void
    219 congestion_control_vegas_log(const circuit_t *circ,
    220                             const congestion_control_t *cc)
    221 {
    222  uint64_t queue_use = cc->cwnd - vegas_bdp(cc);
    223 
    224  if (CIRCUIT_IS_ORIGIN(circ) &&
    225      circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
    226    log_info(LD_CIRC,
    227               "CC: TOR_VEGAS Onion Circuit %d "
    228               "RTT: %"PRIu64", %"PRIu64", %"PRIu64", "
    229               "CWND: %"PRIu64", "
    230               "INFL: %"PRIu64", "
    231               "VBDP: %"PRIu64", "
    232               "QUSE: %"PRIu64", "
    233               "BWE: %"PRIu64", "
    234               "SS: %d",
    235             CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier,
    236             cc->min_rtt_usec/1000,
    237             cc->ewma_rtt_usec/1000,
    238             cc->max_rtt_usec/1000,
    239             cc->cwnd,
    240             cc->inflight,
    241             vegas_bdp(cc),
    242             queue_use,
    243             cc->cwnd*CELL_MAX_NETWORK_SIZE*1000/
    244                MAX(cc->min_rtt_usec,cc->ewma_rtt_usec),
    245             cc->in_slow_start
    246             );
    247  } else {
    248    log_info(LD_CIRC,
    249               "CC: TOR_VEGAS "
    250               "RTT: %"PRIu64", %"PRIu64", %"PRIu64", "
    251               "CWND: %"PRIu64", "
    252               "INFL: %"PRIu64", "
    253               "VBDP: %"PRIu64", "
    254               "QUSE: %"PRIu64", "
    255               "BWE: %"PRIu64", "
    256               "SS: %d",
    257             cc->min_rtt_usec/1000,
    258             cc->ewma_rtt_usec/1000,
    259             cc->max_rtt_usec/1000,
    260             cc->cwnd,
    261             cc->inflight,
    262             vegas_bdp(cc),
    263             queue_use,
    264             cc->cwnd*CELL_MAX_NETWORK_SIZE*1000/
    265                MAX(cc->min_rtt_usec,cc->ewma_rtt_usec),
    266             cc->in_slow_start
    267             );
    268  }
    269 }
    270 
    271 /**
    272 * Implements RFC3742: Limited Slow Start.
    273 * https://datatracker.ietf.org/doc/html/rfc3742#section-2
    274 */
    275 static inline uint64_t
    276 rfc3742_ss_inc(const congestion_control_t *cc)
    277 {
    278  if (cc->cwnd <= cc->vegas_params.ss_cwnd_cap) {
    279    /* If less than the cap, round and always grow by at least 1 sendme_inc. */
    280    return ((uint64_t)cc->cwnd_inc_pct_ss*cc->sendme_inc + 50)/100;
    281  } else {
    282    // K = int(cwnd/(0.5 max_ssthresh));
    283    //  => K = 2*cwnd/max_ssthresh
    284    // cwnd += int(MSS/K);
    285    //  => cwnd += MSS*max_ssthresh/(2*cwnd)
    286    // Return at least 1 for inc.
    287    return MAX(
    288            ((uint64_t)cc->sendme_inc*cc->vegas_params.ss_cwnd_cap + cc->cwnd)/
    289                 (2*cc->cwnd),
    290               1);
    291  }
    292 }
    293 
    294 /**
    295 * Exit Vegas slow start.
    296 *
    297 * This function sets our slow-start state to 0, and emits logs
    298 * and control port information signifying end of slow start.
    299 * It also schedules the next CWND update for steady-state.
    300 */
    301 static void
    302 congestion_control_vegas_exit_slow_start(const circuit_t *circ,
    303                                         congestion_control_t *cc)
    304 {
    305  congestion_control_vegas_log(circ, cc);
    306  cc->in_slow_start = 0;
    307  congestion_control_vegas_log(circ, cc);
    308 
    309  /* Update metricsport metrics */
    310  cc_stats_vegas_exit_ss_cwnd_ma =
    311    stats_update_running_avg(cc_stats_vegas_exit_ss_cwnd_ma,
    312                             cc->cwnd);
    313  cc_stats_vegas_exit_ss_bdp_ma =
    314    stats_update_running_avg(cc_stats_vegas_exit_ss_bdp_ma,
    315                             vegas_bdp(cc));
    316  cc_stats_vegas_exit_ss_inc_ma =
    317    stats_update_running_avg(cc_stats_vegas_exit_ss_inc_ma,
    318                             rfc3742_ss_inc(cc));
    319  cc_stats_vegas_circ_exited_ss++;
    320 
    321  /* We need to report that slow start has exited ASAP,
    322   * for sbws bandwidth measurement. */
    323  if (CIRCUIT_IS_ORIGIN(circ)) {
    324    /* We must discard const here because the event modifies fields :/ */
    325    control_event_circ_bandwidth_used_for_circ(
    326            TO_ORIGIN_CIRCUIT((circuit_t*)circ));
    327  }
    328 }
    329 
    330 /**
    331 * Returns true if the congestion window is considered full.
    332 *
    333 * We allow a number of sendme_incs gap in case buffering issues
    334 * with edge conns cause the window to occasionally be not quite
    335 * full. This can happen if several SENDMEs arrive before we
    336 * return to the eventloop to fill the inbuf on edge connections.
    337 */
    338 static inline bool
    339 cwnd_became_full(const congestion_control_t *cc)
    340 {
    341  if (cc->inflight + cc_vegas_cwnd_full_gap*cc->sendme_inc >= cc->cwnd) {
    342    return true;
    343  } else {
    344    return false;
    345  }
    346 }
    347 
    348 /**
    349 * Returns true if the congestion window is no longer full.
    350 *
    351 * This functions as a low watermark, below which we stop
    352 * allowing cwnd increments.
    353 */
    354 static inline bool
    355 cwnd_became_nonfull(const congestion_control_t *cc)
    356 {
    357  /* Use multiply form to avoid division */
    358  if (100*cc->inflight < cc_vegas_cwnd_full_minpct * cc->cwnd) {
    359    return true;
    360  } else {
    361    return false;
    362  }
    363 }
    364 
    365 /**
    366 * Decide if it is time to reset the cwnd_full status.
    367 *
    368 * If cc_cwnd_full_per_cwnd=1, we reset cwnd_full once per congestion
    369 * window, ie:
    370 *   next_cwnd_event == SENDME_PER_CWND(cc)
    371 *
    372 * Otherwise, we reset cwnd_full whenever there is an update of
    373 * the congestion window, ie:
    374 *   next_cc_event == CWND_UPDATE_RATE(cc)
    375 */
    376 static inline bool
    377 cwnd_full_reset(const congestion_control_t *cc)
    378 {
    379  if (cc_cwnd_full_per_cwnd) {
    380    return (cc->next_cwnd_event == SENDME_PER_CWND(cc));
    381  } else {
    382    return (cc->next_cc_event == CWND_UPDATE_RATE(cc));
    383  }
    384 }
    385 
    386 /**
    387 * Process a SENDME and update the congestion window according to the
    388 * rules specified in TOR_VEGAS of Proposal #324.
    389 *
    390 * Essentially, this algorithm attempts to measure queue lengths on
    391 * the circuit by subtracting the bandwidth-delay-product estimate
    392 * from the current congestion window.
    393 *
    394 * If the congestion window is larger than the bandwidth-delay-product,
    395 * then data is assumed to be queuing. We reduce the congestion window
    396 * in that case.
    397 *
    398 * If the congestion window is smaller than the bandwidth-delay-product,
    399 * then there is spare bandwidth capacity on the circuit. We increase the
    400 * congestion window in that case.
    401 *
    402 * The congestion window is updated only once every congestion window worth of
    403 * packets, even if the signal persists. It is also updated whenever the
    404 * upstream orcon blocks, or unblocks. This minimizes local client queues.
    405 */
    406 int
    407 congestion_control_vegas_process_sendme(congestion_control_t *cc,
    408                                        const circuit_t *circ)
    409 {
    410  uint64_t queue_use;
    411 
    412  tor_assert(cc && cc->cc_alg == CC_ALG_VEGAS);
    413  tor_assert(circ);
    414 
    415  /* Update ack counter until next congestion signal event is allowed */
    416  if (cc->next_cc_event)
    417    cc->next_cc_event--;
    418 
    419  /* Update ack counter until a full cwnd is processed */
    420  if (cc->next_cwnd_event)
    421    cc->next_cwnd_event--;
    422 
    423  /* Compute BDP and RTT. If we did not update, don't run the alg */
    424  if (!congestion_control_update_circuit_estimates(cc, circ)) {
    425    cc->inflight = cc->inflight - cc->sendme_inc;
    426    return 0;
    427  }
    428 
    429  /* The queue use is the amount in which our cwnd is above BDP;
    430   * if it is below, then 0 queue use. */
    431  if (vegas_bdp(cc) > cc->cwnd)
    432    queue_use = 0; // This should not happen anymore..
    433  else
    434    queue_use = cc->cwnd - vegas_bdp(cc);
    435 
    436  /* Update the full state */
    437  if (cwnd_became_full(cc))
    438    cc->cwnd_full = 1;
    439  else if (cwnd_became_nonfull(cc))
    440    cc->cwnd_full = 0;
    441 
    442  if (cc->in_slow_start) {
    443    if (queue_use < cc->vegas_params.gamma && !cc->blocked_chan) {
    444      /* If the congestion window is not fully in use, skip any
    445       * increment of cwnd in slow start */
    446      if (cc->cwnd_full) {
    447        /* Get the "Limited Slow Start" increment */
    448        uint64_t inc = rfc3742_ss_inc(cc);
    449        cc->cwnd += inc;
    450 
    451        // Check if inc is less than what we would do in steady-state
    452        // avoidance. Note that this is likely never to happen
    453        // in practice, but we keep this block and the metrics to make
    454        // sure.
    455        if (inc*SENDME_PER_CWND(cc) <= CWND_INC(cc)*cc->cwnd_inc_rate) {
    456          congestion_control_vegas_exit_slow_start(circ, cc);
    457 
    458          cc_stats_vegas_below_ss_inc_floor++;
    459 
    460          /* We exited slow start without being blocked */
    461          cc_stats_vegas_ss_csig_blocked_ma =
    462            stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma,
    463                                     0);
    464        }
    465      }
    466    } else {
    467      uint64_t old_cwnd = cc->cwnd;
    468 
    469      /* Congestion signal: Set cwnd to gamma threshold */
    470      cc->cwnd = vegas_bdp(cc) + cc->vegas_params.gamma;
    471 
    472      /* Compute the percentage we experience a blocked csig vs RTT sig */
    473      if (cc->blocked_chan) {
    474        cc_stats_vegas_ss_csig_blocked_ma =
    475          stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma,
    476                                   100);
    477      } else {
    478        uint64_t cwnd_diff = (old_cwnd > cc->cwnd ? old_cwnd - cc->cwnd : 0);
    479 
    480        cc_stats_vegas_ss_csig_blocked_ma =
    481          stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma,
    482                                   0);
    483 
    484        /* Account the amount we reduced the cwnd by for the gamma cutoff */
    485        cc_stats_vegas_gamma_drop_ma =
    486          stats_update_running_avg(cc_stats_vegas_gamma_drop_ma,
    487                               cwnd_diff);
    488      }
    489 
    490      congestion_control_vegas_exit_slow_start(circ, cc);
    491    }
    492 
    493    if (cc->cwnd >= cc->vegas_params.ss_cwnd_max) {
    494      cc->cwnd = cc->vegas_params.ss_cwnd_max;
    495      congestion_control_vegas_exit_slow_start(circ, cc);
    496      cc_stats_vegas_above_ss_cwnd_max++;
    497    }
    498 
    499    cc_stats_vegas_ss_queue_ma =
    500       stats_update_running_avg(cc_stats_vegas_ss_queue_ma,
    501                             queue_use);
    502  /* After slow start, We only update once per window */
    503  } else if (cc->next_cc_event == 0) {
    504    if (queue_use > cc->vegas_params.delta) {
    505      uint64_t old_cwnd = cc->cwnd;
    506      uint64_t cwnd_diff;
    507 
    508      /* If we are above the delta threshold, drop cwnd down to the
    509       * delta threshold. */
    510      cc->cwnd = vegas_bdp(cc) + cc->vegas_params.delta - CWND_INC(cc);
    511 
    512      /* Account the amount we reduced the cwnd by for the gamma cutoff */
    513      cwnd_diff = (old_cwnd > cc->cwnd ? old_cwnd - cc->cwnd : 0);
    514      cc_stats_vegas_delta_drop_ma =
    515        stats_update_running_avg(cc_stats_vegas_delta_drop_ma,
    516                             cwnd_diff);
    517 
    518      cc_stats_vegas_above_delta++;
    519 
    520      /* Percentage metrics: Add 100% delta, 0 for other two */
    521      cc_stats_vegas_csig_alpha_ma =
    522          stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
    523                                   0);
    524      cc_stats_vegas_csig_beta_ma =
    525          stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
    526                                   0);
    527      cc_stats_vegas_csig_delta_ma =
    528          stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
    529                                   100);
    530    } else if (queue_use > cc->vegas_params.beta || cc->blocked_chan) {
    531      cc->cwnd -= CWND_INC(cc);
    532 
    533      /* Compute the percentage we experience a blocked csig vs RTT sig */
    534      if (cc->blocked_chan) {
    535        cc_stats_vegas_csig_blocked_ma =
    536          stats_update_running_avg(cc_stats_vegas_csig_blocked_ma,
    537                                   100);
    538      } else {
    539        cc_stats_vegas_csig_blocked_ma =
    540          stats_update_running_avg(cc_stats_vegas_csig_blocked_ma,
    541                                   0);
    542      }
    543 
    544      /* Percentage counters: Add 100% beta, 0 for other two */
    545      cc_stats_vegas_csig_alpha_ma =
    546          stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
    547                                   0);
    548      cc_stats_vegas_csig_beta_ma =
    549          stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
    550                                   100);
    551      cc_stats_vegas_csig_delta_ma =
    552          stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
    553                                   0);
    554    } else if (cc->cwnd_full &&
    555               queue_use < cc->vegas_params.alpha) {
    556      cc->cwnd += CWND_INC(cc);
    557 
    558      /* Percentage counters: Add 100% alpha, 0 for other two */
    559      cc_stats_vegas_csig_alpha_ma =
    560          stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
    561                                   100);
    562      cc_stats_vegas_csig_beta_ma =
    563          stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
    564                                   0);
    565      cc_stats_vegas_csig_delta_ma =
    566          stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
    567                                   0);
    568    } else {
    569      /* Percentage counters: No signal this round. Add 0% to all */
    570      cc_stats_vegas_csig_alpha_ma =
    571          stats_update_running_avg(cc_stats_vegas_csig_alpha_ma,
    572                                   0);
    573      cc_stats_vegas_csig_beta_ma =
    574          stats_update_running_avg(cc_stats_vegas_csig_beta_ma,
    575                                   0);
    576      cc_stats_vegas_csig_delta_ma =
    577          stats_update_running_avg(cc_stats_vegas_csig_delta_ma,
    578                                   0);
    579    }
    580 
    581    /* cwnd can never fall below 1 increment */
    582    cc->cwnd = MAX(cc->cwnd, cc->cwnd_min);
    583 
    584    congestion_control_vegas_log(circ, cc);
    585 
    586    /* Update metrics */
    587    cc_stats_vegas_queue_ma =
    588        stats_update_running_avg(cc_stats_vegas_queue_ma,
    589                                 queue_use);
    590    cc_stats_vegas_bdp_ma =
    591        stats_update_running_avg(cc_stats_vegas_bdp_ma,
    592                                 vegas_bdp(cc));
    593 
    594    /* Log if we're above the ss_cap */
    595    if (cc->cwnd >= cc->vegas_params.ss_cwnd_max) {
    596      log_info(LD_CIRC,
    597            "CC: TOR_VEGAS above ss_max in steady state for circ %d: %"PRIu64,
    598            circ->purpose, cc->cwnd);
    599    }
    600  }
    601 
    602  /* Reset event counters */
    603  if (cc->next_cwnd_event == 0) {
    604    cc->next_cwnd_event = SENDME_PER_CWND(cc);
    605  }
    606  if (cc->next_cc_event == 0) {
    607    cc->next_cc_event = CWND_UPDATE_RATE(cc);
    608  }
    609 
    610  /* Decide if enough time has passed to reset the cwnd utilization */
    611  if (cwnd_full_reset(cc))
    612    cc->cwnd_full = 0;
    613 
    614  /* Update inflight with ack */
    615  cc->inflight = cc->inflight - cc->sendme_inc;
    616 
    617  return 0;
    618 }