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