Kea 2.4.1
avalanche_scen.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10
11
12#include <boost/date_time/posix_time/posix_time.hpp>
13
14using namespace std;
15using namespace boost::posix_time;
16using namespace isc;
17using namespace isc::dhcp;
18
19
20namespace isc {
21namespace perfdhcp {
22
23int
25 const StatsMgr& stats_mgr(tc_.getStatsMgr());
26
27 // get list of sent packets that potentially need to be resent
28 auto sent_packets_its = stats_mgr.getSentPackets(xchg_type);
29 auto begin_it = std::get<0>(sent_packets_its);
30 auto end_it = std::get<1>(sent_packets_its);
31
32 auto& retrans = retransmissions_[xchg_type];
33 auto& start_times = start_times_[xchg_type];
34
35 int still_left_cnt = 0;
36 int current_cycle_resent_cnt = 0;
37 for (auto it = begin_it; it != end_it; ++it) {
38 still_left_cnt++;
39
40 dhcp::PktPtr pkt = *it;
41 auto trans_id = pkt->getTransid();
42
43 // get some things from previous retransmissions
44 auto start_time = pkt->getTimestamp();
45 int current_pkt_resent_cnt = 0;
46 auto r_it = retrans.find(trans_id);
47 if (r_it != retrans.end()) {
48 start_time = (*start_times.find(trans_id)).second;
49 current_pkt_resent_cnt = (*r_it).second;
50 } else {
51 start_times[trans_id] = start_time;
52 }
53
54 // estimate back off time for resending this packet
55 int delay = (1 << current_pkt_resent_cnt); // in seconds
56 if (delay > 64) {
57 delay = 64;
58 }
59 delay *= 1000; // to miliseconds
60 delay += random() % 2000 - 1000; // adjust by random from -1000..1000 range
61
62 // if back-off time passed then resend
63 auto now = microsec_clock::universal_time();
64 if (now - start_time > milliseconds(delay)) {
65 current_cycle_resent_cnt++;
67
68 // do resend packet
69 if (options_.getIpVersion() == 4) {
70 Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
71 socket_.send(pkt4);
72 } else {
73 Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<Pkt6>(pkt);
74 socket_.send(pkt6);
75 }
76
77 // restore sending time of original packet
78 pkt->setTimestamp(start_time);
79
80 current_pkt_resent_cnt++;
81 retrans[trans_id] = current_pkt_resent_cnt;
82 }
83 }
84 if (current_cycle_resent_cnt > 0) {
85 auto now = microsec_clock::universal_time();
86 std::cout << now << " " << xchg_type << ": still waiting for "
87 << still_left_cnt << " answers, resent " << current_cycle_resent_cnt
88 << ", retrying " << retrans.size() << std::endl;
89 }
90 return still_left_cnt;
91}
92
93
94
95int
97 // First indicated number of DISCOVER packets eg. 4000 are sent.
98 // Then in a loop responses to received packets (this is
99 // consumeReceivedPackets()) are sent and then for every 200ms it is checked
100 // if responses to sent packets were received. If not packets are resent.
101 // This happens in resendPackets() method. For each packet it is checked
102 // how many times it was already resent and then back off time is calculated:
103 // 1, 2, 4, 8, 16, 64 (max) seconds. If estimated time has elapsed
104 // from previous sending then the packet is resent. Some stats are collected
105 // and printed during runtime. The whole procedure is stopped when
106 // all packets got responses.
107
108 uint32_t clients_num = options_.getClientsNum() == 0 ?
110
111 StatsMgr& stats_mgr(tc_.getStatsMgr());
112
113 tc_.start();
114
115 auto start = microsec_clock::universal_time();
116
117 // Initiate new DHCP packet exchanges.
118 tc_.sendPackets(clients_num);
119
120 auto now = microsec_clock::universal_time();
121 auto prev_cycle_time = now;
122 for (;;) {
123 // Pull some packets from receiver thread, process them, update some stats
124 // and respond to the server if needed.
126
127 usleep(100);
128
129 now = microsec_clock::universal_time();
130 // Wait for 200ms between subsequent check for resending.
131 // This time taken based on experiments. For times 10-30ms whole scenario
132 // time significantly grows. The same for times >200ms. The optimal times
133 // are between 50-200ms. \todo more research is needed.
134 if (now - prev_cycle_time > milliseconds(200)) { // check if 0.2s elapsed
135 prev_cycle_time = now;
136 int still_left_cnt = 0;
137 still_left_cnt += resendPackets(stage1_xchg_);
139 still_left_cnt += resendPackets(stage2_xchg_);
140 }
141
142 if (still_left_cnt == 0) {
143 break;
144 }
145 }
146
147 if (tc_.interrupted()) {
148 break;
149 }
150 }
151
152 auto stop = microsec_clock::universal_time();
153 boost::posix_time::time_period duration(start, stop);
154
155 tc_.stop();
156
157 tc_.printStats();
158
159 // Print packet timestamps
160 if (options_.testDiags('t')) {
161 stats_mgr.printTimestamps();
162 }
163
164 // Print server id.
165 if (options_.testDiags('s') && tc_.serverIdReceived()) {
166 std::cout << "Server id: " << tc_.getServerId() << std::endl;
167 }
168
169 // Diagnostics flag 'e' means show exit reason.
170 if (options_.testDiags('e')) {
171 std::cout << "Interrupted" << std::endl;
172 }
173
174 // Print any received leases.
175 if (options_.testDiags('l')) {
176 stats_mgr.printLeases();
177 }
178
179 // Calculate total stats.
180 int total_sent_pkts = total_resent_; // This holds sent + resent packets counts.
181 int total_rcvd_pkts = 0; // This holds received packets count.
182 // Get sent and received counts for DO/SA (stage1) exchange from StatsMgr.
183 total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(stage1_xchg_);
184 total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(stage1_xchg_);
185 // Get sent and received counts for RA/RR (stage2) exchange from StatsMgr
186 // if RA/RR was not disabled.
188 total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(stage2_xchg_);
189 total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(stage2_xchg_);
190 }
191
192 std::cout << "It took " << duration.length() << " to provision " << clients_num
193 << " clients. " << std::endl
194 << "Requests sent + resent: " << total_sent_pkts << std::endl
195 << "Requests resent: " << total_resent_ << std::endl
196 << "Responses received: " << total_rcvd_pkts << std::endl;
197
198 return (0);
199}
200
201} // namespace perfdhcp
202} // namespace isc
TestControl tc_
Object for controlling sending and receiving packets.
CommandOptions & options_
Reference to commandline options.
std::unordered_map< ExchangeType, std::unordered_map< uint32_t, int >, EnumClassHash > retransmissions_
A map xchg type -> (a map of trans id -> retransmissions count.
int total_resent_
Total number of resent packets.
int run() override
brief\ Run performance test.
int resendPackets(ExchangeType xchg_type)
\brief Resend packets.
std::unordered_map< ExchangeType, std::unordered_map< uint32_t, boost::posix_time::ptime >, EnumClassHash > start_times_
A map xchg type -> (a map of trans id -> time of sending first packet.
virtual bool send(const dhcp::Pkt4Ptr &pkt)=0
See description of this method in PerfSocket class below.
bool testDiags(const char diag)
Find if diagnostic flag has been set.
uint8_t getIpVersion() const
Returns IP version.
uint32_t getClientsNum() const
Returns number of simulated clients.
ExchangeMode getExchangeMode() const
Returns packet exchange mode.
std::tuple< typename ExchangeStats::PktListIterator, typename ExchangeStats::PktListIterator > getSentPackets(const ExchangeType xchg_type) const
void printLeases() const
Delegate to all exchanges to print their leases.
void printTimestamps() const
Print timestamps of all packets.
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
uint64_t getSentPacketsNum(const ExchangeType xchg_type) const
Return total number of sent packets.
bool interrupted() const
Get interrupted flag.
std::string getServerId() const
Get received server id.
void start()
Start receiver.
StatsMgr & getStatsMgr()
Get stats manager.
void sendPackets(const uint64_t packets_num, const bool preload=false)
Send number of packets to initiate new exchanges.
void stop()
Stop receiver.
unsigned int consumeReceivedPackets()
Pull packets from receiver and process them.
void printStats() const
Print performance statistics.
bool serverIdReceived() const
Get received server id flag.
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:864
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:555
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
ExchangeType
DHCP packet exchange types.
Defines the logger used by the top-level component of kea-lfc.