Kea 2.7.1
avalanche_scen.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2024 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 auto s_it = start_times.find(trans_id);
48 if (r_it != retrans.end() && s_it != start_times.end()) {
49 start_time = s_it->second;
50 current_pkt_resent_cnt = r_it->second;
51 } else {
52 start_times[trans_id] = start_time;
53 }
54
55 // estimate back off time for resending this packet
56 int delay = (1 << current_pkt_resent_cnt); // in seconds
57 if (delay > 64) {
58 delay = 64;
59 }
60 delay *= 1000; // to miliseconds
61 delay += random() % 2000 - 1000; // adjust by random from -1000..1000 range
62
63 // if back-off time passed then resend
64 auto now = microsec_clock::universal_time();
65 if (now - start_time > milliseconds(delay)) {
66 current_cycle_resent_cnt++;
68
69 // do resend packet
70 if (options_.getIpVersion() == 4) {
71 Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
72 socket_.send(pkt4);
73 } else {
74 Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<Pkt6>(pkt);
75 socket_.send(pkt6);
76 }
77
78 // restore sending time of original packet
79 pkt->setTimestamp(start_time);
80
81 current_pkt_resent_cnt++;
82 retrans[trans_id] = current_pkt_resent_cnt;
83 }
84 }
85 if (current_cycle_resent_cnt > 0) {
86 auto now = microsec_clock::universal_time();
87 std::cout << now << " " << xchg_type << ": still waiting for "
88 << still_left_cnt << " answers, resent " << current_cycle_resent_cnt
89 << ", retrying " << retrans.size() << std::endl;
90 }
91 return still_left_cnt;
92}
93
94
95
96int
98 // First indicated number of DISCOVER packets eg. 4000 are sent.
99 // Then in a loop responses to received packets (this is
100 // consumeReceivedPackets()) are sent and then for every 200ms it is checked
101 // if responses to sent packets were received. If not packets are resent.
102 // This happens in resendPackets() method. For each packet it is checked
103 // how many times it was already resent and then back off time is calculated:
104 // 1, 2, 4, 8, 16, 64 (max) seconds. If estimated time has elapsed
105 // from previous sending then the packet is resent. Some stats are collected
106 // and printed during runtime. The whole procedure is stopped when
107 // all packets got responses.
108
109 uint32_t clients_num = options_.getClientsNum() == 0 ?
111
112 StatsMgr& stats_mgr(tc_.getStatsMgr());
113
114 tc_.start();
115
116 auto start = microsec_clock::universal_time();
117
118 // Initiate new DHCP packet exchanges.
119 tc_.sendPackets(clients_num);
120
121 auto now = microsec_clock::universal_time();
122 auto prev_cycle_time = now;
123 for (;;) {
124 // Pull some packets from receiver thread, process them, update some stats
125 // and respond to the server if needed.
127
128 usleep(100);
129
130 now = microsec_clock::universal_time();
131 // Wait for 200ms between subsequent check for resending.
132 // This time taken based on experiments. For times 10-30ms whole scenario
133 // time significantly grows. The same for times >200ms. The optimal times
134 // are between 50-200ms. \todo more research is needed.
135 if (now - prev_cycle_time > milliseconds(200)) { // check if 0.2s elapsed
136 prev_cycle_time = now;
137 int still_left_cnt = 0;
138 still_left_cnt += resendPackets(stage1_xchg_);
140 still_left_cnt += resendPackets(stage2_xchg_);
141 }
142
143 if (still_left_cnt == 0) {
144 break;
145 }
146 }
147
148 if (tc_.interrupted()) {
149 break;
150 }
151 }
152
153 auto stop = microsec_clock::universal_time();
154 boost::posix_time::time_period duration(start, stop);
155
156 tc_.stop();
157
158 tc_.printStats();
159
160 // Print packet timestamps
161 if (options_.testDiags('t')) {
162 stats_mgr.printTimestamps();
163 }
164
165 // Print server id.
166 if (options_.testDiags('s') && tc_.serverIdReceived()) {
167 std::cout << "Server id: " << tc_.getServerId() << std::endl;
168 }
169
170 // Diagnostics flag 'e' means show exit reason.
171 if (options_.testDiags('e')) {
172 std::cout << "Interrupted" << std::endl;
173 }
174
175 // Print any received leases.
176 if (options_.testDiags('l')) {
177 stats_mgr.printLeases();
178 }
179
180 // Calculate total stats.
181 int total_sent_pkts = total_resent_; // This holds sent + resent packets counts.
182 int total_rcvd_pkts = 0; // This holds received packets count.
183 // Get sent and received counts for DO/SA (stage1) exchange from StatsMgr.
184 total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(stage1_xchg_);
185 total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(stage1_xchg_);
186 // Get sent and received counts for RA/RR (stage2) exchange from StatsMgr
187 // if RA/RR was not disabled.
189 total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(stage2_xchg_);
190 total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(stage2_xchg_);
191 }
192
193 std::cout << "It took " << duration.length() << " to provision " << clients_num
194 << " clients. " << std::endl
195 << "Requests sent + resent: " << total_sent_pkts << std::endl
196 << "Requests resent: " << total_resent_ << std::endl
197 << "Responses received: " << total_rcvd_pkts << std::endl;
198
199 return (0);
200}
201
202} // namespace perfdhcp
203} // 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.
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:982
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.