summaryrefslogtreecommitdiffstats
path: root/src/bin/perfdhcp/basic_scen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/perfdhcp/basic_scen.cc')
-rw-r--r--src/bin/perfdhcp/basic_scen.cc256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/bin/perfdhcp/basic_scen.cc b/src/bin/perfdhcp/basic_scen.cc
new file mode 100644
index 0000000..a9b696f
--- /dev/null
+++ b/src/bin/perfdhcp/basic_scen.cc
@@ -0,0 +1,256 @@
+// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <perfdhcp/basic_scen.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+using namespace std;
+using namespace boost::posix_time;
+using namespace isc;
+using namespace isc::dhcp;
+
+
+namespace isc {
+namespace perfdhcp {
+
+
+bool
+BasicScen::checkExitConditions() {
+ if (tc_.interrupted()) {
+ return (true);
+ }
+
+ const StatsMgr& stats_mgr(tc_.getStatsMgr());
+
+ // Check if test period passed.
+ if (options_.getPeriod() != 0) {
+ time_period period(stats_mgr.getTestPeriod());
+ if (period.length().total_seconds() >= options_.getPeriod()) {
+ if (options_.testDiags('e')) {
+ std::cout << "reached test-period." << std::endl;
+ }
+ if (!tc_.waitToExit()) {
+ return true;
+ }
+ }
+ }
+
+ bool max_requests = false;
+ // Check if we reached maximum number of DISCOVER/SOLICIT sent.
+ if (options_.getNumRequests().size() > 0) {
+ if (stats_mgr.getSentPacketsNum(stage1_xchg_) >=
+ options_.getNumRequests()[0]) {
+ max_requests = true;
+ }
+ }
+ // Check if we reached maximum number REQUEST packets.
+ if (options_.getNumRequests().size() > 1) {
+ if (stats_mgr.getSentPacketsNum(stage2_xchg_) >=
+ options_.getNumRequests()[1]) {
+ max_requests = true;
+ }
+ }
+ if (max_requests) {
+ if (options_.testDiags('e')) {
+ std::cout << "Reached max requests limit." << std::endl;
+ }
+ if (!tc_.waitToExit()) {
+ return true;
+ }
+ }
+
+ // Check if we reached maximum number of drops of OFFER/ADVERTISE packets.
+ bool max_drops = false;
+ if (options_.getMaxDrop().size() > 0) {
+ if (stats_mgr.getDroppedPacketsNum(stage1_xchg_) >=
+ options_.getMaxDrop()[0]) {
+ max_drops = true;
+ }
+ }
+ // Check if we reached maximum number of drops of ACK/REPLY packets.
+ if (options_.getMaxDrop().size() > 1) {
+ if (stats_mgr.getDroppedPacketsNum(stage2_xchg_) >=
+ options_.getMaxDrop()[1]) {
+ max_drops = true;
+ }
+ }
+ if (max_drops) {
+ if (options_.testDiags('e')) {
+ std::cout << "Reached maximum drops number." << std::endl;
+ }
+ if (!tc_.waitToExit()) {
+ return true;
+ }
+ }
+
+ // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets.
+ bool max_pdrops = false;
+ if (options_.getMaxDropPercentage().size() > 0) {
+ if ((stats_mgr.getSentPacketsNum(stage1_xchg_) > 10) &&
+ ((100. * stats_mgr.getDroppedPacketsNum(stage1_xchg_) /
+ stats_mgr.getSentPacketsNum(stage1_xchg_)) >=
+ options_.getMaxDropPercentage()[0]))
+ {
+ max_pdrops = true;
+ }
+ }
+ // Check if we reached maximum drops percentage of ACK/REPLY packets.
+ if (options_.getMaxDropPercentage().size() > 1) {
+ if ((stats_mgr.getSentPacketsNum(stage2_xchg_) > 10) &&
+ ((100. * stats_mgr.getDroppedPacketsNum(stage2_xchg_) /
+ stats_mgr.getSentPacketsNum(stage2_xchg_)) >=
+ options_.getMaxDropPercentage()[1]))
+ {
+ max_pdrops = true;
+ }
+ }
+ if (max_pdrops) {
+ if (options_.testDiags('e')) {
+ std::cout << "Reached maximum percentage of drops." << std::endl;
+ }
+ if (!tc_.waitToExit()) {
+ return true;
+ }
+ }
+ return (false);
+}
+
+int
+BasicScen::run() {
+ StatsMgr& stats_mgr(tc_.getStatsMgr());
+
+ // Preload server with the number of packets.
+ if (options_.getPreload() > 0) {
+ tc_.sendPackets(options_.getPreload(), true);
+ }
+
+ // Fork and run command specified with -w<wrapped-command>
+ if (!options_.getWrapped().empty()) {
+ tc_.runWrapped();
+ }
+
+ tc_.start();
+
+ for (;;) {
+ // Calculate number of packets to be sent to stay
+ // catch up with rate.
+ uint64_t packets_due =
+ basic_rate_control_.getOutboundMessageCount(!tc_.exit_time_.is_not_a_date_time());
+ if ((packets_due == 0) && options_.testDiags('i')) {
+ stats_mgr.incrementCounter("shortwait");
+ }
+
+ // Pull some packets from receiver thread, process them, update some stats
+ // and respond to the server if needed.
+ auto pkt_count = tc_.consumeReceivedPackets();
+
+ // If there is nothing to do in this loop iteration then do some sleep to make
+ // CPU idle for a moment, to not consume 100% CPU all the time
+ // but only if it is not that high request rate expected.
+ if (options_.getRate() < 10000 && packets_due == 0 && pkt_count == 0) {
+ /// @todo: need to implement adaptive time here, so the sleep time
+ /// is not fixed, but adjusts to current situation.
+ usleep(1);
+ }
+
+ // If test period finished, maximum number of packet drops
+ // has been reached or test has been interrupted we have to
+ // finish the test.
+ if (checkExitConditions()) {
+ break;
+ }
+
+ // Initiate new DHCP packet exchanges.
+ tc_.sendPackets(packets_due);
+
+ // If -f<renew-rate> option was specified we have to check how many
+ // Renew packets should be sent to catch up with a desired rate.
+ if (options_.getRenewRate() != 0) {
+ uint64_t renew_packets_due =
+ renew_rate_control_.getOutboundMessageCount(!tc_.exit_time_.is_not_a_date_time());
+
+ // Send multiple renews to satisfy the desired rate.
+ if (options_.getIpVersion() == 4) {
+ tc_.sendMultipleMessages4(DHCPREQUEST, renew_packets_due);
+ } else {
+ tc_.sendMultipleMessages6(DHCPV6_RENEW, renew_packets_due);
+ }
+ }
+
+ // If -F<release-rate> option was specified we have to check how many
+ // Release messages should be sent to catch up with a desired rate.
+ if (options_.getReleaseRate() != 0) {
+ uint64_t release_packets_due =
+ release_rate_control_.getOutboundMessageCount(!tc_.exit_time_.is_not_a_date_time());
+ // Send Release messages.
+
+ if (options_.getIpVersion() == 4) {
+ tc_.sendMultipleMessages4(DHCPRELEASE, release_packets_due);
+ } else {
+ tc_.sendMultipleMessages6(DHCPV6_RELEASE, release_packets_due);
+ }
+ }
+
+ // Report delay means that user requested printing number
+ // of sent/received/dropped packets repeatedly.
+ if (options_.getReportDelay() > 0) {
+ tc_.printIntermediateStats();
+ }
+
+ // If we are sending Renews to the server, the Reply packets are cached
+ // so as leases for which we send Renews can be identified. The major
+ // issue with this approach is that most of the time we are caching
+ // more packets than we actually need. This function removes excessive
+ // Reply messages to reduce the memory and CPU utilization. Note that
+ // searches in the long list of Reply packets increases CPU utilization.
+ tc_.cleanCachedPackets();
+ }
+
+ tc_.stop();
+
+ tc_.printStats();
+
+ if (!options_.getWrapped().empty()) {
+ // true means that we execute wrapped command with 'stop' argument.
+ tc_.runWrapped(true);
+ }
+
+ // Print packet timestamps
+ if (options_.testDiags('t')) {
+ stats_mgr.printTimestamps();
+ }
+
+ // Print server id.
+ if (options_.testDiags('s') && tc_.serverIdReceived()) {
+ std::cout << "Server id: " << tc_.getServerId() << std::endl;
+ }
+
+ // Diagnostics flag 'e' means show exit reason.
+ if (options_.testDiags('e')) {
+ std::cout << "Interrupted" << std::endl;
+ }
+ // Print packet templates. Even if -T options have not been specified the
+ // dynamically build packet will be printed if at least one has been sent.
+ if (options_.testDiags('T')) {
+ tc_.printTemplates();
+ }
+
+ // Print any received leases.
+ if (options_.testDiags('l')) {
+ stats_mgr.printLeases();
+ }
+
+ int ret_code = 0;
+ // Check if any packet drops occurred.
+ ret_code = stats_mgr.droppedPackets() ? 3 : 0;
+ return (ret_code);
+}
+
+} // namespace perfdhcp
+} // namespace isc