libperfdhcp_la_SOURCES += test_control.cc test_control.h
libperfdhcp_la_SOURCES += receiver.cc receiver.h
libperfdhcp_la_SOURCES += perf_socket.cc perf_socket.h
+libperfdhcp_la_SOURCES += abstract_scen.h
libperfdhcp_la_SOURCES += avalanche_scen.cc avalanche_scen.h
libperfdhcp_la_SOURCES += basic_scen.cc basic_scen.h
--- /dev/null
+// Copyright (C) 2019 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/.
+
+#ifndef ABSTRACT_SCEN_H
+#define ABSTRACT_SCEN_H
+
+
+#include <perfdhcp/test_control.h>
+
+
+namespace isc {
+namespace perfdhcp {
+
+
+/// \brief Abstract Scenario class.
+///
+/// This class must be inherited by scenario classes.
+class AbstractScen : public boost::noncopyable {
+public:
+ /// \brief Run performance test.
+ ///
+ /// Method runs whole performance test.
+ virtual int run() = 0;
+
+ /// \brief Trivial virtual destructor.
+ virtual ~AbstractScen() {};
+
+protected:
+ TestControl tc_; ///< Object for controling sending and receiving packets.
+};
+
+
+}
+}
+
+#endif // ABSTRACT_SCEN_H
auto& start_times = start_times_[xchg_type];
int still_left_cnt = 0;
- int resent_cnt = 0;
+ int current_cycle_resent_cnt = 0;
for (auto it = begin_it; it != end_it; ++it) {
still_left_cnt++;
auto trans_id = pkt->getTransid();
// get some things from previous retransmissions
- bool first_resend = true;
auto start_time = pkt->getTimestamp();
- int retransmissions_count = 0;
+ int current_pkt_resent_cnt = 0;
auto r_it = retrans.find(trans_id);
if (r_it != retrans.end()) {
- first_resend = false;
start_time = (*start_times.find(trans_id)).second;
- retransmissions_count = (*r_it).second;
+ current_pkt_resent_cnt = (*r_it).second;
+ } else {
+ start_times[trans_id] = start_time;
}
// estimate back off time for resending this packet
- int delay = (1 << retransmissions_count); // in seconds
+ int delay = (1 << current_pkt_resent_cnt); // in seconds
if (delay > 64) {
delay = 64;
}
// if back-off time passed then resend
auto now = microsec_clock::universal_time();
if (now - start_time > milliseconds(delay)) {
- resent_cnt++;
+ current_cycle_resent_cnt++;
total_resent_++;
- // remember sending time of original packet
- boost::posix_time::ptime original_timestamp;
- if (!first_resend) {
- original_timestamp = pkt->getTimestamp();
- }
-
// do resend packet
if (options.getIpVersion() == 4) {
Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
}
// restore sending time of original packet
- if (first_resend) {
- start_times[trans_id] = pkt->getTimestamp();
- } else {
- pkt->setTimestamp(original_timestamp);
- }
+ pkt->setTimestamp(start_time);
- retransmissions_count++;
- retrans[trans_id] = retransmissions_count;
+ current_pkt_resent_cnt++;
+ retrans[trans_id] = current_pkt_resent_cnt;
}
}
- if (resent_cnt > 0) {
+ if (current_cycle_resent_cnt > 0) {
auto now = microsec_clock::universal_time();
std::cout << now << " " << xchg_type << ": still waiting for "
- << still_left_cnt << " answers, resent " << resent_cnt
+ << still_left_cnt << " answers, resent " << current_cycle_resent_cnt
<< ", retrying " << retrans.size() << std::endl;
}
return still_left_cnt;
int
AvalancheScen::run() {
+ // First indicated number of DISCOVER packets eg. 4000 are sent.
+ // Then in a loop responses to received packets (this is
+ // consumeReceivedPackets()) are sent and then for every 200ms it is checked
+ // if reponses to sent packets were received. If not packets are resent.
+ // This happens in resendPackets() method. For each packet it is checked
+ // how many times it was already resent and then back off time is calculated:
+ // 1, 2, 4, 8, 16, 64 (max) seconds. If estimated time has elapsed
+ // from previous sending then the packet is resent. Some stats are collected
+ // and printed during runtime. The whole procedure is stopeed when
+ // all packets got reponses.
+
CommandOptions& options = CommandOptions::instance();
uint32_t clients_num = options.getClientsNum() == 0 ?
#include <config.h>
-#include <perfdhcp/test_control.h>
+#include <perfdhcp/abstract_scen.h>
namespace isc {
namespace perfdhcp {
-class AvalancheScen : public boost::noncopyable {
+/// \brief Avalanche Scenario class.
+///
+/// This class is used to run the performance test where DHCP server
+/// is first loaded with indicated bumer of Discover or Solicit messages
+/// and then the class is waiting till receiving all required responses.
+/// Full DORA and SARR message sequences are expected.
+class AvalancheScen : public AbstractScen {
public:
+ /// Default and the only constructor of AvalancheScen.
AvalancheScen(): total_resent_(0) {};
/// brief\ Run performance test.
///
- /// Method runs whole performance test. Command line options must
- /// be parsed prior to running this function. Otherwise function will
- /// throw exception.
- ///
- /// \throw isc::InvalidOperation if command line options are not parsed.
- /// \throw isc::Unexpected if internal Test Controller error occurred.
- /// \return error_code, 3 if number of received packets is not equal
- /// to number of sent packets, 0 if everything is ok.
+ /// Method runs whole performance test.
int run();
private:
- TestControl tc_;
+ /// A map xchg type -> (a map of trans id -> retransmissions count.
std::unordered_map<ExchangeType, std::unordered_map<uint32_t, int>> retransmissions_;
+ /// A map xchg type -> (a map of trans id -> time of sending first packet.
std::unordered_map<ExchangeType, std::unordered_map<uint32_t, boost::posix_time::ptime>> start_times_;
+
+ /// Total number of resent packets.
int total_resent_;
+ /// Resend packets for given exchange type that did not receive
+ /// a response yet.
int resendPackets(ExchangeType xchg_type);
};
#include <config.h>
-#include <perfdhcp/test_control.h>
+#include <perfdhcp/abstract_scen.h>
namespace isc {
namespace perfdhcp {
-class BasicScen : public boost::noncopyable {
+/// \brief Basic Scenario class.
+///
+/// This class is used to run the performance test where DHCP server
+/// is continuously loaded with DHCP messages according to given rate.
+class BasicScen : public AbstractScen {
public:
+ /// Default and the only constructor of BasicScen.
BasicScen() {};
- /// \brief Check if test exit conditions fulfilled.
- ///
- /// Method checks if the test exit conditions are fulfilled.
- /// Exit conditions are checked periodically from the
- /// main loop. Program should break the main loop when
- /// this method returns true. It is calling function
- /// responsibility to break main loop gracefully and
- /// cleanup after test execution.
- ///
- /// \return true if any of the exit conditions is fulfilled.
- bool checkExitConditions();
-
/// brief\ Run performance test.
///
/// Method runs whole performance test. Command line options must
int run();
private:
- TestControl tc_;
-
/// \brief A rate control class for Discover and Solicit messages.
RateControl basic_rate_control_;
/// \brief A rate control class for Renew messages.
/// \brief A rate control class for Release messages.
RateControl release_rate_control_;
- int resendPackets(ExchangeType xchg_type);
-
+ /// \brief Check if test exit conditions fulfilled.
+ ///
+ /// Method checks if the test exit conditions are fulfilled.
+ /// Exit conditions are checked periodically from the
+ /// main loop. Program should break the main loop when
+ /// this method returns true. It is calling function
+ /// responsibility to break main loop gracefully and
+ /// cleanup after test execution.
+ ///
+ /// \return true if any of the exit conditions is fulfilled.
+ bool checkExitConditions();
};
}
/// \brief Test Control class.
///
-/// This singleton class is used to run the performance test with
+/// This class is used to run the performance test with
/// with \ref TestControl::run function. This function can be executed
/// multiple times if desired because it resets TestControl's internal
/// state every time it is executed. Prior to running \ref TestControl::run,