Kea: avalanche_scen.cc Source File

| Kea 3.2.0-git

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
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 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++;
67 total_resent_++;
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
97AvalancheScen::run() {
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 ?
110 1 : options_.getClientsNum();
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.
126 tc_.consumeReceivedPackets();
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_);
139 if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
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.
188 if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
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
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:51
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:61
isc::perfdhcp::AvalancheScen::total_resent_
int total_resent_
Total number of resent packets.
Definition avalanche_scen.h:66
isc::perfdhcp::AvalancheScen::run
int run() override
brief\ Run performance test.
Definition avalanche_scen.cc:97
isc::perfdhcp::AvalancheScen::socket_
BasePerfSocket & socket_
Definition avalanche_scen.h:58
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:63
isc::perfdhcp::CommandOptions::DORA_SARR
@ DORA_SARR
Definition command_options.h:122
isc::perfdhcp::StatsMgr
Statistics Manager.
Definition bin/perfdhcp/stats_mgr.h:712
isc::perfdhcp::StatsMgr::getSentPackets
std::tuple< typename ExchangeStats::PktListIterator, typename ExchangeStats::PktListIterator > getSentPackets(const ExchangeType xchg_type) const
Definition bin/perfdhcp/stats_mgr.h:1207
isc::perfdhcp::StatsMgr::printLeases
void printLeases() const
Delegate to all exchanges to print their leases.
Definition bin/perfdhcp/stats_mgr.cc:457
isc::perfdhcp::StatsMgr::printTimestamps
void printTimestamps() const
Print timestamps of all packets.
Definition bin/perfdhcp/stats_mgr.h:1171
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:999
isc::dhcp::Pkt4Ptr
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
isc::perfdhcp
Definition abstract_scen.h:15
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 check_exists_add.cc:18