Flow 1.0.0
Flow project: Full implementation reference.
net_env_simulator.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
22#include "flow/log/log.hpp"
23#include "flow/util/random.hpp"
24#include <boost/utility.hpp>
25#include <boost/random.hpp>
26#include <queue>
27#include <utility>
28
29namespace flow::net_flow
30{
31// Types.
32
33/**
34 * Objects of this class can be fed to Node to make it internally simulate network conditions like
35 * loss, latency, and data duplication. At construction one provides parameters controlling those
36 * phenomena; then when Node is about to receive or send some actual network traffic it asks this
37 * object whether it should first simulate some phenomenon like a lost packet. For example, if a
38 * loss probability is given at construction, bool should_drop_received_packet() will return whether
39 * the current received packet should be "dropped" instead of handled, which Node will simulate
40 * internally by ignoring or handling the packet.
41 *
42 * This is not really meant as a replacement for real tools that simulate such phenomena (or
43 * obviously the actual phenomena in a real network). The way it simulates them is probably
44 * unrealistic; for example a wide latency range given in the constructor will cause packets to be
45 * re-ordered quite a bit, whereas on a real network the packets are more likely to arrive in the
46 * right order but with widely varying latencies over time. Anyway -- the idea of using this is not
47 * to benchmark Node's performance under various network conditions; it is to test its correctness.
48 * For example: do frequent packet duplications and drops cause Node to enter an unexpected state
49 * and crash? What happens when an ESTABLISHED socket receives a late re-ordered SYN_ACK after
50 * already getting some DATA? Etc. etc.
51 *
52 * @todo One thing we should probably add for a bit of realism is the following. If a loss range
53 * [A, B] is specified, an individual packet's simulated latency will be a uniformly random number
54 * in that range. Because of this there will be frequent re-ordering of packets: if range
55 * is [50, 100] ms, and we physically get packet X at time 0 and packet Y at time 5 ms, and the
56 * simulated latencies are 80, 60 ms, respectively, then Y will "arrive" 80 - 60 - 5 = 15 ms BEFORE
57 * X despite being sent earlier (assuming perfect actual network conditions under the simulation).
58 * In reality, packets aren't re-ordered all that often. So if we wanted to simulate a high latency
59 * without re-ordering, we'd have to set the range to [A, A] for some A. To avoid having to do
60 * that, we can add some internal memory into Net_env_simulator that would put a floor on a randomly
61 * generated latency. In the previous example, the range for packet Y would be chosen as [75, 100]
62 * (instead of [50, 100]) to guarantee that packet Y arrives at least a bit later than packet X. Of
63 * course that might skew the latency range in bursty traffic, but that might be an OK behavior. We
64 * could add a knob for how often to ignore this new logic and allow a re-ordering, so that that is
65 * also simulated.
66 */
68 public log::Log_context,
69 private boost::noncopyable
70{
71public:
72 // Types.
73
74 /// Short-hand for the random seed integer type.
75 using seed_type_t = uint32_t;
76
77 /// Short-hand for floating point between 0 and 1 used to express probability.
78 using prob_type_t = double;
79
80 /// Short-hand for list of packet loss outcomes.
81 using Packet_loss_seq = std::queue<bool>;
82
83 /// Short-hand for list of packet duplication outcomes.
84 using Packet_dup_seq = std::queue<bool>;
85
86 /// Short-hand for list of packet latencies.
87 using Latency_seq = std::queue<Fine_duration>;
88
89 /// Short-hand for latency range [low, high].
90 using Latency_range = std::pair<Fine_duration, Fine_duration>;
91
92 // Constructors/destructor.
93
94 /**
95 * Constructs simulator.
96 *
97 * @param logger_ptr
98 * Logger to use for subsequently logging.
99 * @param random_seed
100 * Random seed to use for the internal random number generator. Assuming all else is equal
101 * (which can often be the case if all tested components are kept on the same
102 * machine/loopback), using the same seed twice to run the same operations should result in
103 * the same results. If 0 is provided, seed is chosen based on the current time.
104 * @param recv_packet_loss_prob
105 * Probability that the given received packet will get dropped instead of actually being
106 * received (0 is never; 1 is always; and anywhere in between). This probability is
107 * applied only once elements of recv_packet_loss_seq run out.
108 * @param recv_packet_loss_seq
109 * List of packet loss outcomes for received packets. When packet `i` (in chronological
110 * order) is received, it is dropped instead of actually being received if the `i`-th element
111 * in `recv_packet_loss_seq` is true; otherwise it is not so dropped. Once `i >=
112 * recv_packet_loss_seq.size()`, `recv_packet_loss_prob` is used instead.
113 * @param recv_latency_range
114 * The range to use for the randomly generated latencies for received packets. The pair
115 * specifies the [min, max] (inclusive) latency range in its first and second elements
116 * respectively. The latency is chosen uniformly along that range. This range is applied
117 * only once elements of `recv_latency_seq` run out.
118 * @param recv_latency_seq
119 * List of latency outcomes for received packets. When packet `i` (in chronological order)
120 * is received, it is lagged by N, where N is the `i`-th element in `recv_latency_seq`. Once `i
121 * >= recv_latency_seq.size()`, `recv_latency_range is used instead.
122 * @param recv_packet_dup_prob
123 * Probability that the given received packet will get duplicated in addition to actually
124 * being received (0 is never; 1 is always; and anywhere in between). This probability is
125 * applied only once elements of `recv_packet_dup_seq` run out.
126 * @param recv_packet_dup_seq
127 * List of packet loss outcomes for received packets. When packet `i` (in chronological
128 * order) is received, it is duplicated in addition to actually being received if
129 * the `i`-th element in `recv_packet_dup_seq` is true; otherwise it is not so duplicated. Once
130 * `i >= recv_packet_dup_seq.size()`, `recv_packet_dup_prob` is used instead.
131 */
132 explicit Net_env_simulator(log::Logger* logger_ptr,
133 seed_type_t random_seed = 0,
134 prob_type_t recv_packet_loss_prob = 0,
135 const Packet_loss_seq& recv_packet_loss_seq = Packet_loss_seq(),
136 const Latency_range& recv_latency_range = Latency_range(),
137 const Latency_seq& recv_latency_seq = Latency_seq(),
138 prob_type_t recv_packet_dup_prob = 0,
139 const Packet_dup_seq& recv_packet_dup_seq = Packet_dup_seq());
140
141 // Methods.
142
143 /**
144 * Low-level packet was received, but should we simulate that it was dropped before receipt?
145 * Probability and/or prescribed packet loss are set at construction.
146 *
147 * @return `true` if dropped; `false` otherwise.
148 */
150
151 /**
152 * Low-level packet was received and not dropped, but should we simulate that it was lagged by an
153 * additional amount of time, before actually getting received, and if so how much? Latency range
154 * and/or prescribed latencies are set at construction.
155 *
156 * @return How long the next packet should be lagged. May be zero.
157 */
159
160 /**
161 * Low-level packet was received, but should we simulate that it was duplicated?
162 * Probability and/or prescribed packet duplication decisions are set at construction.
163 *
164 * @return `true` if duplicated; `false` otherwise.
165 */
167
168private:
169 // Types.
170
171 /// Random number generator.
173
174 // Data.
175
176 /// Random seed for #m_rnd_generator (saved for reproducibility of "random" events).
178
179 /// Random number generator for various random events like packet loss.
181
182 /**
183 * At a given point in time, the `i`-th from now (in chronological order) received packet will be
184 * dropped if and only if the `i`-th element of #m_recv_packet_loss_seq is true. For example, the
185 * next packet will be dropped if and only if `m_recv_packet_loss_seq.front()` is `true`.
186 */
188
189 /// Returns `true` or `false` according to some probability set at construction; used for received packet loss.
190 boost::random::bernoulli_distribution<prob_type_t> m_recv_packet_loss_distribution;
191
192 /**
193 * At a given point in time, the `i`-th from now (in chronological order) received packet will be
194 * lagged by value in `i`-th element of #m_recv_latency_seq. For example, the next packet will lagged by
195 * `m_recv_latency_seq.front()`.
196 */
198
199 /**
200 * Returns random latencies (in units of `Fine_duration`) within the improper [low, high] range
201 * given at construction; used for received packet latency.
202 */
203 boost::random::uniform_int_distribution<Fine_duration::rep> m_recv_latency_distribution_msec;
204
205 /**
206 * At a given point in time, the `i`-th from now (in chronological order) received packet will be
207 * duplicated if and only if the `i`-th element of #m_recv_packet_dup_seq is `true`. For example, the
208 * next packet will be duplicated if and only if `m_recv_packet_dup_seq.front()` is `true`.
209 */
211
212 /// Returns `true` or `false` according to some probability set at construction; used for received packet duplication.
213 boost::random::bernoulli_distribution<prob_type_t> m_recv_packet_dup_distribution;
214}; // class Net_env_simulator
215
216} // namespace flow::net_flow
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Definition: log.hpp:1619
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1291
Objects of this class can be fed to Node to make it internally simulate network conditions like loss,...
std::queue< Fine_duration > Latency_seq
Short-hand for list of packet latencies.
Net_env_simulator(log::Logger *logger_ptr, seed_type_t random_seed=0, prob_type_t recv_packet_loss_prob=0, const Packet_loss_seq &recv_packet_loss_seq=Packet_loss_seq(), const Latency_range &recv_latency_range=Latency_range(), const Latency_seq &recv_latency_seq=Latency_seq(), prob_type_t recv_packet_dup_prob=0, const Packet_dup_seq &recv_packet_dup_seq=Packet_dup_seq())
Constructs simulator.
Packet_dup_seq m_recv_packet_dup_seq
At a given point in time, the i-th from now (in chronological order) received packet will be duplicat...
std::queue< bool > Packet_dup_seq
Short-hand for list of packet duplication outcomes.
Random_generator m_rnd_generator
Random number generator for various random events like packet loss.
boost::random::bernoulli_distribution< prob_type_t > m_recv_packet_loss_distribution
Returns true or false according to some probability set at construction; used for received packet los...
double prob_type_t
Short-hand for floating point between 0 and 1 used to express probability.
Packet_loss_seq m_recv_packet_loss_seq
At a given point in time, the i-th from now (in chronological order) received packet will be dropped ...
std::pair< Fine_duration, Fine_duration > Latency_range
Short-hand for latency range [low, high].
boost::random::uniform_int_distribution< Fine_duration::rep > m_recv_latency_distribution_msec
Returns random latencies (in units of Fine_duration) within the improper [low, high] range given at c...
Fine_duration received_packet_latency()
Low-level packet was received and not dropped, but should we simulate that it was lagged by an additi...
util::Rnd_gen_uniform_range_base::Random_generator Random_generator
Random number generator.
boost::random::bernoulli_distribution< prob_type_t > m_recv_packet_dup_distribution
Returns true or false according to some probability set at construction; used for received packet dup...
uint32_t seed_type_t
Short-hand for the random seed integer type.
Latency_seq m_recv_latency_seq
At a given point in time, the i-th from now (in chronological order) received packet will be lagged b...
seed_type_t m_seed
Random seed for m_rnd_generator (saved for reproducibility of "random" events).
bool should_duplicate_received_packet()
Low-level packet was received, but should we simulate that it was duplicated? Probability and/or pres...
bool should_drop_received_packet()
Low-level packet was received, but should we simulate that it was dropped before receipt?...
std::queue< bool > Packet_loss_seq
Short-hand for list of packet loss outcomes.
boost::random::mt19937 Random_generator
The random generator engine; it is public for the reason explained in Usability section of the Rnd_ge...
Definition: random.hpp:41
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:410