Commit 6a3c2c61 authored by Marcin Siodelski's avatar Marcin Siodelski

[1959] Implemented changes from the second part of code review.

parent 6ca3dadc
......@@ -56,8 +56,8 @@ CommandOptions::reset() {
rate_ = 0;
report_delay_ = 0;
clients_num_ = 0;
mac_prefix_.assign(mac, mac + 6);
duid_prefix_.clear();
mac_template_.assign(mac, mac + 6);
duid_template_.clear();
base_.clear();
num_request_.clear();
period_ = 0;
......@@ -84,8 +84,8 @@ CommandOptions::reset() {
diags_.clear();
wrapped_.clear();
server_name_.clear();
generateDuidPrefix();
generateDuidTemplate();
commandline_.clear();
}
void
......@@ -132,9 +132,16 @@ CommandOptions::initialize(int argc, char** argv) {
int offset_arg = 0; // Temporary variable holding offset arguments
std::string sarg; // Temporary variable for string args
std::ostringstream stream;
stream << "perfdhcp";
// In this section we collect argument values from command line
// they will be tuned and validated elsewhere
while((opt = getopt(argc, argv, "hv46r:t:R:b:n:p:d:D:l:P:a:L:s:iBc1T:X:O:E:S:I:x:w:")) != -1) {
stream << " -" << opt;
if (optarg) {
stream << " " << optarg;
}
switch (opt) {
case 'v':
version();
......@@ -318,6 +325,8 @@ CommandOptions::initialize(int argc, char** argv) {
}
}
std::cout << "Running: " << stream.str() << std::endl;
// If the IP version was not specified in the
// command line, assume IPv4.
if (ipversion_ == 0) {
......@@ -375,8 +384,8 @@ CommandOptions::initialize(int argc, char** argv) {
// If DUID is not specified from command line we need to
// generate one.
if (duid_prefix_.size() == 0) {
generateDuidPrefix();
if (duid_template_.size() == 0) {
generateDuidTemplate();
}
}
......@@ -439,7 +448,7 @@ CommandOptions::decodeMac(const std::string& base) {
// Decode mac address to vector of uint8_t
std::istringstream s1(base.substr(found + 1));
std::string token;
mac_prefix_.clear();
mac_template_.clear();
// Get pieces of MAC address separated with : (or even ::)
while (std::getline(s1, token, ':')) {
unsigned int ui = 0;
......@@ -454,17 +463,17 @@ CommandOptions::decodeMac(const std::string& base) {
}
// If conversion succeeded store byte value
mac_prefix_.push_back(ui);
mac_template_.push_back(ui);
}
}
// MAC address must consist of 6 octets, otherwise it is invalid
check(mac_prefix_.size() != 6, errmsg);
check(mac_template_.size() != 6, errmsg);
}
void
CommandOptions::decodeDuid(const std::string& base) {
// Strip argument from duid=
std::vector<uint8_t> duid_prefix;
std::vector<uint8_t> duid_template;
size_t found = base.find('=');
check(found == std::string::npos, "expected -b<base> format for duid is -b duid=<duid>");
std::string b = base.substr(found + 1);
......@@ -484,26 +493,26 @@ CommandOptions::decodeDuid(const std::string& base) {
isc_throw(isc::InvalidParameter,
"invalid characters in DUID provided, exepected hex digits");
}
duid_prefix.push_back(static_cast<uint8_t>(ui));
duid_template.push_back(static_cast<uint8_t>(ui));
}
// Assign the new duid only if successfully generated.
std::swap(duid_prefix, duid_prefix_);
std::swap(duid_template, duid_template_);
}
void
CommandOptions::generateDuidPrefix() {
CommandOptions::generateDuidTemplate() {
using namespace boost::posix_time;
// Duid prefix will be most likely generated only once but
// Duid template will be most likely generated only once but
// it is ok if it is called more then once so we simply
// regenerate it and discard previous value.
duid_prefix_.clear();
const uint8_t duid_prefix_len = 14;
duid_prefix_.resize(duid_prefix_len);
duid_template_.clear();
const uint8_t duid_template_len = 14;
duid_template_.resize(duid_template_len);
// The first four octets consist of DUID LLT and hardware type.
duid_prefix_[0] = DUID_LLT >> 8;
duid_prefix_[1] = DUID_LLT & 0xff;
duid_prefix_[2] = HWTYPE_ETHERNET >> 8;
duid_prefix_[3] = HWTYPE_ETHERNET & 0xff;
duid_template_[0] = DUID_LLT >> 8;
duid_template_[1] = DUID_LLT & 0xff;
duid_template_[2] = HWTYPE_ETHERNET >> 8;
duid_template_[3] = HWTYPE_ETHERNET & 0xff;
// As described in RFC3315: 'the time value is the time
// that the DUID is generated represented in seconds
......@@ -512,12 +521,12 @@ CommandOptions::generateDuidPrefix() {
ptime duid_epoch(from_iso_string("20000101T000000"));
time_period period(duid_epoch, now);
uint32_t duration_sec = htonl(period.length().total_seconds());
memcpy(&duid_prefix_[4], &duration_sec, 4);
memcpy(&duid_template_[4], &duration_sec, 4);
// Set link layer address (6 octets). This value may be
// randomized before sending a packet to simulate different
// clients.
memcpy(&duid_prefix_[8], &mac_prefix_[0], 6);
memcpy(&duid_template_[8], &mac_template_[0], 6);
}
uint8_t
......
......@@ -23,7 +23,7 @@
namespace isc {
namespace perfdhcp {
/// \brief Command Options
/// \brief Command Options.
///
/// This class is responsible for parsing the command-line and storing the
/// specified options.
......@@ -49,64 +49,64 @@ public:
/// command line options.
void reset();
/// \brief Parse command line
/// \brief Parse command line.
///
/// Parses the command line and stores the selected options
/// in class data members.
///
/// \param argc Argument count passed to main().
/// \param argv Argument value array passed to main().
/// \throws isc::InvalidParameter if parse fails
/// \throws isc::InvalidParameter if parse fails.
void parse(int argc, char** const argv);
/// \brief Returns IP version
/// \brief Returns IP version.
///
/// \return IP version to be used
/// \return IP version to be used.
uint8_t getIpVersion() const { return ipversion_; }
/// \brief Returns packet exchange mode
/// \brief Returns packet exchange mode.
///
/// \return packet exchange mode
/// \return packet exchange mode.
ExchangeMode getExchangeMode() const { return exchange_mode_; }
/// \brief Returns echange rate
/// \brief Returns echange rate.
///
/// \return exchange rate per second
/// \return exchange rate per second.
int getRate() const { return rate_; }
/// \brief Returns delay between two performance reports
/// \brief Returns delay between two performance reports.
///
/// \return delay between two consecutive performance reports
/// \return delay between two consecutive performance reports.
int getReportDelay() const { return report_delay_; }
/// \brief Returns number of simulated clients
/// \brief Returns number of simulated clients.
///
/// \return number of simulated clients
/// \return number of simulated clients.
uint32_t getClientsNum() const { return clients_num_; }
/// \brief Returns MAC address prefix
/// \brief Returns MAC address template.
///
/// \ return MAC address prefix to simulate different clients
std::vector<uint8_t> getMacPrefix() const { return mac_prefix_; }
/// \return MAC address template to simulate different clients.
std::vector<uint8_t> getMacTemplate() const { return mac_template_; }
/// \brief Returns DUID prefix
/// \brief Returns DUID template.
///
/// \return DUID prefix to simulate different clients
std::vector<uint8_t> getDuidPrefix() const { return duid_prefix_; }
/// \return DUID template to simulate different clients.
std::vector<uint8_t> getDuidTemplate() const { return duid_template_; }
/// \brief Returns base values
/// \brief Returns base values.
///
/// \return all base values specified
/// \return all base values specified.
std::vector<std::string> getBase() const { return base_; }
/// \brief Returns maximum number of exchanges
/// \brief Returns maximum number of exchanges.
///
/// \return number of exchange requests before test is aborted
/// \return number of exchange requests before test is aborted.
std::vector<int> getNumRequests() const { return num_request_; }
/// \brief Returns test period
/// \brief Returns test period.
///
/// \return test period before it is aborted
/// \return test period before it is aborted.
int getPeriod() const { return period_; }
/// \brief Returns drop time
......@@ -114,139 +114,139 @@ public:
/// The method returns maximum time elapsed from
/// sending the packet before it is assumed dropped.
///
/// \return return time before request is assumed dropped
/// \return return time before request is assumed dropped.
std::vector<double> getDropTime() const { return drop_time_; }
/// \brief Returns maximum drops number
/// \brief Returns maximum drops number.
///
/// Returns maximum number of packet drops before
/// aborting a test.
///
/// \return maximum number of dropped requests
/// \return maximum number of dropped requests.
std::vector<int> getMaxDrop() const { return max_drop_; }
/// \brief Returns maximal percentage of drops
/// \brief Returns maximal percentage of drops.
///
/// Returns maximal percentage of packet drops
/// before aborting a test.
///
/// \return maximum percentage of lost requests
/// \return maximum percentage of lost requests.
std::vector<double> getMaxDropPercentage() const { return max_pdrop_; }
/// \brief Returns local address or interface name
/// \brief Returns local address or interface name.
///
/// \return local address or interface name
/// \return local address or interface name.
std::string getLocalName() const { return localname_; }
/// \brief Checks if interface name was used
/// \brief Checks if interface name was used.
///
/// The method checks if interface name was used
/// rather than address.
///
/// \return true if interface name was used
/// \return true if interface name was used.
bool isInterface() const { return is_interface_; }
/// \brief Returns number of preload exchanges
/// \brief Returns number of preload exchanges.
///
/// \return number of preload exchanges
/// \return number of preload exchanges.
int getPreload() const { return preload_; }
/// \brief Returns aggressivity value
/// \brief Returns aggressivity value.
///
/// \return aggressivity value
/// \return aggressivity value.
int getAggressivity() const { return aggressivity_; }
/// \brief Returns local port number
/// \brief Returns local port number.
///
/// \return local port number
/// \return local port number.
int getLocalPort() const { return local_port_; }
/// \brief Checks if seed provided
/// \brief Checks if seed provided.
///
/// \return true if seed was provided
/// \return true if seed was provided.
bool isSeeded() const { return seeded_; }
/// \brief Returns radom seed
/// \brief Returns radom seed.
///
/// \return random seed
/// \return random seed.
uint32_t getSeed() const { return seed_; }
/// \brief Checks if broadcast address is to be used
/// \brief Checks if broadcast address is to be used.
///
/// \return true if broadcast address is to be used
/// \return true if broadcast address is to be used.
bool isBroadcast() const { return broadcast_; }
/// \brief Check if rapid commit option used
/// \brief Check if rapid commit option used.
///
/// \return true if rapid commit option is used
/// \return true if rapid commit option is used.
bool isRapidCommit() const { return rapid_commit_; }
/// \brief Check if server-ID to be taken from first package
/// \brief Check if server-ID to be taken from first package.
///
/// \return true if server-iD to be taken from first package
/// \return true if server-iD to be taken from first package.
bool isUseFirst() const { return use_first_; }
/// \brief Returns template file names
/// \brief Returns template file names.
///
/// \return template file names
/// \return template file names.
std::vector<std::string> getTemplateFiles() const { return template_file_; }
/// brief Returns template offsets for xid
/// brief Returns template offsets for xid.
///
/// \return template offsets for xid
/// \return template offsets for xid.
std::vector<int> getTransactionIdOffset() const { return xid_offset_; }
/// \brief Returns template offsets for rnd
/// \brief Returns template offsets for rnd.
///
/// \return template offsets for rnd
/// \return template offsets for rnd.
std::vector<int> getRandomOffset() const { return rnd_offset_; }
/// \brief Returns template offset for elapsed time
/// \brief Returns template offset for elapsed time.
///
/// \return template offset for elapsed time
/// \return template offset for elapsed time.
int getElapsedTimeOffset() const { return elp_offset_; }
/// \brief Returns template offset for server-ID
/// \brief Returns template offset for server-ID.
///
/// \return template offset for server-ID
/// \return template offset for server-ID.
int getServerIdOffset() const { return sid_offset_; }
/// \brief Returns template offset for requested IP
/// \brief Returns template offset for requested IP.
///
/// \return template offset for requested IP
/// \return template offset for requested IP.
int getRequestedIpOffset() const { return rip_offset_; }
/// \brief Returns diagnostic selectors
/// \brief Returns diagnostic selectors.
///
/// \return diagnostics selector
/// \return diagnostics selector.
std::string getDiags() const { return diags_; }
/// \brief Returns wrapped command
/// \brief Returns wrapped command.
///
/// \return wrapped command (start/stop)
/// \return wrapped command (start/stop).
std::string getWrapped() const { return wrapped_; }
/// \brief Returns server name
/// \brief Returns server name.
///
/// \return server name
/// \return server name.
std::string getServerName() const { return server_name_; }
/// \brief Prints command line arguments.
/// \brief Print command line arguments.
void printCommandLine() const;
/// \brief Print usage
/// \brief Print usage.
///
/// Prints perfdhcp usage
/// Prints perfdhcp usage.
void usage() const;
/// \brief Print program version
/// \brief Print program version.
///
/// Prints perfdhcp version
/// Prints perfdhcp version.
void version() const;
private:
/// \brief Default Constructor
/// \brief Default Constructor.
///
/// Private constructor as this is a singleton class.
/// Use CommandOptions::instance() to get instance of it.
......@@ -254,54 +254,54 @@ private:
reset();
}
/// \brief Initializes class members based command line
/// \brief Initializes class members based on the command line.
///
/// Reads each command line parameter and sets class member values
/// Reads each command line parameter and sets class member values.
///
/// \param argc Argument count passed to main().
/// \param argv Argument value array passed to main().
/// \throws isc::InvalidParameter if command line options initialization fails
/// \throws isc::InvalidParameter if command line options initialization fails.
void initialize(int argc, char** argv);
/// \brief Validates initialized options
/// \brief Validates initialized options.
///
/// \throws isc::InvalidParameter if command line validation fails
/// \throws isc::InvalidParameter if command line validation fails.
void validate() const;
/// \brief Throws !InvalidParameter exception if condition is true
/// \brief Throws !InvalidParameter exception if condition is true.
///
/// Convenience function that throws an InvalidParameter exception if
/// the condition argument is true
/// the condition argument is true.
///
/// \param condition Condition to be checked
/// \param errmsg Error message in exception
/// \throws isc::InvalidParameter if condition argument true
/// \param condition Condition to be checked.
/// \param errmsg Error message in exception.
/// \throws isc::InvalidParameter if condition argument true.
inline void check(bool condition, const std::string& errmsg) const;
/// \brief Casts command line argument to positive integer
/// \brief Casts command line argument to positive integer.
///
/// \param errmsg Error message if lexical cast fails
/// \throw InvalidParameter if lexical cast fails
/// \param errmsg Error message if lexical cast fails.
/// \throw InvalidParameter if lexical cast fails.
int positiveInteger(const std::string& errmsg) const;
/// \brief Casts command line argument to non-negative integer
/// \brief Casts command line argument to non-negative integer.
///
/// \param errmsg Error message if lexical cast fails
/// \throw InvalidParameter if lexical cast fails
/// \param errmsg Error message if lexical cast fails.
/// \throw InvalidParameter if lexical cast fails.
int nonNegativeInteger(const std::string& errmsg) const;
/// \brief Returns command line string if it is not empty
/// \brief Returns command line string if it is not empty.
///
/// \param errmsg Error message if string is empty
/// \throw InvalidParameter if string is empty
/// \param errmsg Error message if string is empty.
/// \throw InvalidParameter if string is empty.
std::string nonEmptyString(const std::string& errmsg) const;
/// \brief Set number of clients
/// \brief Set number of clients.
///
/// Interprets the getopt() "opt" global variable as the number of clients
/// (a non-negative number). This value is specified by the "-R" switch.
///
/// \throw InvalidParameter if -R<value> is wrong
/// \throw InvalidParameter if -R<value> is wrong.
void initClientsNum();
/// \brief Sets value indicating if interface name was given.
......@@ -311,7 +311,7 @@ private:
/// is set accordingly.
void initIsInterface();
/// \brief Decodes base provided with -b<base>
/// \brief Decodes base provided with -b<base>.
///
/// Function decodes argument of -b switch, which
/// specifies a base value used to generate unique
......@@ -321,45 +321,47 @@ private:
/// - -b mac=00:01:02:03:04:05
/// - -b duid=0F1234 (duid can be up to 128 hex digits)
// Function will decode 00:01:02:03:04:05 and/or
/// 0F1234 respectively and initialize mac_prefix_
/// and/or duid_prefix_ members
/// 0F1234 respectively and initialize mac_template_
/// and/or duid_template_ members.
///
/// \param base Base in string format
/// \throws isc::InvalidParameter if base is invalid
/// \param base Base in string format.
/// \throws isc::InvalidParameter if base is invalid.
void decodeBase(const std::string& base);
/// \brief Decodes base MAC address provided with -b<base>
/// \brief Decodes base MAC address provided with -b<base>.
///
/// Function decodes parameter given as -b mac=00:01:02:03:04:05
/// The function will decode 00:01:02:03:04:05 initialize mac_prefix_
/// The function will decode 00:01:02:03:04:05 initialize mac_template_
/// class member.
/// Provided MAC address is for example only
/// Provided MAC address is for example only.
///
/// \param base Base string given as -b mac=00:01:02:03:04:05
/// \throws isc::InvalidParameter if mac address is invalid
/// \param base Base string given as -b mac=00:01:02:03:04:05.
/// \throws isc::InvalidParameter if mac address is invalid.
void decodeMac(const std::string& base);
/// \brief Decodes base DUID provided with -b<base>
/// \brief Decodes base DUID provided with -b<base>.
///
/// Function decodes parameter given as -b duid=0F1234
/// The function will decode 0F1234 and initialize duid_prefix_
/// Function decodes parameter given as -b duid=0F1234.
/// The function will decode 0F1234 and initialize duid_template_
/// class member.
/// Provided DUID is for example only.
///
/// \param base Base string given as -b duid=0F1234
/// \throws isc::InvalidParameter if DUID is invalid
/// \param base Base string given as -b duid=0F1234.
/// \throws isc::InvalidParameter if DUID is invalid.
void decodeDuid(const std::string& base);
/// \brief Generates DUID-LLT (based on link layer address).
///
/// Function generates DUID based on link layer address and
/// initiates duid_prefix_ value with it.
void generateDuidPrefix();
/// initiates duid_template_ value with it.
/// \todo add support to generate DUIDs other than based on
/// 6-octets long MACs (e.g. DUID-UUID.
void generateDuidTemplate();
/// \brief Converts two-digit hexadecimal string to a byte
/// \brief Converts two-digit hexadecimal string to a byte.
///
/// \param hex_text Hexadecimal string e.g. AF
/// \throw isc::InvalidParameter if string does not represent hex byte
/// \param hex_text Hexadecimal string e.g. AF.
/// \throw isc::InvalidParameter if string does not represent hex byte.
uint8_t convertHexString(const std::string& hex_text) const;
uint8_t ipversion_; ///< IP protocol version to be used, expected values are:
......@@ -369,9 +371,9 @@ private:
int report_delay_; ///< Delay between generation of two consecutive
///< performance reports
uint32_t clients_num_; ///< Number of simulated clients (aka randomization range).
std::vector<uint8_t> mac_prefix_; ///< MAC address prefix used to generate unique DUIDs
std::vector<uint8_t> mac_template_; ///< MAC address template used to generate unique DUIDs
///< for simulated clients.
std::vector<uint8_t> duid_prefix_; ///< DUID prefix used to generate unique DUIDs for
std::vector<uint8_t> duid_template_; ///< DUID template used to generate unique DUIDs for
///< simulated clients
std::vector<std::string> base_; ///< Collection of base values specified with -b<value>
///< options. Supported "bases" are mac=<mac> and duid=<duid>
......@@ -420,6 +422,7 @@ private:
std::string wrapped_; ///< Wrapped command specified as -w<value>. Expected
///< values are start and stop.
std::string server_name_; ///< Server name specified as last argument of command line.
std::string commandline_; ///< Entire command line as typed in by the user.
};
} // namespace perfdhcp
......
......@@ -44,30 +44,43 @@ namespace perfdhcp {
///
class LocalizedOption : public dhcp::Option {
public:
/// \brief Constructor, sets default (0) option offset
/// \brief Constructor, used to create localized option from buffer.
///
/// \param u specifies universe (V4 or V6)
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \param data content of the option
/// This constructor creates localized option using whole provided
/// option buffer.
///
/// \param u universe (V4 or V6).
/// \param type option type (0-255 for V4 and 0-65535 for V6).
/// Option values 0 and 255 (v4) and 0 (v6) are not valid option
/// codes but they are accepted here for the server testing purposes.
/// \param data content of the option.
/// \param offset location of option in a packet (zero is default).
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& data) :
const dhcp::OptionBuffer& data,
const size_t offset = 0) :
dhcp::Option(u, type, data),
offset_(0), option_valid_(true) {
offset_(offset), option_valid_(true) {
}
/// \brief Constructor, used to create localized option from buffer
/// \brief Constructor, used to create option from buffer iterators.
///
/// This constructor creates localized option using part of the
/// option buffer pointed by iterators.
///
/// \param u specifies universe (V4 or V6)
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \param data content of the option
/// \param offset location of option in a packet (zero is default)
/// \param first iterator to the first element that should be copied
/// \param last iterator to the next element after the last one
/// to be copied.
/// \param offset offset of option in a packet (zero is default)
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& data,
const size_t offset) :
dhcp::Option(u, type, data),
dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last,
const size_t offset = 0) :
dhcp::Option(u, type, first, last),
offset_(offset), option_valid_(true) {
}
......@@ -113,44 +126,6 @@ public:
}
}
/// \brief Constructor, sets default (0) option offset
///
/// This contructor is similar to the previous one, but it does not take
/// the whole vector<uint8_t>, but rather subset of it.
///
/// \param u specifies universe (V4 or V6)
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \param first iterator to the first element that should be copied
/// \param last iterator to the next element after the last one
/// to be copied.
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last) :
dhcp::Option(u, type, first, last),
offset_(0), option_valid_(true) {
}
/// \brief Constructor, used to create option from buffer iterators
///
/// This contructor is similar to the previous one, but it does not take
/// the whole vector<uint8_t>, but rather subset of it.
///
/// \param u specifies universe (V4 or V6)
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \param first iterator to the first element that should be copied
/// \param last iterator to the next element after the last one
/// to be copied.
/// \param offset offset of option in a packet (zero is default)