From 4fe05b29a41fa40992c8bcc9bce61392ff4e5a10 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 2 Jul 2020 12:20:32 -0700 Subject: Add RTT Congestion Control Tor proposal as #324. --- proposals/324-rtt-congestion-control.txt | 1125 ++++++++++++++++++++++++++++++ 1 file changed, 1125 insertions(+) create mode 100644 proposals/324-rtt-congestion-control.txt (limited to 'proposals/324-rtt-congestion-control.txt') diff --git a/proposals/324-rtt-congestion-control.txt b/proposals/324-rtt-congestion-control.txt new file mode 100644 index 0000000..b96c2f7 --- /dev/null +++ b/proposals/324-rtt-congestion-control.txt @@ -0,0 +1,1125 @@ +Filename: 324-rtt-congestion-control.txt +Title: RTT-based Congestion Control for Tor +Author: Mike Perry +Created: 02 July 2020 +Status: Open + + +0. Motivation [MOTIVATION] + +This proposal specifies how to incrementally deploy RTT-based congestion +control and improved queue management in Tor. It is written to allow us +to first deploy the system only at Exit relays, and then incrementally +improve the system by upgrading intermediate relays. + +Lack of congestion control is the reason why Tor has an inherent speed +limit of about 500KB/sec for downloads and uploads via Exits, and even +slower for onion services. Because our stream SENDME windows are fixed +at 500 cells per stream, and only ~500 bytes can be sent in one cell, +the max speed of a single Tor stream is 500*500/circuit_latency. This +works out to about 500KB/sec max sustained throughput for a single +download, even if circuit latency is as low as 500ms. + +Because onion services paths are more than twice the length of Exit +paths (and thus more than twice the circuit latency), onion service +throughput will always have less than half the throughput of Exit +throughput, until we deploy proper congestion control with dynamic +windows. + +Proper congestion control will remove this speed limit for both Exits +and onion services, as well as reduce memory requirements for fast Tor +relays, by reducing queue lengths. + +The high-level plan is to use Round Trip Time (RTT) as a primary +congestion signal, and compare the performance of two different +congestion window update algorithms that both use RTT as a congestion +signal. + +The combination of RTT-based congestion signaling, a congestion window +update algorithm, and Circuit-EWMA will get us the most if not all of +the benefits we seek, and only requires clients and Exits to upgrade to +use it. Once this is deployed, circuit bandwidth caps will no longer be +capped at ~500kb/sec by the fixed window sizes of SENDME; queue latency +will fall significantly; memory requirements at relays should plummet; +and transient bottlenecks in the network should dissipate. + +Extended background information on the choices made in this proposal can +be found at: + https://lists.torproject.org/pipermail/tor-dev/2020-June/014343.html + https://lists.torproject.org/pipermail/tor-dev/2020-January/014140.html + +An exhaustive list of citations for further reading is in Section +[CITATIONS]. + + +1. Overview [OVERVIEW] + +This proposal has five main sections, after this overview. These +sections are referenced [IN_ALL_CAPS] rather than by number, for easy +searching. + +Section [CONGESTION_SIGNALS] specifies how to use Tor's SENDME flow +control cells to measure circuit RTT, for use as an implicit congestion +signal. It also specifies an explicit congestion signal, which can be +used as a future optimization once all relays upgrade. + +Section [CONTROL_ALGORITHMS] specifies two candidate congestion window +upgrade mechanisms, which will be compared for performance in simulation +in Shadow, as well as evaluated on the live network, and tuned via +consensus parameters listed in [CONSENSUS_PARAMETERS]. + +Section [FLOW_CONTROL] specifies how to handle back-pressure when one of +the endpoints stops reading data, but data is still arriving. In +particular, it specifies what to do with streams that are not being read +by an application, but still have data arriving on them. + +Section [SYSTEM_INTERACTIONS] describes how congestion control will +interact with onion services, circuit padding, and conflux-style traffic +splitting. + +Section [EVALUATION] describes how we will evaluate and tune our +options for control algorithms and their parameters. + +Section [PROTOCOL_SPEC] describes the specific cell formats and +descriptor changes needed by this proposal. + +Section [SECURITY_ANALYSIS] provides information about the DoS and +traffic analysis properties of congestion control. + + +2. Congestion Signals [CONGESTION_SIGNALS] + +In order to detect congestion at relays on a circuit, Tor will use +circuit Round Trip Time (RTT) measurement. This signal will be used in +slightly different ways in our various [CONTROL_ALGORITHMS], which will +be compared against each other for optimum performance in Shadow and on +the live network. + +To facilitate this, we will also change SENDME accounting logic +slightly. These changes only require clients, exits, and dirauths to +update. + +As a future optimization, we also specify an explicit congestion signal. +This signal *will* require all relays on a circuit to upgrade to support +it, but it will reduce congestion by making the first congestion event +on a circuit much faster to detect. + +2.1 RTT measurement + +Recall that Tor clients, exits, and onion services send +RELAY_COMMAND_SENDME relay cells every CIRCWINDOW_INCREMENT (100) cells +of received RELAY_COMMAND_DATA. + +This allows those endpoints to measure the current circuit RTT, by +measuring the amount of time between sending of every 100th data cell +and the arrival of the SENDME command that the other endpoint +immediately sends to ack that 100th cell. + +Circuits will record the current RTT measurement as a field in their +circuit_t data structure. They will also record the minimum and maximum +RTT seen so far. + +Algorithms that make use of this RTT measurement for congestion +window update are specified in [CONTROL_ALGORITHMS]. + +2.2. SENDME behavior changes + +We will make four major changes to SENDME behavior to aid in computing +and using RTT as a congestion signal. + +First, we will need to establish a ProtoVer of "CCtrl=1" to signal +support by Exits for the new SENDME format and congestion control +algorithm mechanisms. We will need a similar announcement in the onion +service descriptors of services that support congestion control. + +Second, we will turn CIRCWINDOW_INCREMENT into a consensus parameter +'circwindow_inc', instead of using a hardcoded value of 100 cells. It is +likely that more frequent SENDME cells will provide quicker reaction to +congestion, since the RTT will be measured more often. If +experimentation in Shadow shows that more frequent SENDMEs reduce +congestion and improve performance but add significant overhead, we can +reduce SENDME overhead by allowing SENDME cells to carry stream data, as +well. + + TODO: If two endpoints view different consensus parameters for + 'circwindow_inc', we will have complications measuring RTT, + as well as complications for authenticated SENDME hash + accounting. We need a way for endpoints to negotiate SENDME + pacing with eachother, perhaps during circuit setup. This will + require changes to the Onionskin/CREATE cell format (and + RELAY_COMMAND_EXTEND), as mentioned in Section [PROTOCOL_SPEC]. + +Second, all end-to-end relay cells except RELAY_COMMAND_DROP and +RELAY_COMMAND_INTRODUCE1 will count towards SENDME cell counts. The +details behind how these cells are handled is addressed in section +[SYSTEM_INTERACTIONS]. + + TODO: List any other exceptions. There probably are some more. + +Third, authenticated SENDMEs can remain as-is in terms of protocol +behavior, but will require some implementation updates to account for +variable window sizes and variable SENDME pacing. In particular, the +sendme_last_digests list for auth sendmes needs updated checks for +larger windows and CIRCWINDOW_INCREMENT changes. Other functions to +examine include: + - circuit_sendme_cell_is_next() + - sendme_record_cell_digest_on_circ() + - sendme_record_received_cell_digest() + - sendme_record_sending_cell_digest() + - send_randomness_after_n_cells + +Fourth, stream level SENDMEs will be eliminated. Details on handling +streams and backpressure is covered in [FLOW_CONTROL]. + +2.3. Backward ECN signaling [BACKWARD_ECN] + +As an optimization after the RTT deployment, we will deploy an explicit +congestion control signal by allowing relays to modify the +cell_t.command field when they detect congestion, on circuits for which +all relays have support for this signal (as mediated by Tor protocol +version handshake via the client). This is taken from the Options +mail[1], section BACKWARD_ECN_TOR. + +To detect congestion in order to deliver this signal, we will deploy a +simplified version of the already-simple CoDel algorithm on each +outbound TLS connection at relays. + https://queue.acm.org/detail.cfm?id=2209336 + https://tools.ietf.org/html/rfc8289 + +Each cell will get a timestamp upon arrival at a relay that will allow +us to measure how long it spends in queues, all the way to hitting a TLS +outbuf. + +The duration of total circuitmux queue time for each cell will be +compared a consensus parameter 'min_queue_target', which is set to 5% of +min network RTT. (This mirrors the CoDel parameter of the same name). + +As soon as a cell of a circuit spends more than this time in queues, a +per-circuit flag 'ecn_exit_slow_start' will be set to 1. As soon as a +cell is available in the opposite direction on that circuit, the relay +will flip the cell_t.command of from CELL_COMMAND_RELAY to +CELL_COMMAND_RELAY_CONGESTION. (We must wait for a cell in the opposite +direction because that is the sender that caused the congestion). + +This enhancement will allow endpoints to very quickly exit from +[CONTROL_ALGORITHM] "slow start" phase (during which, the congestion +window increases exponentially). The ability to more quickly exit the +exponential slow start phase during congestion will help reduce queue +sizes at relays. + +To avoid side channels, this cell must only be flipped on +CELL_COMMAND_RELAY, and not CELL_COMMAND_RELAY_EARLY. Additionally, all +relays MUST enforce that only *one* such cell command is flipped, per +direction, per circuit. Any additional CELL_COMMAND_RELAY_CONGESTION +cells seen by any relay or client MUST cause those circuit participants +to immediately close the circuit. + +As a further optimization, if no relay cells are pending in the opposite +direction as congestion is happening, we can send a zero-filled cell +instead. In the forward direction of the circuit, we can send this cell +without any crypto layers, so long as further relays enforce that the +contents are zero-filled, to avoid side channels. + + +3. Congestion Window Update Algorithms [CONTROL_ALGORITHMS] + +We specify two candidate window update algorithms. The specification +describes the update algorithms for the slow start phase and the +steady state phase separately, with some explanation. Then the +combined algorithm is given. + +Note that these algorithms differ slightly from the background tor-dev +mails[1,2], due to corrections and improvements. Hence they have been +given different names than in those two mails. + +These algorithms will be evaluated by running Shadow simulations, to +help determine parameter ranges, but experimentation on the live network +will be required to determine which of these algorithms performs best +when in competition with our current SENDME behavior, as used by real +network traffic. This experimentation and tuning is detailed in section +[EVALUATION]. + +All of these algorithms have rules to update 'cwnd' - the current +congestion window. In the C Tor reference implementation, 'cwnd' is +called the circuit 'package_window'. C Tor also maintains a +'deliver_window', which it uses to track how many cells it has received, +in order to send the appropriate number of SENDME acks. + + TODO: This 'deliver_window' count can be updated by the other + endpoint using the congestion control rules to watch for + cheating. Alternatively, it can be simplified just to count + the number of cells we get until we send a SENDME. + +Implementation of different algorithms should be very simple - each +algorithm should have a different set of package_window update functions +depending on the selected algorithm, as specified by consensus parameter +'cc_alg'. + +For C Tor's current flow control, these functions are defined in sendme.c, +and are called by relay.c: + - sendme_note_circuit_data_packaged() + - sendme_circuit_data_received() + - sendme_circuit_consider_sending() + - sendme_process_circuit_level() + +Despite the complexity of the following algorithms in their TCP +implementations, their Tor equivalents are extremely simple, each being +just a handful of lines of C. This simplicity is possible because Tor +does not have to deal with out-of-order delivery, packet drops, +duplicate packets, and other network issues at the circuit layer, due to +the fact that Tor circuits already have reliability and in-order +delivery at that layer. + +We are also removing the aspects of TCP that cause the congestion +algorithm to reset into slow start after being idle for too long, or +after too many congestion signals. These are deliberate choices that +simplify the algorithms and also should provide better performance for +Tor workloads. + + TODO: We may want to experiment with adding revert-to-slow-start back + in, but slow start is very expensive in a lot of ways, so let's + see if we can avoid falling back into it, if at all possible. + +3.1. Tor Westwood: TCP Westwood using RTT signaling [TOR_WESTWOOD] + http://intronetworks.cs.luc.edu/1/html/newtcps.html#tcp-westwood + http://nrlweb.cs.ucla.edu/nrlweb/publication/download/99/2001-mobicom-0.pdf + http://cpham.perso.univ-pau.fr/TCP/ccr_v31.pdf + https://c3lab.poliba.it/images/d/d7/Westwood_linux.pdf + +Recall that TCP Westwood is basically TCP Reno, but it uses RTT to help +estimate the bandwidth-delay-product (BDP) of the link, and use that for +"Fast recovery" after a congestion signal arrives. + +We will also be using the RTT congestion signal as per BOOTLEG_RTT_TOR +here, from the Options mail[1] and Defenestrator paper[3]. Recall that +BOOTLEG_RTT_TOR emits a congestion signal when the current RTT falls +below some fractional threshold ('rtt_thresh') fraction between RTT_min +and RTT_max: + + RTT_current < (1−rtt_thresh)*RTT_min + rtt_thresh*RTT_max + +We can also optionally use the ECN signal described in [BACKWARD_ECN] +above, to exit Slow Start. + +Tor Westwood will require each circuit endpoint to maintain a +Bandwidth-Delay-Product (BDP) and Bandwidth Estimate (BWE) variable. + +The bandwidth estimate is the current congestion window size divided by +the RTT estimate: + + BWE = cwnd / RTT_current + +The BDP estimate is computed by multiplying the Bandwidth estimate by +the circuit latency: + + BDP = BWE * RTT_min + + TODO: Different papers on TCP Westwood and TCP Vegas recommend + different methods for calculating BWE. See citations for + details, but common options are 'packets_in_flight/RTT_current' + or 'circwindow_inc*sendme_arrival_rate'. They also recommend + averaging and filtering of the BWE, due to ack compression in + inbound queues. We will need to experiment to determine how to + best compute the BWE for Tor circuits. + +3.1.1. Tor Westwood: Slow Start + +Prior to the first congestion signal, Tor Westwood will update its +congestion window exponentially, as per Slow Start. + +Recall that this first congestion signal can be either BOOTLEG_RTT_TOR's +RTT threshold signal, or BACKWARD_ECN's cell command signal. + +For simplicity, we will just write the BOOTLEG_RTT_TOR check, which +compares the current RTT measurement to the observed min and max RTT, +using the consensus parameter 'rtt_thresh'. + +This section of the update algorithm is: + + cwnd = cwnd + circwindow_inc # For acked cells + + # BOOTLEG_RTT_TOR threshold check: + if RTT_current < (1−rtt_thresh)*RTT_min + rtt_thresh*RTT_max: + cwnd = cwnd + circwindow_inc # Exponential window growth + else: + BDP = BWE*RTT_min + cwnd = max(cwnd * cwnd_recovery_m, BDP) + in_slow_start = 0 + +Increasing the congestion window by 100 *more* cells every SENDME allows +the sender to send 100 *more* cells every 100 cells. Thus, this is an +exponential function that causes cwnd to double every cwnd cells. + +Once a congestion signal is experienced, Slow Start is exited, and the +Additive-Increase-Multiplicative-Decrease (AIMD) steady-state phase +begins. + +3.1.2. Tor Westwood: Steady State AIMD + +After slow start exits, in steady-state, after every SENDME response +without a congestion signal, the window is updated as: + + cwnd = cwnd + circwindow_inc # For acked cells + cwnd = cwnd + circwindow_inc/cwnd # Linear window growth + +This comes out to increasing cwnd by 1, every time cwnd cells are +successfully sent without a congestion signal occurring. Thus this is +additive linear growth, not exponential growth. + +If there is a congestion signal, cwnd is updated as: + + cwnd = cwnd + circwindow_inc # For acked cells + cwnd = max(cwnd * cwnd_recovery_m, BDP) # For window shrink + +This is called "Fast Recovery". If you dig into the citations, actual +TCP Westwood has some additional details for responding to multiple +packet losses that in some cases can fall back into slow-start, as well +as some smoothing of the BDP to make up for dropped acks. Tor does not +need either of these aspects of complexity. + +3.1.3. Tor Westwood: Complete SENDME Update Algorithm + +Here is the complete congestion window algorithm for Tor Westwood, using +only RTT signaling. + +This will run each time we get a SENDME (aka sendme_process_circuit_level()): + + in_slow_start = 1 # Per-circuit indicator + + Every received SENDME ack, do: + cwnd = cwnd + circwindow_inc # Update acked cells + + # BOOTLEG_RTT_TOR threshold; can also be BACKWARD_ECN check: + if RTT_current < (1−rtt_thresh)*RTT_min + rtt_thresh*RTT_max: + if in_slow_start: + cwnd = cwnd + circwindow_inc # Exponential growth + else: + cwnd = cwnd + circwindow_inc/cwnd # Linear growth + else: + BDP = BWE*RTT_min + cwnd = max(cwnd * cwnd_recovery_m, BDP) # Window shrink + in_slow_start = 0 + +3.2. Tor Vegas: TCP Vegas with Aggressive Slow Start [TOR_VEGAS] + http://intronetworks.cs.luc.edu/1/html/newtcps.html#tcp-vegas + http://pages.cs.wisc.edu/~akella/CS740/F08/740-Papers/BOP94.pdf + ftp://ftp.cs.princeton.edu/techreports/2000/628.pdf + +TCP Vegas control algorithm makes use of two RTT measurements: +RTT_current and RTT_min. Like TCP Westwood, it also maintains a +bandwidth estimate and a BDP estimate, but those can be simplified away +with algebra. + +The bandwidth estimate is the current congestion window size divided by +the RTT estimate: + + BWE = cwnd/RTT_current + +The extra queue use along a path can thus be estimated by first +estimating the path's bandwidth-delay product: + + BDP = BWE*RTT_min + +TCP Vegas then estimates the queue use caused by congestion as: + + queue_use = cwnd - BDP + = cwnd - cwnd*RTT_min/RTT_current + = cwnd * (1 - RTT_min/RTT_current) + +So only RTT_min and RTT_current need to be recorded to provide this +queue_use estimate. + + TODO: This simplification might not hold for some versions of BWE + and BDP estimation. See also the [TOR_WESTWOOD] section's TODO + and paper citations for both TCP Westwood and TCP Vegas. + +3.2.1. Tor Vegas Slow Start + +During slow start, we will increase our window exponentially, so long as +this queue_use estimate is below the 'vegas_gamma' consensus parameter. + +We also re-use the Tor Westwood backoff, upon exit from Slow Start. + +Note though that the exit from Slow Start for here does *not* use the +BOOTLEG_RTT_TOR style RTT threshold, and instead relies on the +queue_use calculation directly. + +Tor Vegas slow start can also be exited due to [BACKWARD_ECN] cell +signal, which is omitted for brevity and clarity. + + cwnd = cwnd + circwindow_inc # Ack cells + + if queue_use < vegas_gamma: # Vegas RTT check + cwnd = cwnd + circwindow_inc # Exponential growth + else: + cwnd = max(cwnd * cwnd_recovery_m, BDP) # Westwood backoff + in_slow_start = 0 + +3.2.2. Tor Vegas: Steady State Queue Tracking + +Recall that TCP Vegas does not use AIMD in the steady state. Because +TCP Vegas is actually trying to directly control the queue use +on the path, its updates are additive and subtractive only. + +If queue_use drops below a threshold alpha (typically 2-3 packets for +TCP Vegas, but perhaps double or triple that for our smaller cells), +then the congestion window is increased. If queue_use exceeds a +threshold beta (typically 4-6 packets, but again we should probably +double or triple this), then the congestion window is decreased. + + cwnd = cwnd + circwindow_inc # Ack cells + + if queue_use < vegas_alpha: + cwnd = cwnd + circwindow_inc/cwnd # linear growth + elif queue_use > vegas_beta: + cwnd = cwnd - circwindow_inc/cwnd # linear backoff + + TODO: Why not reduce the window by the number of packets that + queue_use is over or under the target value by, rather than + just 1 cell per cwnd? Need to ask some TCP folks, or experiment. + +3.2.3. Tor Vegas: Complete SENDME Update Algorithm + + in_slow_start = 1 # Per-circuit indicator + + Every received SENDME ack: + cwnd = cwnd + circwindow_inc # Update acked cells + + queue_use = cwnd * (1 - RTT_min/RTT_current) + + if in_slow_start: + if queue_use < vegas_gamma: + cwnd = cwnd + circwindow_inc # Exponential growth + else: + cwnd = max(cwnd * cwnd_recovery_m, BDP) # Westwood backoff + in_slow_start = 0 + else: + if queue_use < vegas_alpha: + cwnd = cwnd + circwindow_inc/cwnd # linear growth + elif queue_use > vegas_beta: + cwnd = cwnd - circwindow_inc/cwnd # linear backoff + + +4. Flow Control [FLOW_CONTROL] + +Flow control provides what is known as "pushback" -- the property that +if one endpoint stops reading data, the other endpoint stops sending +data. This prevents data from accumulating at points in the network, if +it is not being read fast enough by an application. + +Because Tor must multiplex many streams onto one circuit, and each +stream is mapped to another TCP socket, Tor's current pushback is rather +complicated and under-specified. In C Tor, it is implemented in the +following functions: + - circuit_consider_stop_edge_reading() + - connection_edge_package_raw_inbuf() + - circuit_resume_edge_reading() + +Tor currently maintains separate windows for each stream on a circuit, +to provide individual stream flow control. Circuit windows are SENDME +acked as soon as a relay data cell is decrypted and recognized. Stream +windows are only SENDME acked if the data can be delivered to an active +edge connection. This allows the circuit to continue to operate if an +endpoint refuses to read data off of one of the streams on the circuit. + +Because Tor streams can connect to many different applications and +endpoints per circuit, it is important to preserve the property that if +only one endpoint edge connection is inactive, it does not stall the +whole circuit, in case one of those endpoints is malfunctioning or +malicious. + +However, window-based stream flow control also imposes a speed limit on +individual streams. If the stream window size is below the circuit +congestion window size, then it becomes the speed limit of a download, +as we saw in the [MOTIVATION] section of this proposal. + +So for performance, it is optimal that each stream window is the same +size as the circuit's congestion window. However, large stream windows +are a vector for OOM attacks, because malicious clients can force Exits +to buffer a full stream window for each stream while connecting to a +malicious site and uploading data that the site does not read from its +socket. This attack is significantly easier to perform at the stream +level than on the circuit level, because of the multiplier effects of +only needing to establish a single fast circuit to perform the attack on +a very large number of streams. + +This catch22 means that if we use windows for stream flow control, we +either have to commit to allocating a full congestion window worth +memory for each stream, or impose a speed limit on our streams. + +Hence, we will discard stream windows entirely, and instead use a +simpler buffer-based design that uses XON/XOFF as a backstop. This will +allow us to make full use of the circuit congestion window for every +stream in combination, while still avoiding buffer buildup inside the +network. + +4.1. Stream Flow Control Without Windows [WINDOWLESS_FLOW] + +Each endpoint (client, Exit, or onion service) should send circuit-level +SENDME acks for all circuit cells as soon as they are decrypted and +recognized, but *before* delivery to their edge connections. If the edge +connection is blocked because an application is not reading, data will +build up in a queue at that endpoint. + +Three consensus parameters will govern the max length of this queue: +xoff_client, xoff_exit, and xoff_mobile. These will be used for Tor +clients, exits, and mobile devices, respectively. These cuttofs will be +a percentage of current 'cwnd' rather than number of cells. Something +like 5% of 'cwnd' should be plenty, since these edge connections should +normally drain *much* faster than Tor itself. + +If the length of an application stream queue exceeds the size provided +in the appropriate consensus parameter, a RELAY_COMMAND_STREAM_XOFF will +be sent, which instructs the other endpoint to stop sending from that +edge connection. This XOFF cell can optionally contain any available +stream data, as well. + +As soon as the queue begins to drain, a RELAY_COMMAND_STREAM_XON will +sent, which allows the other end to resume reading on that edge +connection. Because application streams should drain quickly once they +are active, we will send the XON command as soon as they start draining. +If the queues fill again, another XOFF will be sent. If this results in +excessive XOFF/XON flapping and chatter, we will also use consensus +parameters xon_client, xon_exit, and xon_mobile to optionally specify +when to send an XON. These parameters will be defined in terms of cells +below the xoff_* levels, rather than percentage. The XON cells can also +contain stream data, if any is available. + +Tor's OOM killer will be invoked to close any streams whose application +buffer grows too large, due to memory shortage, or malicious endpoints. + +Note that no stream buffer should ever grow larger than the xoff level +plus 'cwnd', unless an endpoint is ignoring XOFF. So, +'xoff_{client,exit,mobile} + cwnd' should be the hard-close stream +cutoff, regardless of OOM killer status. + + +5. System Interactions [SYSTEM_INTERACTIONS] + +Tor's circuit-level SENDME system currently has special cases in the +following situations: Intropoints, HSDirs, onion services, and circuit +padding. Additionally, proper congestion control will allow us to very +easily implement conflux (circuit traffic splitting). + +This section details those special cases and interactions of congestion +control with other components of Tor. + +5.1. HSDirs + +Because HSDirs use the tunneled dirconn mechanism and thus also use +RELAY_COMMAND_DATA, they are already subject to Tor's flow control. + +We may want to make sure our initial circuit window for HSDir circuits +is set custom for those circuit types, so a SENDME is not required to +fetch long descriptors. This will ensure HSDir descriptors can be +fetched in one RTT. + +5.2. Introduction Points + +Introduction Points are not currently subject to any flow control. + +Because Intropoints accept INTRODUCE1 cells from many client circuits +and then relay them down a single circuit to the service as INTRODUCE2 +cells, we cannot provide end-to-end congestion control all the way from +client to service for these cells. + +We can run congestion control from the service to the Intropoint, +however, and if that congestion window reaches zero (because the service +is overwhelmed), then we start sending NACKS back to the clients (or +begin requiring proof-of-work), rather than just let clients wait for +timeout. + +5.3. Rendezvous Points + +Rendezvous points are already subject to end-to-end SENDME control, +because all relay cells are sent end-to-end via the rendezvous circuit +splice in circuit_receive_relay_cell(). + +This means that rendezvous circuits will use end-to-end congestion +control, as soon as individual onion clients and onion services upgrade +to support it. There is no need for intermediate relays to upgrade at +all. + +5.4. Circuit Padding + +Recall that circuit padding is negotiated between a client and a middle +relay, with one or more state machines running on circuits at the middle +relay that decide when to add padding. + https://github.com/torproject/tor/blob/master/doc/HACKING/CircuitPaddingDevelopment.md + +This means that the middle relay can send padding traffic towards the +client that contributes to congestion, and the client may also send +padding towards the middle relay, that also creates congestion. + +For low-traffic padding machines, such as the currently deployed circuit +setup obfuscation, this padding is inconsequential. + +However, higher traffic circuit padding machines that are designed to +defend against website traffic fingerprinting will need additional care +to avoid inducing additional congestion, especially after the client or +the exit experiences a congestion signal. + +The current overhead percentage rate limiting features of the circuit +padding system should handle this in some cases, but in other cases, an +XON/XOFF circuit padding flow control command may be required, so that +clients may signal to the machine that congestion is occurring. + +5.5. Conflux + +Conflux (aka multi-circuit traffic splitting) becomes significantly +easier to implement once we have congestion control. However, much like +congestion control, it will require experimentation to tune properly. + +Recall that Conflux uses a 256-bit UUID to bind two circuits together at +the Exit or onion service. The original Conflux paper specified an +equation based on RTT to choose which circuit to send cells on. + https://www.cypherpunks.ca/~iang/pubs/conflux-pets.pdf + +However, with congestion control, we will already know which circuit has +the larger congestion window, and thus has the most available cells in +its current congestion window. This will also be the faster circuit. +Thus, the decision of which circuit to send a cell on only requires +comparing congestion windows (and choosing the circuit with more packets +remaining in its window). + +Conflux will require sequence numbers on data cells, to ensure that the +two circuits' data is properly re-assembled. The resulting out-of-order +buffer can potentially be as large as an entire congestion window, if +the circuits are very desynced (or one of them closes). It will be very +expensive for Exits to maintain this much memory, and exposes them to +OOM attacks. + +This is not as much of a concern in the client download direction, since +clients will typically only have a small number of these out-of-order +buffers to keep around. But for the upload direction, Exits will need +to send some form of early XOFF on the faster circuit if this +out-of-order buffer begins to grow too large, since simply halting the +delivery of SENDMEs will still allow a full congestion window full of +data to arrive. This will also require tuning and experimentation, and +optimum results will vary between simulator and live network. + + TODO: Can we use explicit SENDME sequence number acking to make a + connection-resumption conflux, to recover from circuit collapse + or client migration? I am having trouble coming up with a design + that does not require Exits to maintain a full congestion + window full of data as a retransmit buffer in the event of + circuit close. Such reconnect activity might require assistance + from Guard relays so that they can help clients discover which + cells were sent vs lost. + + +6. Performance Evaluation [EVALUATION] + +Congestion control for Tor will be easy to implement, but difficult to +tune to ensure optimal behavior. + +6.1. Congestion Signal Experiments + +Our first experiments will be to conduct client-side experiments to +determine how stable the RTT measurements of circuits are across the +live Tor network, to determine if we need more frequent SENDMEs, and/or +need to use any RTT smoothing or averaging. + +Once we have a reliable way to measure RTT, we will need to test the +reliability and accuracy of the Bandwidth Estimation (BWE) and +Bandwidth-Delay-Product (BDP) measurements that are required for +[TOR_WESTWOOD] and [TOR_VEGAS]. These experiments can be conducted in +Shadow, with precise network topologies for which actual bandwidth and +latency (and thus BWE and BDP) are known parameters. We should use the +most accurate form of these estimators from Shadow experimentation to +run some client tests with custom Exits on the live network, to check +for high variability in these estimates, discrepancy with client +application throughput and application latency, and other surprises. + +Care will need to be taken to increase or alter Tor's circwindow during +these experiments in Shadow and on the custom Exits, so that the default +of 1000 does not impose an artificial ceiling on circuit bandwidth. + +6.2. Congestion Algorithm Experiments + +In order to evaluate performance of congestion control algorithms, we +will need to implement [TOR_WESTWOOD], [TOR_VEGAS], and also variants of +those without the Westwood BDP fast recovery backoff. We will need to +simulate their use in the Shadow Tor network simulator. + +Simulation runs will need to evaluate performance on networks that use +only one algorithm, as well as on networks that run a combinations of +algorithms - particularly each type of congestion control in combination +with Tor's current flow control. If Tor's current flow control is too +aggressive, we can experiment with kneecapping these legacy flow control +Tor clients by setting a low 'circwindow' consensus parameter for them. + +Because custom congestion control can be deployed by any Exit or onion +service that desires better service, we will need to be particularly +careful about how congestion control algorithms interact with rogue +implementations that more aggressively increase their window sizes. +During these adversarial-style experiments, we must verify that cheaters +do not get better service, and that Tor's circuit OOM killer properly +closes circuits that seriously abuse the congestion control algorithm, +as per [SECURITY_ANALYSIS]. + +Finally, we should determine if the [BACKWARD_ECN] cell_t.command +congestion signal is enough of an optimization to be worth the +complexity, especially if it is only used once, to exit slow start. This +can be determined in Shadow. + +6.3. Flow Control Algorithm Experiments + +We will need to tune the xoff_* consensus parameters to minimize the +amount of edge connection buffering as well as XON/XOFF chatter for +Exits. This can be done in simulation, but will require fine-tuning on +the live network. + +Relays will need to report these statistics in extra-info descriptor, +to help with monitoring the live network conditions. + +6.4. Performance Metrics [EVALUATION_METRICS] + +Because congestion control will affect so many aspects of performance, +from throughput to RTT, to load balancing, queue length, overload, and +other failure conditions, the full set of performance metrics will be +required: + https://trac.torproject.org/projects/tor/wiki/org/roadmaps/CoreTor/PerformanceMetrics + +We will also need to monitor network health for relay queue lengths, +relay overload, and other signs of network stress (and particularly the +alleviation of network stress). + +6.5. Consensus Parameter Tuning [CONSENSUS_PARAMETERS] + +During Shadow simulation, we will determine reasonable default +parameters for our consensus parameters for each algorithm. We will then +re-run these tuning experiments on the live Tor network, as described +in: + https://trac.torproject.org/projects/tor/wiki/org/roadmaps/CoreTor/PerformanceExperiments + +The following list is the complete set of network consensus parameters +referenced in this proposal, sorted roughly in order of importance (most +important to tune first): + + cc_alg: + - Description: + Specifies which congestion control algorithm clients should + use, as an integer. + - Range: [0,2] (0=fixed, 1=Westwood, 2=Vegas) + - Default: 2 + + cwnd_recovery_m: + - Description: Specifies how much to reduce the congestion + window after a congestion signal, as a fraction of + 100. + - Range: [0, 100] + - Default: 70 + + circwindow: + - Description: Initial congestion window for legacy Tor clients + - Range: [1, 1000] + - Default: 1000 (reduced if legacy Tor clients compete unfairly) + + circwindow_cc: + - Description: Initial congestion window for new congestion + control Tor clients. + - Range: [1, 1000] + - Default: 10-100 + + rtt_thresh: + - Description: + Specifies the cutoff for BOOTLEG_RTT_TOR to deliver + congestion signal, as fixed point representation + divided by 1000. + - Range: [1, 1000] + - Default: 230 + + vegas_alpha + vegas_beta + vegas_gamma + - Description: These parameters govern the number of cells + that [TOR_VEGAS] can detect in queue before reacting. + - Range: [1, 1000] + - Defaults: 6,12,12 + + circwindow_inc: + - Description: Specifies how many cells a SENDME acks + - Range: [1, 5000] + - Default: 100 + + min_queue_target: + - Description: How long in milliseconds can a cell spend in + a relay's queues before we declare its circuit congested? + - Range: [1, 10000] + - Default: 10 + + xoff_client + xoff_mobile + xoff_exit + - Description: Specifies the stream queue size as a percentage of + 'cwnd' at an endpoint before an XOFF is sent. + - Range: [1, 100] + - Default: 5 + + xon_client + xon_mobile + xon_exit + - Description: Specifies the how many cells below xoff_* before + an XON is sent from an endpoint. + - Range: [1, 10000000] + - Default: 10000 + + +7. Protocol format specifications [PROTOCOL_SPEC] + + TODO: This section needs details once we close out other TODOs above. + +7.1. Circuit window handshake format + + TODO: We need to specify a way to communicate the currently seen + circwindow_inc consensus parameter to the other endpoint, + due to consensus sync delay. Probably during the CREATE + onionskin (and RELAY_COMMAND_EXTEND). + TODO: We probably want stricter rules on the range of values + for the per-circuit negotiation - something like + it has to be between [circwindow_inc/2, 2*circwindow_inc]. + That way, we can limit weird per-circuit values, but still + allow us to change the consensus value in increments. + +7.2. XON/XOFF relay cell formats + + TODO: We need to specify XON/XOFF for flow control. This should be + simple. + TODO: We should also allow it to carry stream data. + +7.3. Onion Service formats + + TODO: We need to specify how to signal support for congestion control + in an onion service, to both the intropoint and to clients. + +7.4. Protocol Version format + + TODO: We need to pick a protover to signal Exit and Intropoint + congestion control support. + +7.5. SENDME relay cell format + + TODO: We need to specify how to add stream data to a SENDME as an + optimization. + +7.6. BACKWARD_ECN signal format + + TODO: We need to specify exactly which byte to flip in cells + to signal congestion on a circuit. + + TODO: Black magic will allow us to send zero-filled BACKWARD_ECN + cells in the *wrong* direction in a circuit, towards the Exit - + ie with no crypto layers at all. If we enforce strict format + and zero-filling of these cells at intermediate relays, we can + avoid side channels there, too. (Such a hack allows us to + send BACKWARD_ECN without any wait, if there are no relay cells + that are available heading in the backward direction, towards + the endpoint that caused congestion). + +7.7. Extrainfo descriptor formats + + TODO: We will want to gather information on circuitmux and other + relay queues, as well as XON/XOFF rates, and edge connection + queue lengths at exits. + + +8. Security Analysis [SECURITY_ANALYSIS] + +The security risks of congestion control come in three forms: DoS +attacks, fairness abuse, and side channel risk. + +8.1. DoS Attacks (aka Adversarial Buffer Bloat) + +The most serious risk of eliminating our current window cap is that +endpoints can abuse this situation to create huge queues and thus DoS +Tor relays. + +This form of attack was already studied against the Tor network in the +Sniper attack: + https://www.freehaven.net/anonbib/cache/sniper14.pdf + +We had two fixes for this. First, we implemented a circuit-level OOM +killer that closed circuits whose queues became too big, before the +relay OOMed and crashed. + +Second, we implemented authenticated SENDMEs, so clients could not +artificially increase their window sizes with honest exits: + https://gitweb.torproject.org/torspec.git/tree/proposals/289-authenticated-sendmes.txt + +We can continue this kind of enforcement by having Exit relays ensure +that clients are not transmitting SENDMEs too often, and do not appear +to be inflating their send windows beyond what the Exit expects by +calculating a similar receive window. + +Unfortunately, authenticated SENDMEs do *not* prevent the same attack +from being done by rogue exits, or rogue onion services. For that, we +rely solely on the circuit OOM killer. During our experimentation, we +must ensure that the circuit OOM killer works properly to close circuits +in these scenarios. + +But in any case, it is important to note that we are not any worse off +with congestion control than we were before, with respect to these kinds +of DoS attacks. In fact, the deployment of congestion control by honest +clients should reduce queue use and overall memory use in relays, +allowing them to be more resilient to OOM attacks than before. + +8.2. Congestion Control Fairness Abuse (aka Cheating) + +On the Internet, significant research and engineering effort has been +devoted to ensuring that congestion control algorithms are "fair" in +that each connection receives equal throughput. This fairness is +provided both via the congestion control algorithm, as well as via queue +management algorithms at Internet routers. + +One of the most unfortunate early results was that TCP Vegas, despite +being near-optimal at minimizing queue lengths at routers, was easily +out-performed by more aggressive algorithms that tolerated larger queue +delay (such as TCP Reno). + +Note that because the most common direction of traffic for Tor is from +Exit to client, unless Exits are malicious, we do not need to worry +about rogue algorithms as much, but we should still examine them in our +experiments because of the possibility of malicious Exits, as well as +malicious onion services. + +Queue management can help further mitigate this risk, too. When RTT is +used as a congestion signal, our current Circuit-EWMA queue management +algorithm is likely sufficient for this. Because Circuit-EWMA will add +additional delay to loud circuits, "cheaters" who use alternate +congestion control algorithms to inflate their congestion windows should +end up with more RTT congestion signals than those who do not, and the +Circuit-EWMA scheduler will also relay fewer of their cells per time +interval. + +In this sense, we do not need to worry about fairness and cheating as a +security property, but a lack of fairness in the congestion control +algorithm *will* increase memory use in relays to queue these +unfair/loud circuits, perhaps enough to trigger the OOM killer. So we +should still be mindful of these properties in selecting our congestion +control algorithm, to minimize relay memory use, if nothing else. + +These two properties (honest Exits and Circuit-EWMA) may even be enough +to make it possible to use [TOR_VEGAS] even in the presence of other +algorithms, which would be a huge win in terms of memory savings as well +as vastly reduced queue delay. We must verify this experimentally, +though. + +8.3. Side Channel Risks + +Vastly reduced queue delay and predictable amounts of congestion on the +Tor network may make certain forms of traffic analysis easier. +Additionally, the ability to measure RTT and have it be stable due to +minimal network congestion may make geographical inference attacks +easier: + https://www.freehaven.net/anonbib/cache/ccs07-latency-leak.pdf + https://www.robgjansen.com/publications/howlow-pets2013.pdf + +It is an open question as to if these risks are serious enough to +warrant eliminating the ability to measure RTT at the protocol level and +abandoning it as a congestion signal, in favor of other approaches +(which have their own side channel risks). It will be difficult to +comprehensively eliminate RTT measurements, too. + +On the plus side, Conflux traffic splitting (which is made easy once +congestion control is implemented) does show promise as providing +defense against traffic analysis: + https://www.comsys.rwth-aachen.de/fileadmin/papers/2019/2019-delacadena-splitting-defense.pdf + +There is also literature on shaping circuit bandwidth to create a side +channel. This can be done regardless of the use of congestion control, +and is not an argument against using congestion control. In fact, the +Backlit defense may be an argument in favor of endpoints monitoring +circuit bandwidth and latency more closely, as a defense: + https://www.freehaven.net/anonbib/cache/ndss09-rainbow.pdf + https://www.freehaven.net/anonbib/cache/ndss11-swirl.pdf + https://www.freehaven.net/anonbib/cache/acsac11-backlit.pdf + +Finally, recall that we are considering BACKWARD_ECN to use a +circuit-level cell_t.command to signal congestion. This allows all +relays in the path to signal congestion in under RTT/2 in either +direction, and it can be flipped on existing relay cells already in +transit, without introducing any overhead. However, because +cell_t.command is visible and malleable to all relays, it can also be +used as a side channel. So we must limit its use to a couple of cells +per circuit, at most. + https://blog.torproject.org/tor-security-advisory-relay-early-traffic-confirmation-attack + + +9. [CITATIONS] + +1. Options for Congestion Control in Tor-Like Networks. + https://lists.torproject.org/pipermail/tor-dev/2020-January/014140.html + +2. Towards Congestion Control Deployment in Tor-like Networks. + https://lists.torproject.org/pipermail/tor-dev/2020-June/014343.html + +3. DefenestraTor: Throwing out Windows in Tor. + https://www.cypherpunks.ca/~iang/pubs/defenestrator.pdf + +4. TCP Westwood: Bandwidth Estimation for Enhanced Transport over Wireless Links + http://nrlweb.cs.ucla.edu/nrlweb/publication/download/99/2001-mobicom-0.pdf + +5. Performance Evaluation and Comparison of Westwood+, New Reno, and Vegas TCP Congestion Control + http://cpham.perso.univ-pau.fr/TCP/ccr_v31.pdf + +6. Linux 2.4 Implementation of Westwood+ TCP with rate-halving + https://c3lab.poliba.it/images/d/d7/Westwood_linux.pdf + +7. TCP Westwood + http://intronetworks.cs.luc.edu/1/html/newtcps.html#tcp-westwood + +8. TCP Vegas: New Techniques for Congestion Detection and Avoidance + http://pages.cs.wisc.edu/~akella/CS740/F08/740-Papers/BOP94.pdf + +9. Understanding TCP Vegas: A Duality Model + ftp://ftp.cs.princeton.edu/techreports/2000/628.pdf + +10. TCP Vegas + http://intronetworks.cs.luc.edu/1/html/newtcps.html#tcp-vegas + +11. Controlling Queue Delay + https://queue.acm.org/detail.cfm?id=2209336 + +12. Controlled Delay Active Queue Management + https://tools.ietf.org/html/rfc8289 + +13. How Much Anonymity does Network Latency Leak? + https://www.freehaven.net/anonbib/cache/ccs07-latency-leak.pdf + +14. How Low Can You Go: Balancing Performance with Anonymity in Tor + https://www.robgjansen.com/publications/howlow-pets2013.pdf + +15. POSTER: Traffic Splitting to Counter Website Fingerprinting + https://www.comsys.rwth-aachen.de/fileadmin/papers/2019/2019-delacadena-splitting-defense.pdf + +16. RAINBOW: A Robust And Invisible Non-Blind Watermark for Network Flows + https://www.freehaven.net/anonbib/cache/ndss09-rainbow.pdf + +17. SWIRL: A Scalable Watermark to Detect Correlated Network Flows + https://www.freehaven.net/anonbib/cache/ndss11-swirl.pdf + +18. Exposing Invisible Timing-based Traffic Watermarks with BACKLIT + https://www.freehaven.net/anonbib/cache/acsac11-backlit.pdf + +19. The Sniper Attack: Anonymously Deanonymizing and Disabling the Tor Network + https://www.freehaven.net/anonbib/cache/sniper14.pdf + +20. Authenticating sendme cells to mitigate bandwidth attacks + https://gitweb.torproject.org/torspec.git/tree/proposals/289-authenticated-sendmes.txt + +21. Tor security advisory: "relay early" traffic confirmation attack + https://blog.torproject.org/tor-security-advisory-relay-early-traffic-confirmation-attack + +22. The Path Less Travelled: Overcoming Tor’s Bottlenecks with Traffic Splitting + https://www.cypherpunks.ca/~iang/pubs/conflux-pets.pdf + +23. Circuit Padding Developer Documentation + https://github.com/torproject/tor/blob/master/doc/HACKING/CircuitPaddingDevelopment.md + +24. Plans for Tor Live Network Performance Experiments + https://trac.torproject.org/projects/tor/wiki/org/roadmaps/CoreTor/PerformanceExperiments + +25. Tor Performance Metrics for Live Network Tuning + https://trac.torproject.org/projects/tor/wiki/org/roadmaps/CoreTor/PerformanceMetrics + -- cgit v1.2.3-54-g00ecf