Kea 3.1.1
basic_scen.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2025 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#include <boost/date_time/posix_time/posix_time.hpp>
12
13using namespace std;
14using namespace boost::posix_time;
15using namespace isc;
16using namespace isc::dhcp;
17
18
19namespace isc {
20namespace perfdhcp {
21
22
23bool
25 if (tc_.interrupted()) {
26 return (true);
27 }
28
29 const StatsMgr& stats_mgr(tc_.getStatsMgr());
30
31 // Check if test period passed.
32 if (options_.getPeriod() != 0) {
33 time_period period(stats_mgr.getTestPeriod());
34 if (period.length().total_seconds() >= options_.getPeriod()) {
35 if (options_.testDiags('e')) {
36 std::cout << "reached test-period." << std::endl;
37 }
38 if (!tc_.waitToExit()) {
39 return true;
40 }
41 }
42 }
43
44 bool max_requests = false;
45 // Check if we reached maximum number of DISCOVER/SOLICIT sent.
46 if (options_.getNumRequests().size() > 0) {
47 if (stats_mgr.getSentPacketsNum(stage1_xchg_) >=
48 static_cast<uint64_t>(options_.getNumRequests()[0])) {
49 max_requests = true;
50 }
51 }
52 // Check if we reached maximum number REQUEST packets.
53 if (options_.getNumRequests().size() > 1) {
54 if (stats_mgr.getSentPacketsNum(stage2_xchg_) >=
55 static_cast<uint64_t>(options_.getNumRequests()[1])) {
56 max_requests = true;
57 }
58 }
59 if (max_requests) {
60 if (options_.testDiags('e')) {
61 std::cout << "Reached max requests limit." << std::endl;
62 }
63 if (!tc_.waitToExit()) {
64 return true;
65 }
66 }
67
68 // Check if we reached maximum number of drops of OFFER/ADVERTISE packets.
69 bool max_drops = false;
70 if (options_.getMaxDrop().size() > 0) {
71 if (stats_mgr.getDroppedPacketsNum(stage1_xchg_) >=
72 static_cast<uint64_t>(options_.getMaxDrop()[0])) {
73 max_drops = true;
74 }
75 }
76 // Check if we reached maximum number of drops of ACK/REPLY packets.
77 if (options_.getMaxDrop().size() > 1) {
78 if (stats_mgr.getDroppedPacketsNum(stage2_xchg_) >=
79 static_cast<uint64_t>(options_.getMaxDrop()[1])) {
80 max_drops = true;
81 }
82 }
83 if (max_drops) {
84 if (options_.testDiags('e')) {
85 std::cout << "Reached maximum drops number." << std::endl;
86 }
87 if (!tc_.waitToExit()) {
88 return true;
89 }
90 }
91
92 // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets.
93 bool max_pdrops = false;
94 if (options_.getMaxDropPercentage().size() > 0) {
95 if ((stats_mgr.getSentPacketsNum(stage1_xchg_) > 10) &&
96 ((100. * stats_mgr.getDroppedPacketsNum(stage1_xchg_) /
97 stats_mgr.getSentPacketsNum(stage1_xchg_)) >=
98 options_.getMaxDropPercentage()[0]))
99 {
100 max_pdrops = true;
101 }
102 }
103 // Check if we reached maximum drops percentage of ACK/REPLY packets.
104 if (options_.getMaxDropPercentage().size() > 1) {
105 if ((stats_mgr.getSentPacketsNum(stage2_xchg_) > 10) &&
106 ((100. * stats_mgr.getDroppedPacketsNum(stage2_xchg_) /
107 stats_mgr.getSentPacketsNum(stage2_xchg_)) >=
108 options_.getMaxDropPercentage()[1]))
109 {
110 max_pdrops = true;
111 }
112 }
113 if (max_pdrops) {
114 if (options_.testDiags('e')) {
115 std::cout << "Reached maximum percentage of drops." << std::endl;
116 }
117 if (!tc_.waitToExit()) {
118 return true;
119 }
120 }
121 return (false);
122}
123
124int
126 StatsMgr& stats_mgr(tc_.getStatsMgr());
127
128 // Preload server with the number of packets.
129 if (options_.getPreload() > 0) {
130 tc_.sendPackets(options_.getPreload(), true);
131 }
132
133 // Fork and run command specified with -w<wrapped-command>
134 if (!options_.getWrapped().empty()) {
135 tc_.runWrapped();
136 }
137
138 tc_.start();
139
140 for (;;) {
141 // Calculate number of packets to be sent to stay
142 // catch up with rate.
143 uint64_t packets_due =
144 basic_rate_control_.getOutboundMessageCount(!tc_.exit_time_.is_not_a_date_time());
145 if ((packets_due == 0) && options_.testDiags('i')) {
146 stats_mgr.incrementCounter("shortwait");
147 }
148
149 // Pull some packets from receiver thread, process them, update some stats
150 // and respond to the server if needed.
151 auto pkt_count = tc_.consumeReceivedPackets();
152
153 // If there is nothing to do in this loop iteration then do some sleep to make
154 // CPU idle for a moment, to not consume 100% CPU all the time
155 // but only if it is not that high request rate expected.
156 if (options_.getRate() < 10000 && packets_due == 0 && pkt_count == 0) {
159 usleep(1);
160 }
161
162 // If test period finished, maximum number of packet drops
163 // has been reached or test has been interrupted we have to
164 // finish the test.
165 if (checkExitConditions()) {
166 break;
167 }
168
169 // Initiate new DHCP packet exchanges.
170 tc_.sendPackets(packets_due);
171
172 // If -f<renew-rate> option was specified we have to check how many
173 // Renew packets should be sent to catch up with a desired rate.
174 if (options_.getRenewRate() != 0) {
175 uint64_t renew_packets_due =
176 renew_rate_control_.getOutboundMessageCount(!tc_.exit_time_.is_not_a_date_time());
177
178 // Send multiple renews to satisfy the desired rate.
179 if (options_.getIpVersion() == 4) {
180 tc_.sendMultipleMessages4(DHCPREQUEST, renew_packets_due);
181 } else {
182 tc_.sendMultipleMessages6(DHCPV6_RENEW, renew_packets_due);
183 }
184 }
185
186 // If -F<release-rate> option was specified we have to check how many
187 // Release messages should be sent to catch up with a desired rate.
188 if (options_.getReleaseRate() != 0) {
189 uint64_t release_packets_due =
190 release_rate_control_.getOutboundMessageCount(!tc_.exit_time_.is_not_a_date_time());
191 // Send Release messages.
192
193 if (options_.getIpVersion() == 4) {
194 tc_.sendMultipleMessages4(DHCPRELEASE, release_packets_due);
195 } else {
196 tc_.sendMultipleMessages6(DHCPV6_RELEASE, release_packets_due);
197 }
198 }
199
200 // Report delay means that user requested printing number
201 // of sent/received/dropped packets repeatedly.
202 if (options_.getReportDelay() > 0) {
203 tc_.printIntermediateStats();
204 }
205
206 // If we are sending Renews to the server, the Reply packets are cached
207 // so as leases for which we send Renews can be identified. The major
208 // issue with this approach is that most of the time we are caching
209 // more packets than we actually need. This function removes excessive
210 // Reply messages to reduce the memory and CPU utilization. Note that
211 // searches in the long list of Reply packets increases CPU utilization.
212 tc_.cleanCachedPackets();
213 }
214
215 tc_.stop();
216
217 tc_.printStats();
218
219 if (!options_.getWrapped().empty()) {
220 // true means that we execute wrapped command with 'stop' argument.
221 tc_.runWrapped(true);
222 }
223
224 // Print packet timestamps
225 if (options_.testDiags('t')) {
226 stats_mgr.printTimestamps();
227 }
228
229 // Print server id.
230 if (options_.testDiags('s') && tc_.serverIdReceived()) {
231 std::cout << "Server id: " << tc_.getServerId() << std::endl;
232 }
233
234 // Diagnostics flag 'e' means show exit reason.
235 if (options_.testDiags('e')) {
236 std::cout << "Interrupted" << std::endl;
237 }
238 // Print packet templates. Even if -T options have not been specified the
239 // dynamically build packet will be printed if at least one has been sent.
240 if (options_.testDiags('T')) {
241 tc_.printTemplates();
242 }
243
244 // Print any received leases.
245 if (options_.testDiags('l')) {
246 stats_mgr.printLeases();
247 }
248
249 int ret_code = 0;
250 // Check if any packet drops occurred.
251 ret_code = stats_mgr.droppedPackets() ? 3 : 0;
252 return (ret_code);
253}
254
255} // namespace perfdhcp
256} // namespace isc
TestControl tc_
Object for controlling sending and receiving packets.
CommandOptions & options_
Reference to commandline options.
RateControl renew_rate_control_
A rate control class for Renew messages.
Definition basic_scen.h:52
int run() override
brief\ Run performance test.
bool checkExitConditions()
Check if test exit conditions fulfilled.
Definition basic_scen.cc:24
RateControl release_rate_control_
A rate control class for Release messages.
Definition basic_scen.h:54
RateControl basic_rate_control_
A rate control class for Discover and Solicit messages.
Definition basic_scen.h:50
void printLeases() const
Delegate to all exchanges to print their leases.
uint64_t getDroppedPacketsNum(const ExchangeType xchg_type) const
Return total number of dropped packets.
const CustomCounter & incrementCounter(const std::string &counter_key, const uint64_t value=1)
Increment specified counter.
void printTimestamps() const
Print timestamps of all packets.
uint64_t getSentPacketsNum(const ExchangeType xchg_type) const
Return total number of sent packets.
boost::posix_time::time_period getTestPeriod() const
Get time period since the start of test.
bool droppedPackets() const
Check if any packet drops occurred.
@ DHCPV6_RENEW
Definition dhcp6.h:212
@ DHCPV6_RELEASE
Definition dhcp6.h:215
@ DHCPREQUEST
Definition dhcp4.h:237
@ DHCPRELEASE
Definition dhcp4.h:241
Defines the logger used by the top-level component of kea-lfc.