Flow 1.0.2
Flow project: Full implementation reference.
cong_ctl_classic_bw.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
25
26namespace flow::net_flow
27{
28// Types.
29
30/**
31 * Classic congestion control but with backoff to bandwidth estimate-based pipe size.
32 * Implements Congestion_control_strategy abstract API.
33 *
34 * The basic idea is the same as in Congestion_control_classic. See that class's doc header first.
35 * Except where noted below, the algorithm is identical.
36 *
37 * The difference is that instead of halving (or otherwise lowering by an arbitrary constant factor)
38 * the window, we set the window to a pipe width based on our estimate of the available bandwidth
39 * and the inherent latency in the pipe. The latter is tracked by keeping the minimum individual
40 * packet RTT observed thus far; the former (bandwidth estimate) is obtained from
41 * Send_bandwidth_estimator. Normally bandwidth estimation would be inside the congestion control
42 * strategy class, but since its results may be useful independently of congestion control, it is a
43 * separate module.
44 *
45 * The specifics of the implementation are based on Westwood/Westwood+. The part about computing
46 * the pipe width based on B * RTTmin comes from the original Westwood paper. The bandwidth
47 * estimation algorithm is based on Westwood+ and is discussed in further detail in class
48 * Send_bandwidth_estimator. The reference implementation is Linux kernel's Westwood+
49 * implementation; see Send_bandwidth_estimator doc header for references.
50 *
51 * The strength of this algorithm is that it is potentially less timid in the face of random loss as
52 * opposed to true congestion, when compared to Congestion_control_classic (Reno). It won't just halve
53 * CWND at the slightest provocation. On the other hand bandwidth estimation seems to, in my tests
54 * at least, kind of measure the rate at which we're sending data and less the actual available
55 * pipe. Still, at least at lower latencies and loss rates it can greatly outperform
56 * Congestion_control_classic; though at higher such values it can actually be worse (at least in my
57 * crude tests -- more formal testing with real simulation TBD).
58 *
59 * @see Congestion_control_classic, Send_bandwidth_estimator.
60 */
63{
64public:
65 // Constructors/destructor.
66
67 /**
68 * Constructs object by setting up logging and saving a pointer to the containing Peer_socket.
69 * Congestion window is chosen to be some small initial value, and an exponential congestion
70 * window growth is set up to continue indefinitely, until a loss event, drop timeout, or idle
71 * timeout.
72 *
73 * Only a weak pointer of `sock` is stored: the `shared_ptr` itself is not saved, so the reference
74 * count of `sock` does not increase. This avoids a circular `shared_ptr` situation that would arise
75 * from `*this` pointing to `sock`, and `sock` pointing to `*this` (the two objects *do* need access
76 * to each other, as explained in class Congestion_control_strategy doc header).
77 *
78 * @param logger_ptr
79 * The Logger implementation to use subsequently.
80 * @param sock
81 * The Peer_socket for which this module will control congestion policy.
82 */
84
85 // Methods.
86
87 /**
88 * Implements Congestion_control_strategy::congestion_window_bytes() API.
89 * @return See Congestion_control_strategy::congestion_window_bytes().
90 */
91 size_t congestion_window_bytes() const override;
92
93 /**
94 * Implements Congestion_control_strategy::on_individual_ack() API. This results in no
95 * congestion_window_bytes() change but may affect its later values.
96 *
97 * Internally this gauges the "true" latency of the pipe.
98 *
99 * @param packet_rtt
100 * See Congestion_control_strategy::on_individual_ack().
101 * @param bytes
102 * See Congestion_control_strategy::on_individual_ack().
103 * @param sent_cwnd_bytes
104 * See Congestion_control_strategy::on_individual_ack().
105 */
106 void on_individual_ack(const Fine_duration& packet_rtt, const size_t bytes, const size_t sent_cwnd_bytes) override;
107
108 /**
109 * Implements Congestion_control_strategy::on_acks() API. Congestion window grows either linearly
110 * (in congestion avoidance mode) or exponentially (in slow start mode). There is no congestion
111 * avoidance mode until at least one of on_loss_event() or on_drop_timeout() occurs; at least
112 * until then slow start is in effect.
113 *
114 * Additional Peer_socket state used: none.
115 *
116 * @param bytes
117 * See Congestion_control_strategy::on_acks().
118 * @param packets
119 * See Congestion_control_strategy::on_acks().
120 */
121 void on_acks(size_t bytes, size_t packets) override;
122
123 /**
124 * Implements Congestion_control_strategy::on_loss_event() API. Congestion window changes
125 * (probably drops) to a value based on the estimation of the available outgoing bandwidth, and
126 * the next slow start (if any, e.g., on a later Drop Timeout) will end once the congestion window
127 * exceeds this value. Thus after this call congestion avoidance mode begins anew.
128 *
129 * Additional Peer_socket state used: none.
130 *
131 * @param bytes
132 * See Congestion_control_strategy::on_loss_event().
133 * @param packets
134 * See Congestion_control_strategy::on_loss_event().
135 */
136 void on_loss_event(size_t bytes, size_t packets) override;
137
138 /**
139 * Implements Congestion_control_strategy::on_drop_timeout() API. Congestion window is set to a
140 * low value, while the next slow start session is set to end at a pipe width based on the
141 * estimation of the available outgoing bandwidth. Thus a slow start session, most
142 * likely, begins.
143 *
144 * Internally this also may affect our gauge of the "true" latency of the pipe.
145 *
146 * Additional Peer_socket state used: none.
147 *
148 * @param bytes
149 * See Congestion_control_strategy::on_drop_timeout().
150 * @param packets
151 * See Congestion_control_strategy::on_drop_timeout().
152 */
153 void on_drop_timeout(size_t bytes, size_t packets) override;
154
155 /**
156 * Implements Congestion_control_strategy::on_idle_timeout() API. Congestion window is set to a
157 * low value. Thus a slow start session begins.
158 *
159 * Additional Peer_socket state used: none.
160 */
161 void on_idle_timeout() override;
162
163private:
164 // Methods.
165
166 /**
167 * Returns the best bandwidth/latency-based guess for what the current window (pipe) size should
168 * be.
169 *
170 * @return A CWND/SSTHRESH-suitable value.
171 */
173
174 // Constants.
175
176 /**
177 * The initial value for #m_rtt_min, until one RTT measurement comes in. Initialize to
178 * conservatively large value. I considered making this configurable, but it doesn't seem worth
179 * it, as we'll get a real RTT sample with the very first ACK that arrives. Also the Linux
180 * `tcp_westwood.c` reference implementation does the same thing (a hard constant).
181 */
183
184 // Data.
185
186 /// The Reno CWND/SSTHRESH-changing engine and CWND/SSTHRESH storage.
188
189 /**
190 * The minimum individual packet's RTT observed so far; it should be reset to the next sample if
191 * #m_reset_rtt_min is `true`, which may happen if our algorithm thinks the pipe has changed
192 * drastically, making past measurements useless.
193 */
195
196 /**
197 * If `true`, then when the next RTT measurement comes in, any past measurement should be
198 * disregarded, and #m_rtt_min should be set to the new measurement. Do this if the pipe may have
199 * drastically changed, obsoleting any prior observations.
200 */
202}; // class Congestion_control_classic_with_bandwidth_est
203
204} // 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 but with backoff to bandwidth estimate-based pipe size.
static const Send_bandwidth_estimator::Time_unit S_INIT_RTT_MIN
The initial value for m_rtt_min, until one RTT measurement comes in.
void on_drop_timeout(size_t bytes, size_t packets) override
Implements Congestion_control_strategy::on_drop_timeout() API.
void on_idle_timeout() override
Implements Congestion_control_strategy::on_idle_timeout() API.
bool m_reset_rtt_min
If true, then when the next RTT measurement comes in, any past measurement should be disregarded,...
void on_acks(size_t bytes, size_t packets) override
Implements Congestion_control_strategy::on_acks() API.
void on_individual_ack(const Fine_duration &packet_rtt, const size_t bytes, const size_t sent_cwnd_bytes) override
Implements Congestion_control_strategy::on_individual_ack() API.
void on_loss_event(size_t bytes, size_t packets) override
Implements Congestion_control_strategy::on_loss_event() API.
size_t congestion_window_adjusted_bytes() const
Returns the best bandwidth/latency-based guess for what the current window (pipe) size should be.
Send_bandwidth_estimator::Time_unit m_rtt_min
The minimum individual packet's RTT observed so far; it should be reset to the next sample if m_reset...
Congestion_control_classic_with_bandwidth_est(log::Logger *logger_ptr, Peer_socket::Const_ptr sock)
Constructs object by setting up logging and saving a pointer to the containing Peer_socket.
Congestion_control_classic_data m_classic_data
The Reno CWND/SSTHRESH-changing engine and CWND/SSTHRESH storage.
size_t congestion_window_bytes() const override
Implements Congestion_control_strategy::congestion_window_bytes() API.
The abstract interface for a per-socket module that determines the socket's congestion control behavi...
Definition: cong_ctl.hpp:180
boost::chrono::milliseconds Time_unit
The primary time unit over which this class reports bandwidth.
Definition: bandwidth.hpp:167
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
Fine_clock::duration Fine_duration
A high-res time duration as computed from two Fine_time_pts.
Definition: common.hpp:411