Kea: avalanche_scen.cc Source File

| Kea 2.2.0

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
9#include <perfdhcp/avalanche_scen.h>
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
24AvalancheScen::resendPackets(ExchangeType xchg_type) {
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++;
66 total_resent_++;
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
96AvalancheScen::run() {
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 ?
109 1 : options_.getClientsNum();
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.
125 tc_.consumeReceivedPackets();
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_);
138 if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
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.
187 if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
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
avalanche_scen.h
isc::perfdhcp::AbstractScen::tc_
TestControl tc_
Object for controlling sending and receiving packets.
Definition: abstract_scen.h:52
isc::perfdhcp::AbstractScen::stage2_xchg_
ExchangeType stage2_xchg_
Definition: abstract_scen.h:57
isc::perfdhcp::AbstractScen::options_
CommandOptions & options_
Reference to commandline options.
Definition: abstract_scen.h:48
isc::perfdhcp::AbstractScen::stage1_xchg_
ExchangeType stage1_xchg_
Definition: abstract_scen.h:56
isc::perfdhcp::AvalancheScen::retransmissions_
std::unordered_map< ExchangeType, std::unordered_map< uint32_t, int >, EnumClassHash > retransmissions_
A map xchg type -> (a map of trans id -> retransmissions count.
Definition: avalanche_scen.h:60
isc::perfdhcp::AvalancheScen::total_resent_
int total_resent_
Total number of resent packets.
Definition: avalanche_scen.h:65
isc::perfdhcp::AvalancheScen::run
int run() override
brief\ Run performance test.
Definition: avalanche_scen.cc:96
isc::perfdhcp::AvalancheScen::socket_
BasePerfSocket & socket_
Definition: avalanche_scen.h:57
isc::perfdhcp::AvalancheScen::resendPackets
int resendPackets(ExchangeType xchg_type)
\brief Resend packets.
Definition: avalanche_scen.cc:24
isc::perfdhcp::AvalancheScen::start_times_
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.
Definition: avalanche_scen.h:62
isc::perfdhcp::BasePerfSocket::send
virtual bool send(const dhcp::Pkt4Ptr &pkt)=0
See description of this method in PerfSocket class below.
isc::perfdhcp::CommandOptions::testDiags
bool testDiags(const char diag)
Find if diagnostic flag has been set.
Definition: command_options.h:419
isc::perfdhcp::CommandOptions::getIpVersion
uint8_t getIpVersion() const
Returns IP version.
Definition: command_options.h:144
isc::perfdhcp::CommandOptions::DORA_SARR
@ DORA_SARR
Definition: command_options.h:119
isc::perfdhcp::CommandOptions::getClientsNum
uint32_t getClientsNum() const
Returns number of simulated clients.
Definition: command_options.h:189
isc::perfdhcp::CommandOptions::getExchangeMode
ExchangeMode getExchangeMode() const
Returns packet exchange mode.
Definition: command_options.h:149
isc::perfdhcp::StatsMgr
Statistics Manager.
Definition: bin/perfdhcp/stats_mgr.h:710
isc::perfdhcp::StatsMgr::getSentPackets
std::tuple< typename ExchangeStats::PktListIterator, typename ExchangeStats::PktListIterator > getSentPackets(const ExchangeType xchg_type) const
Definition: bin/perfdhcp/stats_mgr.h:1211
isc::perfdhcp::StatsMgr::printLeases
void printLeases() const
Delegate to all exchanges to print their leases.
Definition: bin/perfdhcp/stats_mgr.cc:461
isc::perfdhcp::StatsMgr::printTimestamps
void printTimestamps() const
Print timestamps of all packets.
Definition: bin/perfdhcp/stats_mgr.h:1172
isc::perfdhcp::StatsMgr::getRcvdPacketsNum
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
Definition: bin/perfdhcp/stats_mgr.h:992
isc::perfdhcp::StatsMgr::getSentPacketsNum
uint64_t getSentPacketsNum(const ExchangeType xchg_type) const
Return total number of sent packets.
Definition: bin/perfdhcp/stats_mgr.h:979
isc::perfdhcp::TestControl::interrupted
bool interrupted() const
Get interrupted flag.
Definition: test_control.h:225
isc::perfdhcp::TestControl::getServerId
std::string getServerId() const
Get received server id.
Definition: test_control.h:245
isc::perfdhcp::TestControl::start
void start()
Start receiver.
Definition: test_control.h:231
isc::perfdhcp::TestControl::getStatsMgr
StatsMgr & getStatsMgr()
Get stats manager.
Definition: test_control.h:228
isc::perfdhcp::TestControl::sendPackets
void sendPackets(const uint64_t packets_num, const bool preload=false)
Send number of packets to initiate new exchanges.
Definition: test_control.cc:559
isc::perfdhcp::TestControl::stop
void stop()
Stop receiver.
Definition: test_control.h:234
isc::perfdhcp::TestControl::consumeReceivedPackets
unsigned int consumeReceivedPackets()
Pull packets from receiver and process them.
Definition: test_control.cc:1007
isc::perfdhcp::TestControl::printStats
void printStats() const
Print performance statistics.
Definition: test_control.cc:741
isc::perfdhcp::TestControl::serverIdReceived
bool serverIdReceived() const
Get received server id flag.
Definition: test_control.h:242
isc::cryptolink::random
std::vector< uint8_t > random(size_t len)
Generate random value.
Definition: crypto_rng.cc:26
isc::dhcp
Definition: dhcp4/client_handler.cc:20
isc::dhcp::PktPtr
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition: pkt.h:797
isc::dhcp::Pkt4Ptr
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
isc::perfdhcp::ExchangeType
ExchangeType
DHCP packet exchange types.
Definition: bin/perfdhcp/stats_mgr.h:32
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
perfdhcp