Flow 1.0.0
Flow project: Full implementation reference.
cong_ctl_classic.hpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
24
25namespace flow::net_flow
26{
27// Types.
28
29/**
30 * Classic congestion control, based on Reno (TCP RFC 5681), with congestion avoidance, slow start,
31 * and congestion window halving (etc.) upon a loss event. Implements Congestion_control_strategy
32 * abstract API.
33 *
34 * The basic idea is: start with a narrow pipe. With each acknowledgment, grow the width of the
35 * pipe exponentially (a/k/a "slow start"). Eventually this will either hit the maximum width or
36 * cause loss. Once loss is detected, guess that the "steady-state" pipe width is about half of that
37 * at the point where loss occurred, set the pipe to that width and increase the pipe width but
38 * slowly (linearly) as acknowledgments arrive (a/k/a "congestion avoidance"). Eventually this
39 * will cause loss again: again guess pipe is half that width and start at that width and increase
40 * linearly (congestion avoidance again). Continue indefinitely. This results in the
41 * characteristic CWND vs. time graph, where CWND first explodes up, then goes up diagonally and
42 * vertically down, up, down, up, down, like a saw edge.
43 *
44 * Additionally, on major loss (Drop Timeout), guess the steady state pipe width as above but reset
45 * the actual pipe width to its narrowest value. This will cause exponential growth again until the
46 * steady state pipe width is reached, then linear growth.
47 *
48 * On idle timeout (when connection is seen as idle in the send direction), reset the pipe to its
49 * original narrow width but make no change to the steady-state pipe width.
50 *
51 * The strength of this algorithm is that it's time-tested and saved the Internet from collapsing.
52 * The weakness is that once it encounters loss -- which may well be random loss and not a sign of
53 * congestion -- it backs off very conservatively (half). This means in a somewhat lossy
54 * environment one flow like this will fail to take advantage of the available bandwidth.
55 *
56 * @note The above refers to "half" the pipe width being used when backing off due to loss, as in classic Reno,
57 * but actually we make it configurable through socket options.
58 *
59 * @see Congestion_control_classic_with_bandwidth_est that acts similarly but instead of backing
60 * off conservatively to half (etc.) the pipe, backs off to an estimate as to the available
61 * pipe width based on a bandwidth estimator.
62 */
65{
66public:
67 // Constructors/destructor.
68
69 /**
70 * Constructs object by setting up logging and saving a pointer to the containing Peer_socket.
71 * Congestion window is chosen to be some small initial value, and an exponential congestion
72 * window growth is set up to continue indefinitely, until a loss event, drop timeout, or idle
73 * timeout.
74 *
75 * Only a weak pointer of `sock` is stored: the `shared_ptr` itself is not saved, so the reference
76 * count of `sock` does not increase. This avoids a circular `shared_ptr` situation that would arise
77 * from `*this` pointing to `sock`, and `sock` pointing to `*this` (the two objects *do* need access
78 * to each other, as explained in class Congestion_control_strategy doc header).
79 *
80 * @param logger_ptr
81 * The Logger implementation to use subsequently.
82 * @param sock
83 * The Peer_socket for which this module will control congestion policy.
84 */
86
87 // Methods.
88
89 /**
90 * Implements Congestion_control_strategy::congestion_window_bytes() API.
91 * @return See Congestion_control_strategy::congestion_window_bytes().
92 */
93 size_t congestion_window_bytes() const override;
94
95 /**
96 * Implements Congestion_control_strategy::on_acks() API. Congestion window grows either linearly
97 * (in congestion avoidance mode) or exponentially (in slow start mode). There is no congestion
98 * avoidance mode until at least one of on_loss_event() or on_drop_timeout() occurs; at least
99 * until then slow start is in effect.
100 *
101 * Additional Peer_socket state used: none.
102 *
103 * @param bytes
104 * See Congestion_control_strategy::on_acks().
105 * @param packets
106 * See Congestion_control_strategy::on_acks().
107 */
108 void on_acks(size_t bytes, size_t packets) override;
109
110 /**
111 * Implements Congestion_control_strategy::on_loss_event() API. Congestion window changes to some
112 * configurable constant fraction (like half) of its current value, and the next slow start (if
113 * any, e.g., on a later Drop Timeout) will end once the congestion window exceeds this value.
114 * Thus after this call congestion avoidance mode begins anew.
115 *
116 * Additional Peer_socket state used: Peer_socket::m_snd_flying_bytes (the # of bytes still In-flight
117 * after the loss event).
118 *
119 * @param bytes
120 * See Congestion_control_strategy::on_loss_event().
121 * @param packets
122 * See Congestion_control_strategy::on_loss_event().
123 */
124 void on_loss_event(size_t bytes, size_t packets) override;
125
126 /**
127 * Implements Congestion_control_strategy::on_drop_timeout() API. Congestion window is set to a
128 * low value, while the next slow start session is set to end at roughly half (or some
129 * configurable constant fraction) of the current (pre-decrease) congestion window. Thus a slow
130 * start session begins.
131 *
132 * Additional Peer_socket state used: Peer_socket::m_snd_flying_bytes (the # of bytes still In-flight
133 * after the loss event implied by the timeout).
134 *
135 * @param bytes
136 * See Congestion_control_strategy::on_drop_timeout().
137 * @param packets
138 * See Congestion_control_strategy::on_drop_timeout().
139 */
140 void on_drop_timeout(size_t bytes, size_t packets) override;
141
142 /**
143 * Implements Congestion_control_strategy::on_idle_timeout() API. Congestion window is set to a
144 * low value. Thus a slow start session begins.
145 *
146 * Additional Peer_socket state used: none.
147 */
148 void on_idle_timeout() override;
149
150private:
151 // Methods.
152
153 /**
154 * Returns the decay (as a percentage) to apply to the congestion window upon encounterling loss.
155 * RFC 5681-3.2.1 and formula (4) say this should 50 (i.e., halve it); but we make it configurable
156 * by a socket option.
157 *
158 * @return A percentage in the range [1, 100].
159 */
160 unsigned int congestion_window_decay() const;
161
162 // Data.
163
164 /// The Reno CWND/SSTHRESH-changing engine and CWND/SSTHRESH storage.
166}; // class Congestion_control_classic
167
168} // namespace flow::net_flow
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1291
Utility class for use by Congestion_control_strategy implementations that implements congestion windo...
Classic congestion control, based on Reno (TCP RFC 5681), with congestion avoidance,...
Congestion_control_classic_data m_classic_data
The Reno CWND/SSTHRESH-changing engine and CWND/SSTHRESH storage.
void on_acks(size_t bytes, size_t packets) override
Implements Congestion_control_strategy::on_acks() API.
void on_idle_timeout() override
Implements Congestion_control_strategy::on_idle_timeout() API.
void on_drop_timeout(size_t bytes, size_t packets) override
Implements Congestion_control_strategy::on_drop_timeout() API.
unsigned int congestion_window_decay() const
Returns the decay (as a percentage) to apply to the congestion window upon encounterling loss.
size_t congestion_window_bytes() const override
Implements Congestion_control_strategy::congestion_window_bytes() API.
Congestion_control_classic(log::Logger *logger_ptr, Peer_socket::Const_ptr sock)
Constructs object by setting up logging and saving a pointer to the containing Peer_socket.
void on_loss_event(size_t bytes, size_t packets) override
Implements Congestion_control_strategy::on_loss_event() API.
The abstract interface for a per-socket module that determines the socket's congestion control behavi...
Definition: cong_ctl.hpp:180
Const_target_ptr Const_ptr
Short-hand for ref-counted pointer to immutable values of type Target_type::element_type (a-la T cons...
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25