Flow 2.0.0
Flow project: Full implementation reference.
options.cpp
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
21#include <boost/algorithm/string.hpp>
22
23// Internal macros (#undef at the end of file).
24
25/// @cond
26/* -^- Doxygen, please ignore the following. (Don't want docs generated for temp macro; this is more maintainable
27 * than specifying the macro name to omit it, in Doxygen-config EXCLUDE_SYMBOLS.) */
28
29#define ADD_CONFIG_OPTION(ARG_opt, ARG_desc) \
30 Node_options::add_config_option(opts_desc, #ARG_opt, &target->ARG_opt, defaults_source.ARG_opt, ARG_desc, \
31 printout_only)
32
33// -v- Doxygen, please stop ignoring.
34/// @endcond
35
36namespace flow::net_flow
37{
38
39// Implementations.
40
42 // They definitely need to opt into this.
43 m_st_capture_interrupt_signals_internally(false),
44 /* OS is under no obligation to take this literally and will probably impose its own limit which
45 * may be smaller than this. In Linux 2.6.x I've observed the limit can't go higher than somewhere
46 * between 1MB and 2MB. Anyway, we pick a reasonable value and hope it has some effect. */
47 m_st_low_lvl_max_buf_size(3 * 1024 * 1024),
48 // Let the code pick something reasonable based on platform, hopefully.
49 m_st_timer_min_period(0),
50 // Allow unlimited # of packets per loop iteration for now.
51 m_dyn_max_packets_per_main_loop_iteration(0),
52 // default max_block_size + a SMALL overhead.
53 m_dyn_low_lvl_max_packet_size(1124),
54 // This default is explained in the option description (as of this writing): it's faster.
55 m_dyn_guarantee_one_low_lvl_in_buf_per_socket(true),
56 // For TCP these days values like ~500 are not-atypical, but let's be modest by default.
57 m_dyn_accept_backlog_limit(64)
58{
59 // Nothing.
60}
61
62template<typename Opt_type>
64 const std::string& opt_id,
65 Opt_type* target_val, const Opt_type& default_val,
66 const char* description, bool printout_only) // Static.
67{
68 using boost::program_options::value;
69 if (printout_only)
70 {
71 opts_desc->add_options()
72 (opt_id_to_str(opt_id).c_str(), value<Opt_type>()->default_value(default_val));
73 }
74 else
75 {
76 opts_desc->add_options()
77 (opt_id_to_str(opt_id).c_str(), value<Opt_type>(target_val)->default_value(default_val),
78 description);
79 }
80}
81
83 Node_options* target,
84 const Node_options& defaults_source,
85 bool printout_only) // Static.
86{
87 ADD_CONFIG_OPTION
89 "If and only if this is true, the Node will detect SIGINT and SIGTERM (or your OS's version thereof); "
90 "upon seeing such a signal, it will fire Node::interrupt_all_waits(), which will interrupt all "
91 "blocking operations, conceptually similarly to POSIX's EINTR. If this is true, the user may register "
92 "their own signal handler(s) (for any purpose whatsoever) using boost::asio::signal_set. However, behavior "
93 "is undefined if the program registers signal handlers via any other API, such as sigaction() or signal(). "
94 "If you need to set up such a non-signal_set signal handler, AND you require EINTR-like behavior, "
95 "then (1) set this option to false; (2) trap SIGINT and SIGTERM yourself; (3) in your handlers for the "
96 "latter, simply call Node::interrupt_all_waits(). Similarly, if you want custom behavior regarding "
97 "Node::interrupt_all_waits(), feel free to call it whenever you want (not necessarily even from a signal "
98 "handler), and set this to false. However, if a typical, common-sense behavior is what you're after -- and "
99 "either don't need additional signal handling or are OK with using signal_set for it -- then setting this to "
100 "true is a good option.");
101 ADD_CONFIG_OPTION
103 "The max size to ask the OS to set our UDP socket's receive buffer to in order to minimize loss "
104 "if we can't process datagrams fast enough. This should be as high as possible while being "
105 "\"acceptable\" in terms of memory. However, the OS will probably have its own limit and may well "
106 "pick a limit that is the minimum of that limit and this value.");
107 ADD_CONFIG_OPTION
109 "A time period such that the boost.asio timer implementation for this platform is able to "
110 "accurately able to schedule events within this time period or greater. If you select 0, the "
111 "code will decide what this value based on the platform, but its logic for this may or may not "
112 "be correct (actually it will probably be correct but possibly too conservative [large], causing "
113 "timer coarseness in mechanisms like packet pacing).");
114 ADD_CONFIG_OPTION
116 "The UDP net-stack may deliver 2 or more datagrams to the Flow Node at the same time. To lower overhead "
117 "and increase efficiency, Flow will process all such datagrams -- and any more that may arrive during this "
118 "processing -- before preparing any resulting outgoing messages, such as acknowledgments or more data packets. "
119 "In high-speed conditions this may result in excessive burstiness of outgoing traffic. This option's value "
120 "places a limit on the number of datagrams to process before constructing and sending any resulting outgoing "
121 "messages to prevent this burstiness. If 0, there is no limit.");
122 ADD_CONFIG_OPTION
124 "Any incoming low-level (UDP) packet will be truncated to this size. This should be well above "
125 "per-socket max-block-size (# of bytes of user payload per DATA packet). There will only be one buffer "
126 "of this size in memory at a time, so no need to be too stingy, but on the other hand certain "
127 "allocation/deallocation behavior may cause performance drops if this unnecessarily large.");
128 ADD_CONFIG_OPTION
130 "This very inside-baseball setting controls the allocation/copy behavior of the UDP receive-deserialize "
131 "operation sequence. When enabled, there is exactly one input buffer large enough to "
132 "hold any one serialized incoming packet; any deserialized data (including DATA and ACK payloads) are "
133 "stored in separately allocated per-packet buffers; and and the input buffer is repeatedly reused "
134 "without reallocation. When disabled, however, at least some packet types (most notably DATA) will "
135 "use the zero-copy principle, having the deserializer take ownership of the input buffer and access pieces "
136 "inside it as post-deserialization values (most notably the DATA payload); in this case the input buffer "
137 "has to be reallocated between UDP reads. As of this writing the former behavior seems to be somewhat "
138 "faster, especially if low-lvl-max-packet-size is unnecessarily large; but arguably the zero-copy behavior "
139 "may become faster if some implementation details related to this change. So this switch seemed worth "
140 "keeping.");
141 ADD_CONFIG_OPTION
143 "Maximum backlog size for each `Server_socket` subsequently created via `Node::listen()`. The backlog "
144 "(for a given `Server_socket`) is defined as the total number of connections either in SYN_RCVD state "
145 "(SYN_ACK sent, awaiting SYN_ACK_ACK) or in ESTABLISHED state but not yet user-accepted via "
146 "`Server_socket::*accept()`. When a SYN arrives while the backlog is full, it is rejected with an RST "
147 "response. This value is captured at `Node::listen()` time and fixed for the resulting `Server_socket`'s "
148 "lifetime; subsequent changes affect only `Server_socket`s created by later `listen()` calls. "
149 "It *is* dynamic at the `Node` level, but does *not* dynamically affect existing listening `Server_socket`s.");
150
152 &target->m_dyn_sock_opts,
153 defaults_source.m_dyn_sock_opts,
154 printout_only);
155} // Node_options::setup_config_parsing_helper()
156
158{
159 // Set up *opts_desc to parse into *this when the caller chooses to. Take defaults from *this.
160 setup_config_parsing_helper(opts_desc, this, *this, false);
161} // Node_options::setup_config_parsing()
162
163std::ostream& operator<<(std::ostream& os, const Node_options& opts)
164{
165 Node_options sink;
166 Node_options::Options_description opts_desc{"Per-net_flow::Node option values"};
167 Node_options::setup_config_parsing_helper(&opts_desc, &sink, opts, true);
168 return os << opts_desc;
169}
170
171std::string Node_options::opt_id_to_str(const std::string& opt_id) // Static.
172{
173 using boost::algorithm::starts_with;
174 using boost::algorithm::replace_all;
175 using std::string;
176
177 const string STATIC_PREFIX = "m_st_";
178 const string DYNAMIC_PREFIX = "m_dyn_";
179
180 string str = opt_id;
181 if (starts_with(opt_id, STATIC_PREFIX))
182 {
183 str.erase(0, STATIC_PREFIX.size());
184 }
185 else if (starts_with(opt_id, DYNAMIC_PREFIX))
186 {
187 str.erase(0, DYNAMIC_PREFIX.size());
188 }
189
190 replace_all(str, "_", "-");
191
192 return str;
193}
194
196 /* Should be a safe UDP datagram size. @todo Not a totally solid statement... plus it's too low;
197 * increasing to ~1500 increases throughput hugely. Choosing it dynamically is a @todo elsewhere
198 * in the code. */
199 m_st_max_block_size(1024),
200 // Initial value recommended by RFC 6298 is 1 sec but seems too conservative. @todo Decide.
201 m_st_connect_retransmit_period(boost::chrono::milliseconds{125}),
202 // @todo.
203 m_st_connect_retransmit_timeout(boost::chrono::seconds{3}),
204 /* @todo Reconsider. See also to-do in class Node doc header.
205 * WARNING! If you change this, ensure s_st_max_cong_wnd_blocks is still sufficiently small. */
206 m_st_snd_buf_max_size(6 * 1024 * 1024),
207 // @todo Ditto.
208 m_st_rcv_buf_max_size(m_st_snd_buf_max_size),
209 /* If not for SYN-flood-like possibility, this could be ~= m_st_rcv_buf_max_size. Instead let's keep it modest.
210 * It would after all be strange to receive a large number of DATAs without a single retried SYN_ACK_ACK. */
211 m_st_rcv_sync_rcvd_data_q_cumulative_max_size(64 * 1024),
212 // Disabling flow control is an emergency measure only.
213 m_st_rcv_flow_control_on(true),
214 // Seems reasonable. Should be a few hundred KB typically.
215 m_st_rcv_buf_max_size_slack_percent(10),
216 /* The value 50% is taken from BSD implementation (Stevens/Wright, TCP/IP Illustrated Vol. 2,
217 * 1995), although it's barely discussed there. It does make sense though; it should give the
218 * sender a large window to work with but also leave some time to allow our application layer to
219 * read off more bytes from Receive buffer after advertising the window at this mark. */
220 m_st_rcv_buf_max_size_to_advertise_percent(50),
221 /* This allows for about 2.2 Received_packet struct per maximally large packet in
222 * m_rcv_packets_with_gaps. So it's something like 10-20 bytes per 1k of DATA, or about 2-4%
223 * overhead. So it's conservative in terms of memory use. For any reasonably large max Receive
224 * buffer size, it's also at least 100 packets. If 100 packets arrive numbering higher than
225 * unreceived packet P, it's a VERY good bet P will never arrive. Thus it's also conservative in
226 * terms of loss. Finally, since this formula allows enough space to hold an entire
227 * m_rcv_syn_rcvd_data_q's worth of queued up packets, it won't throw away any queued up
228 * packets in SYN_RCVD state. */
229 m_st_rcv_max_packets_after_unrecvd_packet_ratio_percent(220),
230 // Satisfies RFC 5681 (500 ms max); taken from BSD implementation (Stevens/Wright, TCP/IP Illustrated Vol. 2, 1995).
231 m_st_delayed_ack_timer_period(boost::chrono::milliseconds{200}),
232 // Per RFC 5681.
233 m_st_max_full_blocks_before_ack_send(2),
234 m_st_rexmit_on(true),
235 // @todo Experiment and look at RFCs.
236 m_st_max_rexmissions_per_packet(15),
237 // @todo Experiment. RFC 6298 recommends this value.
238 m_st_init_drop_timeout(boost::chrono::seconds{1}),
239 // @todo Experiment. Choosing less aggressive values for now, except for m_st_drop_all_on_drop_timeout.
240 m_st_drop_packet_exactly_after_drop_timeout(false),
241 // Consistent with RFC 4341, but see discussion where it's used.
242 m_st_drop_all_on_drop_timeout(true),
243 // @todo Experiment. Choosing less aggressive values for now, except for m_st_drop_all_on_drop_timeout.
244 m_st_out_of_order_ack_restarts_drop_timer(true),
245 // @todo Experiment.
246 m_st_snd_pacing_enabled(true),
247 /* Value taken from Linux's westwood.c which was written by the creators of Westwood+ bandwidth
248 * estimation algorithm themselves. 50 msec seems like a reasonable line in the sand between
249 * "small RTT" and "medium RTT." */
250 m_st_snd_bandwidth_est_sample_period_floor(boost::chrono::milliseconds{50}),
251 // Pass in a non-existent strategy ID, which will cause our operator<<() to choose what it considers the default.
252 m_st_cong_ctl_strategy(boost::lexical_cast<Congestion_control_strategy_choice>("none")),
253 // Let code choose initial CWND using RFC 5681 method.
254 m_st_cong_ctl_init_cong_wnd_blocks(0),
255 /* See the constraints in the doc header for this constant. That said, here are the calculations I
256 * used to get 640:
257 *
258 * this option = B * RTT / max-block-size = 100 Mbits/sec * 50 msec * 1/1024 blocks/byte = 100
259 * Mbits/sec * 50 msec * 1/1000 sec/msec * 1/8 Mbytes/Mbits * 1024*1024 bytes/Mbytes / 1024 bytes
260 * = (100*50/1000/8*1024*1024/1024) blocks = 640 blocks. (Note the units cancel out properly.)
261 *
262 * Receive buffer is currently 6 Mbytes. 6 Mbytes / 640 blocks = 6 * 1024 * 1024 / (640 * 1024),
263 * which is a Receive buffer-to-CWND ratio of 9.6s.
264 *
265 * WARNING! If you change this, ensure m_st_max_rcv_buf_size is still sufficiently large. */
266 m_st_cong_ctl_max_cong_wnd_blocks(640),
267 // Per RFC 5681-3.1.
268 m_st_cong_ctl_cong_wnd_on_drop_timeout_blocks(1),
269 // Use RFC 5681 default (0 is special value).
270 m_st_cong_ctl_cong_avoidance_increment_blocks(0),
271 // Use RFC 5681 default (0 is special value).
272 m_st_cong_ctl_classic_wnd_decay_percent(0),
273 // The minimal allowed ceiling by RFC 6298.
274 m_dyn_drop_timeout_ceiling(boost::chrono::seconds{60}),
275 // RFC 6298 recommends this value.
276 m_dyn_drop_timeout_backoff_factor(2),
277 // This shouldn't be too bad. @todo Though it should probably be based off DTO or something....
278 m_dyn_rcv_wnd_recovery_timer_period(boost::chrono::seconds{1}),
279 // Seems OK. After a minute it's probably a lost cause.
280 m_dyn_rcv_wnd_recovery_max_period(boost::chrono::minutes{1})
281{
282 // Nothing.
283}
284
286 Peer_socket_options* target,
287 const Peer_socket_options& defaults_source,
288 bool printout_only) // Static.
289{
290 using std::vector;
291 using std::string;
292 using boost::algorithm::join;
293
294 // Build the comma-separated list of possible string values for enum m_st_cong_ctl_strategy, for help output.
295 vector<string> cong_strategy_ids;
296 Congestion_control_selector::get_ids(&cong_strategy_ids);
297 const string str_cong_strategy_ids = join(cong_strategy_ids, ", ");
298
299 ADD_CONFIG_OPTION
301 "The size of block that we will strive to (and will, assuming at least that many bytes are "
302 "available in Send buffer) pack into each outgoing DATA packet. It is assumed the other side is "
303 "following the same policy (any packets that do not -- i.e., exceed this size -- are dropped). "
304 "This is an important control; the higher it is the better for performance AS LONG AS it's not so "
305 "high it undergoes IP fragmentation (or does that even happen in UDP? if not, even worse -- "
306 "it'll just be dropped and not sent!). The performance impact is major; e.g., assuming no "
307 "fragmentation/dropping, we've seen a ~1500 byte MBS result in 20-30% higher throughput than "
308 "1024 byte MBS. "
309 "Additionally, if using net_flow module with no reliability feature -- i.e., if you want to perform FEC "
310 "or something else outside the Flow protocol -- then it is absolutely essential that EVERY send*() call "
311 "provides a buffer whose size is a multiple of max-block-size. Otherwise packet boundaries "
312 "will not be what you expect, and you will get what seems to be corrupted data at the "
313 "application layer (since our stream-based API has no way of knowing where your message begins "
314 "or ends). Alternatively you can encode message terminators or packet sizes, but since in "
315 "unreliable mode integrity of a given block is guaranteed only if all blocks align with "
316 "max-block-size boundaries, you'll still probably be screwed.");
317 ADD_CONFIG_OPTION
319 "How often to resend SYN or SYN_ACK while SYN_ACK or SYN_ACK_ACK, respectively, has not been received. "
320 "In other words, this controls the pause between retries during the connection opening phase, by either side, "
321 "if the other side is not responding with the appropriate response. "
322 "Examples: \"250 ms\", \"1 s\".");
323 ADD_CONFIG_OPTION
325 "How long from the first SYN or SYN_ACK to allow for connection handshake before aborting connection. "
326 "Examples: \"5500 ms\", \"60 seconds\".");
327 ADD_CONFIG_OPTION
329 "Maximum number of bytes that the Send buffer can hold. This determines how many bytes user can "
330 "send() while peer cannot send over network until send() refuses to take any more bytes. Note "
331 "that any value given will be increased, if necessary, to the nearest multiple of "
332 "max-block-size. This is important to preserve message boundaries when operating in "
333 "unreliable mode (guaranteed max-block-size-sized chunks of data will be sent out in their "
334 "entirety instead of being fragmented).");
335 ADD_CONFIG_OPTION
337 "Maximum number of bytes that the Receive buffer can hold. This determines how many bytes "
338 "can be received in the background by the Node without user doing any receive()s. "
339 "It is also rounded up to to the nearest multiple of max-block-size.");
340 ADD_CONFIG_OPTION
342 "Due to loss or reordering we may receive DATA packets before receiving the handshake-finishing SYN_ACK_ACK; "
343 "any such SYN_RCVD-state DATA packets beyond this cumulative payload size shall be silently dropped. "
344 "The value 0 will drop all such DATA packets.");
345 ADD_CONFIG_OPTION
347 "Whether flow control (a/k/a receive window a/k/a rcv_wnd management) is enabled. If this is "
348 "disabled, an infinite rcv_wnd will always be advertised to the sender; so if the Receive buffer "
349 "is exceeded packets are dropped as normal, but the sender will not know it should stop sending "
350 "until Receive buffer space is freed. If this is enabled, we keep the sender informed of how "
351 "much Receive buffer space is available, so it can suspend the flow as necessary.");
352 ADD_CONFIG_OPTION
354 "% of rcv-buf-max-size such that if Receive buffer stores up to (100 + this many) % of "
355 "rcv-buf-max-size bytes, the bytes will still be accepted. In other words, this allows the max "
356 "Receive buffer to hold slightly more than rcv-buf-max-size bytes. However, the current Receive "
357 "buffer capacity advertised to the other side of the connection will be based on the "
358 "non-inflated rcv-buf-max-size. This option provides some protection against the fact that the "
359 "receive window value sent to the other side will lag behind reality somewhat.");
360 ADD_CONFIG_OPTION
362 "% of rcv-buf-max-size that has to be freed, since the last receive window advertisement, via "
363 "user popping data from Receive buffer, before we must send a receive window advertisement. "
364 "Normally we send rcv_wnd to the other side opportunistically in every ACK; but there can be "
365 "situations when there is no packets to acknowledge, and hence we must specifically make a "
366 "packet just to send over rcv_wnd. Typically we should only need to do this if the buffer was "
367 "exceeded and is now significantly freed. This value must be in [1, 100], but anything over 50 "
368 "is probably pushing it.");
369 ADD_CONFIG_OPTION
371 "The limit on the size of Peer_socket::m_rcv_packets_with_gaps, expressed as what percentage the "
372 "maximal size of that structure times max-block-size is of the maximal Receive buffer size. For "
373 "example, if this is 200, then Peer_socket::m_rcv_packets_with_gaps can represent up to roughly "
374 "2x as many full-sized blocks as the Receive buffer can. This should also by far exceed any "
375 "sender congestion window max size to avoid packet loss. m_rcv_packets_with_gaps consists of all packets "
376 "such that at least one packet sequentially preceding them has not yet been received.");
377 ADD_CONFIG_OPTION
379 "The maximum amount of time to delay sending ACK with individual packet's acknowledgment since "
380 "receiving that individual packet. If set to zero duration, any given individual acknowledgment "
381 "is sent within a non-blocking amount of time of its DATA packet being read. Inspired by RFC "
382 "1122-4.2.3.2. Examples: \"200 ms\", \"550200 microseconds\".");
383 ADD_CONFIG_OPTION
385 "If there are at least this many TIMES max-block-size bytes' worth of individual acknowledgments "
386 "to be sent, then the delayed ACK timer is to be short-circuited, and the accumulated "
387 "acknowledgments are to be sent as soon as possible. Inspired by RFC 5681.");
388 ADD_CONFIG_OPTION
390 "Whether to enable reliability via retransmission. If false, a detected lost packet may have "
391 "implications on congestion control (speed at which further data are sent) but will not cause "
392 "that packet to be resent; receiver application code either has to be OK with missing packets or "
393 "must implement its own reliability (e.g., FEC). Packets may also be delivered in an order "
394 "different from the way they were sent. If true, the receiver need not worry about it, as any "
395 "lost packets will be retransmitted with no participation from the application code on either "
396 "side, as in TCP. Also as in TCP, this adds order preservation, so that the stream of bytes sent "
397 "will be exactly equal to the stream of bytes received. Retransmission removes the requirement "
398 "for the very exacting block-based way in which send() and friends must be called. "
399 "This option must have the same value on both sides of the connection, or the server will refuse "
400 "the connection.");
401 ADD_CONFIG_OPTION
403 "If retransmission is enabled and a given packet is retransmitted this many times and has to be "
404 "retransmitted yet again, the connection is reset. Should be positive.");
405 ADD_CONFIG_OPTION
407 "Once socket enters ESTABLISHED state, this is the value for m_snd_drop_timeout before the first RTT "
408 "measurement is made (the first valid acknowledgment arrives). Example: \"2 seconds\".");
409 ADD_CONFIG_OPTION
411 "If true, when scheduling Drop Timer, schedule it for Drop Timeout relative to the send time of "
412 "the earliest In-flight packet at the time. If false, also schedule DTO relative to the time of "
413 "scheduling. The latter is less aggressive and is recommended by RFC 6298.");
414 ADD_CONFIG_OPTION
416 "If true, when the Drop Timer fires, all In-flight packets are to be considered Dropped (and "
417 "thus the timer is to be disabled). If false, only the earliest In-flight packet is to be "
418 "considered Dropped (and thus the timer is to restart). RFC 6298 recommends false. true is more aggressive.");
419 ADD_CONFIG_OPTION
421 "If an In-flight packet is acknowledged, but it is not the earliest In-flight packet (i.e., it's "
422 "an out-of-order acknowledgment), and this is true, the timer is restarted. Otherwise the timer "
423 "continues to run. The former is less aggressive. RFC 6298 wording is ambiguous on what it "
424 "recommends (not clear if cumulative ACK only, or if SACK also qualifies).");
425 ADD_CONFIG_OPTION
427 "When estimating the available send bandwidth, each sample must be compiled over at least this long "
428 "of a time period, even if the SRTT is lower. Normally a sample is collected over at least an SRTT, but "
429 "computing a bandwidth sample over a quite short time period can produce funky results, hence this floor. "
430 "Send bandwidth estimation is used at least for some forms of congestion control.");
431 ADD_CONFIG_OPTION
433 "Enables or disables packet pacing, which attempts to spread out, without sacrificing overall "
434 "send throughput, outgoing low-level packets to prevent loss. If disabled, any packet that is "
435 "allowed by congestion/flow control to be sent over the wire is immediately sent to the UDP "
436 "net-stack; so for example if 200 packets are ready to send and are allowed to be sent, they're sent "
437 "at the same time. If enabled, they will be spread out over a reasonable time period instead. "
438 "Excessive burstiness can lead to major packet drops, so this can really help.");
439 ADD_CONFIG_OPTION
441 (string("The congestion control algorithm to use for the connection or connections. The choices are: [") +
442 str_cong_strategy_ids + "].").c_str());
443 ADD_CONFIG_OPTION
445 "The initial size of the congestion window, given in units of max-block-size-sized blocks. "
446 "The special value 0 means RFC 5681's automatic max-block-size-based computation should "
447 "be used instead.");
448 ADD_CONFIG_OPTION
450 "The constant that determines the CWND limit in congestion_window_at_limit() and "
451 "clamp_congestion_window() (in multiple of max-block-size). When choosing this value, use these "
452 "constraints: "
453 "(1) This limits total outgoing throughput. The throughput B will be <= CWND/RTT, where RTT is "
454 "roughly the RTT of the connection, and CWND == S_MAX_CONG_WND_BLOCKS * max-block-size. "
455 "Therefore, choose B and RTT values and set S_MAX_CONG_WND_BLOCKS = B * RTT / max-block-size "
456 "(B in bytes/second, RTT in seconds). "
457 "(2) Until we implement Receive window, this value should be much (say, 4x) less than the size "
458 "of the Receive buffer, to avoid situations where even a well-behaving user (i.e., user that "
459 "receive()s all data ASAP) cannot keep up with reading data off Receive buffer, forcing "
460 "net_flow to drop large swaths of incoming traffic. If CWND is much smaller than Receive "
461 "buffer size, then this avoids that problem.");
462 ADD_CONFIG_OPTION
464 "On Drop Timeout, set congestion window to this value times max-block-size.");
465 ADD_CONFIG_OPTION
467 "The multiple of max-block-size by which to increment CWND in congestion avoidance mode after receiving "
468 "at least a full CWND's worth of clean acknowledgments. RFC 5681 (classic Reno) mandates this is set to 1, "
469 "but we allow it to be overridden. The special value 0 causes the RFC value to be used.");
470 ADD_CONFIG_OPTION
472 "In classic congestion control, RFC 5681 specified the window should be halved on loss; this "
473 "option allows one to use a customer percentage instead. This should be a value in [1, "
474 "100] to have the window decay to that percentage of its previous value, or 0 to use the RFC "
475 "5681-recommended constant (50).");
476 ADD_CONFIG_OPTION
478 "Whenever the Drop Timer fires, upon the requisite Dropping of packet(s), the DTO (Drop Timeout) "
479 "is set to its current value times this factor, and then the timer is rescheduled accordingly. "
480 "RFC 6298 recommends 2. Another value might be 1 (disable feature). The lower the more "
481 "aggressive.");
482 ADD_CONFIG_OPTION
484 "When the mode triggered by rcv-buf-max-size-to-advertise-percent being exceeded is in effect, "
485 "to counteract the possibility of ACK loss the receive window is periodically advertised "
486 "subsequently -- with the period given by this option -- until either some new data arrive or "
487 "rcv-wnd-recovery-max-period is exceeded. Example: \"5 s\".");
488 ADD_CONFIG_OPTION
490 "Approximate amount of time since the beginning of rcv_wnd recovery due to "
491 "rcv-buf-max-size-to-advertise-percent until we give up and end that phase. Example: \"30 s\".");
492 ADD_CONFIG_OPTION
494 "Ceiling to impose on the Drop Timeout. Example: \"120 s\".");
495} // Peer_socket_options::setup_config_parsing_helper()
496
498{
499 // Set up *opts_desc to parse into *this when the caller chooses to. Take defaults from *this.
500 setup_config_parsing_helper(opts_desc, this, *this, false);
501} // Node_options::setup_config_parsing()
502
503std::ostream& operator<<(std::ostream& os, const Peer_socket_options& opts)
504{
506 Peer_socket_options::Options_description opts_desc("Per-net_flow::Peer_socket option values");
507 Peer_socket_options::setup_config_parsing_helper(&opts_desc, &sink, opts, true);
508 return os << opts_desc;
509}
510
511#undef ADD_CONFIG_OPTION // For cleanliness.
512
513} // namespace flow::net_flow
static void get_ids(std::vector< std::string > *ids)
Returns a list of strings, called IDs, each of which textually represents a distinct Congestion_contr...
Definition: cong_ctl.cpp:115
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25
std::ostream & operator<<(std::ostream &os, const Congestion_control_selector::Strategy_choice &strategy_choice)
Serializes a Peer_socket_options::Congestion_control_strategy_choice enum to a standard ostream – the...
Definition: cong_ctl.cpp:146
A set of low-level options affecting a single Flow Node, including Peer_socket objects and other obje...
Definition: options.hpp:456
unsigned int m_dyn_accept_backlog_limit
Maximum backlog size for each Server_socket subsequently created via Node::listen().
Definition: options.hpp:588
static void setup_config_parsing_helper(Options_description *opts_desc, Node_options *target, const Node_options &defaults_source, bool printout_only)
Loads the full set of boost.program_options config options into the given Options_description,...
Definition: options.cpp:82
void setup_config_parsing(Options_description *opts_desc)
Modifies a boost.program_options options description object to enable subsequent parsing of a command...
Definition: options.cpp:157
Node_options()
Constructs a Node_options with values equal to those used by Node when the Node creator chooses not t...
Definition: options.cpp:41
Peer_socket_options m_dyn_sock_opts
The set of per-Peer_socket options in this per-Node set of options.
Definition: options.hpp:600
size_t m_st_low_lvl_max_buf_size
The max size to ask the OS to set our UDP socket's receive buffer to in order to minimize loss if we ...
Definition: options.hpp:532
size_t m_dyn_low_lvl_max_packet_size
Any incoming low-level (UDP) packet will be truncated to this size.
Definition: options.hpp:560
unsigned int m_dyn_max_packets_per_main_loop_iteration
The UDP net-stack may deliver 2 or more datagrams to the Flow Node at the same time.
Definition: options.hpp:552
static void add_config_option(Options_description *opts_desc, const std::string &opt_id, Opt_type *target_val, const Opt_type &default_val, const char *description, bool printout_only)
A helper that adds a single option to a given Options_description, for use either in printing out the...
Definition: options.cpp:63
static std::string opt_id_to_str(const std::string &opt_id)
Helper that, for a given option m_blah, takes something like "m_blah_blah" and returns the similar mo...
Definition: options.cpp:171
Fine_duration m_st_timer_min_period
A time period such that the boost.asio timer implementation for this platform is able to accurately a...
Definition: options.hpp:541
bool m_dyn_guarantee_one_low_lvl_in_buf_per_socket
This very inside-baseball setting controls the allocation/copy behavior of the UDP receive-deserializ...
Definition: options.hpp:575
bool m_st_capture_interrupt_signals_internally
If and only if this is true, the Node will detect SIGINT and SIGTERM (or your OS's version thereof); ...
Definition: options.hpp:524
Peer_socket_options::Options_description Options_description
Short-hand for boost.program_options config options description. See setup_config_parsing().
Definition: options.hpp:460
A set of low-level options affecting a single Peer_socket.
Definition: options.hpp:36
Fine_duration m_st_init_drop_timeout
Once socket enters ESTABLISHED state, this is the value for Peer_socket::m_snd_drop_timeout until the...
Definition: options.hpp:233
unsigned int m_st_max_rexmissions_per_packet
If retransmission is enabled and a given packet is retransmitted this many times and has to be retran...
Definition: options.hpp:227
size_t m_st_rcv_buf_max_size
Maximum number of bytes that the Receive buffer can hold.
Definition: options.hpp:141
size_t m_st_cong_ctl_max_cong_wnd_blocks
The constant that determines the CWND limit in Congestion_control_classic_data::congestion_window_at_...
Definition: options.hpp:303
Fine_duration m_st_snd_bandwidth_est_sample_period_floor
When estimating the available send bandwidth, each sample must be compiled over at least this long of...
Definition: options.hpp:274
unsigned int m_st_cong_ctl_cong_avoidance_increment_blocks
The multiple of max-block-size by which to increment CWND in congestion avoidance mode after receivin...
Definition: options.hpp:313
size_t m_st_cong_ctl_cong_wnd_on_drop_timeout_blocks
On Drop Timeout, set congestion window to this value times max-block-size.
Definition: options.hpp:306
Fine_duration m_dyn_rcv_wnd_recovery_max_period
Approximate amount of time since the beginning of rcv_wnd recovery due to rcv-buf-max-size-to-adverti...
Definition: options.hpp:346
Congestion_control_strategy_choice
The possible choices for congestion control strategy for the socket.
Definition: options.hpp:63
size_t m_st_cong_ctl_init_cong_wnd_blocks
The initial size of the congestion window, given in units of max-block-size-sized blocks.
Definition: options.hpp:284
bool m_st_drop_packet_exactly_after_drop_timeout
If true, when scheduling Drop Timer, schedule it for Drop Timeout relative to the send time of the ea...
Definition: options.hpp:240
bool m_st_rexmit_on
Whether to enable reliability via retransmission.
Definition: options.hpp:221
size_t m_st_snd_buf_max_size
Maximum number of bytes that the Send buffer can hold.
Definition: options.hpp:134
Fine_duration m_st_connect_retransmit_period
How often to resend SYN or SYN_ACK while SYN_ACK or SYN_ACK_ACK, respectively, has not been received.
Definition: options.hpp:121
unsigned int m_st_rcv_buf_max_size_slack_percent
% of rcv-buf-max-size such that if Receive buffer stores up to (100 + this many) % of rcv-buf-max-siz...
Definition: options.hpp:167
void setup_config_parsing(Options_description *opts_desc)
Analogous to Node_options::setup_config_parsing().
Definition: options.cpp:497
size_t m_st_rcv_sync_rcvd_data_q_cumulative_max_size
Due to loss or reordering we may receive DATA packets before receiving the handshake-finishing SYN_AC...
Definition: options.hpp:148
Peer_socket_options()
Constructs a Peer_socket_options with values equal to those used by Node when the Node creator choose...
Definition: options.cpp:195
Fine_duration m_dyn_rcv_wnd_recovery_timer_period
When the mode triggered by rcv-buf-max-size-to-advertise-percent being exceeded is in effect,...
Definition: options.hpp:340
bool m_st_drop_all_on_drop_timeout
If true, when the Drop Timer fires, all In-flight packets are to be considered Dropped (and thus the ...
Definition: options.hpp:247
Fine_duration m_st_connect_retransmit_timeout
How long from the first SYN or SYN_ACK to allow for connection handshake before aborting connection.
Definition: options.hpp:124
Congestion_control_strategy_choice m_st_cong_ctl_strategy
The congestion control algorithm to use for the connection or connections.
Definition: options.hpp:277
static void setup_config_parsing_helper(Options_description *opts_desc, Peer_socket_options *target, const Peer_socket_options &defaults_source, bool printout_only)
Analogous to Node_options::setup_config_parsing_helper().
Definition: options.cpp:285
boost::program_options::options_description Options_description
Short-hand for boost.program_options config options description. See setup_config_parsing().
Definition: options.hpp:40
size_t m_st_max_full_blocks_before_ack_send
If there are at least this many TIMES max-block-size bytes' worth of individual acknowledgments to be...
Definition: options.hpp:205
bool m_st_snd_pacing_enabled
Enables or disables packet pacing, which attempts to spread out, without sacrificing overall send thr...
Definition: options.hpp:265
bool m_st_rcv_flow_control_on
Whether flow control (a/k/a receive window a/k/a rcv_wnd management) is enabled.
Definition: options.hpp:157
Fine_duration m_st_delayed_ack_timer_period
The maximum amount of time to delay sending ACK with individual packet's acknowledgment since receivi...
Definition: options.hpp:198
unsigned int m_dyn_drop_timeout_backoff_factor
Whenever the Drop Timer fires, upon the requisite Dropping of packet(s), the DTO (Drop Timeout) is se...
Definition: options.hpp:332
bool m_st_out_of_order_ack_restarts_drop_timer
If an In-flight packet is acknowledged, but it is not the earliest In-flight packet (i....
Definition: options.hpp:255
size_t m_st_max_block_size
The size of block that we will strive to (and will, assuming at least that many bytes are available i...
Definition: options.hpp:114
unsigned int m_st_cong_ctl_classic_wnd_decay_percent
In classic congestion control, RFC 5681 specifies the window should be halved on loss; this option al...
Definition: options.hpp:321
unsigned int m_st_rcv_buf_max_size_to_advertise_percent
% of rcv-buf-max-size that has to be freed, since the last receive window advertisement,...
Definition: options.hpp:178
unsigned int m_st_rcv_max_packets_after_unrecvd_packet_ratio_percent
The limit on the size of Peer_socket::m_rcv_packets_with_gaps, expressed as what percentage the maxim...
Definition: options.hpp:190
Fine_duration m_dyn_drop_timeout_ceiling
Ceiling to impose on the Drop Timeout.
Definition: options.hpp:324