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
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.
Definition: abstract_scen.h:52
CommandOptions & options_
Reference to commandline options.
Definition: abstract_scen.h:48
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.
Definition: test_control.h:225
std::string getServerId() const
Get received server id.
Definition: test_control.h:245
void start()
Start receiver.
Definition: test_control.h:231
StatsMgr & getStatsMgr()
Get stats manager.
Definition: test_control.h:228
void sendPackets(const uint64_t packets_num, const bool preload=false)
Send number of packets to initiate new exchanges.
void stop()
Stop receiver.
Definition: test_control.h:234
unsigned int consumeReceivedPackets()
Pull packets from receiver and process them.
void printStats() const
Print performance statistics.
bool serverIdReceived() const
Get received server id flag.
Definition: test_control.h:242
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition: pkt.h:797
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
ExchangeType
DHCP packet exchange types.
Defines the logger used by the top-level component of kea-lfc.