diff options
author | Marcin Siodelski <marcin@isc.org> | 2016-09-01 18:03:04 +0200 |
---|---|---|
committer | Marcin Siodelski <marcin@isc.org> | 2016-09-01 18:03:04 +0200 |
commit | c5b4a5981cf642ebb9aecb8acc07b87abdccbd91 (patch) | |
tree | cf3cfadbd73e3bb7317fad75abff4ba804c4ac70 /src/bin | |
parent | [master] configure.ac version update (diff) | |
parent | [github22] Updated AUTHORS file. (diff) | |
download | kea-c5b4a5981cf642ebb9aecb8acc07b87abdccbd91.tar.xz kea-c5b4a5981cf642ebb9aecb8acc07b87abdccbd91.zip |
[master] Merge branch 'github22'
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/perfdhcp/command_options.cc | 92 | ||||
-rw-r--r-- | src/bin/perfdhcp/command_options.h | 43 | ||||
-rw-r--r-- | src/bin/perfdhcp/perfdhcp.xml | 33 | ||||
-rw-r--r-- | src/bin/perfdhcp/test_control.cc | 150 | ||||
-rw-r--r-- | src/bin/perfdhcp/test_control.h | 8 | ||||
-rw-r--r-- | src/bin/perfdhcp/tests/command_options_unittest.cc | 47 | ||||
-rw-r--r-- | src/bin/perfdhcp/tests/test_control_unittest.cc | 85 | ||||
-rw-r--r-- | src/bin/perfdhcp/tests/testdata/Makefile.am | 1 | ||||
-rw-r--r-- | src/bin/perfdhcp/tests/testdata/mac-list.txt | 4 |
9 files changed, 404 insertions, 59 deletions
diff --git a/src/bin/perfdhcp/command_options.cc b/src/bin/perfdhcp/command_options.cc index 4c8405117c..15295006d0 100644 --- a/src/bin/perfdhcp/command_options.cc +++ b/src/bin/perfdhcp/command_options.cc @@ -20,6 +20,7 @@ #include <stdlib.h> #include <stdint.h> #include <unistd.h> +#include <fstream> using namespace std; @@ -117,6 +118,8 @@ CommandOptions::reset() { mac_template_.assign(mac, mac + 6); duid_template_.clear(); base_.clear(); + mac_list_file_.clear(); + mac_list_.clear(); num_request_.clear(); period_ = 0; drop_time_set_ = 0; @@ -142,6 +145,7 @@ CommandOptions::reset() { diags_.clear(); wrapped_.clear(); server_name_.clear(); + v6_relay_encapsulation_level_ = 0; generateDuidTemplate(); } @@ -205,10 +209,11 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { std::ostringstream stream; stream << "perfdhcp"; + int num_mac_list_files = 0; // 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:" + while((opt = getopt(argc, argv, "hv46A:r:t:R:b:n:p:d:D:l:P:a:L:M:" "s:iBc1T:X:O:E:S:I:x:w:e:f:F:")) != -1) { stream << " -" << static_cast<char>(opt); if (optarg) { @@ -219,6 +224,19 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { use_first_ = true; break; + // Simulate DHCPv6 relayed traffic. + case 'A': + // @todo: At the moment we only support simulating a single relay + // agent. In the future we should extend it to up to 32. + // See comment in https://github.com/isc-projects/kea/pull/22#issuecomment-243405600 + v6_relay_encapsulation_level_ = + static_cast<uint8_t>(positiveInteger("-A<encapusulation-level> must" + " be a positive integer")); + if (v6_relay_encapsulation_level_ != 1) { + isc_throw(isc::InvalidParameter, "-A only supports 1 at the moment."); + } + break; + case '4': check(ipversion_ == 6, "IP version already set to 6"); ipversion_ = 4; @@ -340,6 +358,13 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max())); break; + case 'M': + check(num_mac_list_files >= 1, "only -M option can be specified"); + num_mac_list_files++; + mac_list_file_ = std::string(optarg); + loadMacs(); + break; + case 'n': num_req = positiveInteger("value of num-request:" " -n<value> must be a positive integer"); @@ -554,7 +579,7 @@ CommandOptions::decodeBase(const std::string& base) { // Currently we only support mac and duid if ((b.substr(0, 4) == "mac=") || (b.substr(0, 6) == "ether=")) { - decodeMac(b); + decodeMacBase(b); } else if (b.substr(0, 5) == "duid=") { decodeDuid(b); } else { @@ -565,7 +590,7 @@ CommandOptions::decodeBase(const std::string& base) { } void -CommandOptions::decodeMac(const std::string& base) { +CommandOptions::decodeMacBase(const std::string& base) { // Strip string from mac= size_t found = base.find('='); static const char* errmsg = "expected -b<base> format for" @@ -685,12 +710,45 @@ CommandOptions::convertHexString(const std::string& text) const { return ui; } +void CommandOptions::loadMacs() { + std::string line; + std::ifstream infile(mac_list_file_.c_str()); + while (std::getline(infile, line)) { + check(decodeMacString(line), "invalid mac in input"); + } +} + +bool CommandOptions::decodeMacString(const std::string& line) { + // decode mac string into a vector of uint8_t returns true in case of error. + std::istringstream s(line); + std::string token; + std::vector<uint8_t> mac; + while(std::getline(s, token, ':')) { + // Convert token to byte value using std::istringstream + if (token.length() > 0) { + unsigned int ui = 0; + try { + // Do actual conversion + ui = convertHexString(token); + } catch (isc::InvalidParameter&) { + return (true); + } + // If conversion succeeded store byte value + mac.push_back(ui); + } + } + mac_list_.push_back(mac); + return (false); +} + void CommandOptions::validate() const { check((getIpVersion() != 4) && (isBroadcast() != 0), "-B is not compatible with IPv6 (-6)"); check((getIpVersion() != 6) && (isRapidCommit() != 0), "-6 (IPv6) must be set to use -c"); + check(getIpVersion() == 4 && isUseRelayedV6(), + "Can't use -4 with -A, it's a V6 only option."); check((getIpVersion() != 6) && (getReleaseRate() != 0), "-F<release-rate> may be used with -6 (IPv6) only"); check((getExchangeMode() == DO_SA) && (getNumRequests().size() > 1), @@ -757,7 +815,8 @@ CommandOptions::validate() const { check((getTemplateFiles().size() < 2) && (getRequestedIpOffset() >= 0), "second/request -T<template-file> must be set to " "use -I<ip-offset>"); - + check((!getMacListFile().empty() && base_.size() > 0), + "Can't use -b with -M option"); } void @@ -871,6 +930,9 @@ CommandOptions::printCommandLine() const { if (use_first_) { std::cout << "use-first" << std::endl; } + if (!mac_list_file_.empty()) { + std::cout << "mac-list-file=" << mac_list_file_ << std::endl; + } for (size_t i = 0; i < template_file_.size(); ++i) { std::cout << "template-file[" << i << "]=" << template_file_[i] << std::endl; } @@ -910,15 +972,16 @@ CommandOptions::printCommandLine() const { void CommandOptions::usage() const { std::cout << - "perfdhcp [-hv] [-4|-6] [-e<lease-type>] [-r<rate>] [-f<renew-rate>]\n" + "perfdhcp [-hv] [-4|-6] [-A<encapusulation-level>] [-e<lease-type>]" + " [-r<rate>] [-f<renew-rate>]\n" " [-F<release-rate>] [-t<report>] [-R<range>] [-b<base>]\n" " [-n<num-request>] [-p<test-period>] [-d<drop-time>]\n" " [-D<max-drop>] [-l<local-addr|interface>] [-P<preload>]\n" " [-a<aggressivity>] [-L<local-port>] [-s<seed>] [-i] [-B]\n" - " [-c] [-1] [-T<template-file>] [-X<xid-offset>]\n" - " [-O<random-offset] [-E<time-offset>] [-S<srvid-offset>]\n" - " [-I<ip-offset>] [-x<diagnostic-selector>] [-w<wrapped>]\n" - " [server]\n" + " [-c] [-1] [-M<mac-list-file>] [-T<template-file>]\n" + " [-X<xid-offset>] [-O<random-offset] [-E<time-offset>]\n" + " [-S<srvid-offset>] [-I<ip-offset>] [-x<diagnostic-selector>]\n" + " [-w<wrapped>] [server]\n" "\n" "The [server] argument is the name/address of the DHCP server to\n" "contact. For DHCPv4 operation, exchanges are initiated by\n" @@ -979,6 +1042,11 @@ CommandOptions::usage() const { " via which exchanges are initiated.\n" "-L<local-port>: Specify the local port to use\n" " (the value 0 means to use the default).\n" + "-M<mac-list-file>: A text file containing a list of MAC addresses,\n" + " one per line. If provided, a MAC address will be choosen randomly\n" + " from this list for every new exchange. In the DHCPv6 case, MAC\n" + " addresses are used to generate DUID-LLs. This parameter must not be\n" + " used in conjunction with the -b parameter.\n" "-O<random-offset>: Offset of the last octet to randomize in the template.\n" "-P<preload>: Initiate first <preload> exchanges back to back at startup.\n" "-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)\n" @@ -1018,6 +1086,12 @@ CommandOptions::usage() const { " the exchange rate (given by -r<rate>). Furthermore the sum of\n" " this value and the renew-rate (given by -f<rate) must be equal\n" " to or less than the exchange rate.\n" + "-A<encapusulation-level>: Specifies that relayed traffic must be\n" + " generated. The argument specifies the level of encapsulation, i.e.\n" + " how many relay agents are simulated. Currently the only supported\n" + " <encapsulation-level> value is 1, which means that the generated\n" + " traffic is an equivalent of the traffic passing through a single\n" + " relay agent.\n" "\n" "The remaining options are used only in conjunction with -r:\n" "\n" diff --git a/src/bin/perfdhcp/command_options.h b/src/bin/perfdhcp/command_options.h index baa1a70af4..5d588b1893 100644 --- a/src/bin/perfdhcp/command_options.h +++ b/src/bin/perfdhcp/command_options.h @@ -24,6 +24,9 @@ namespace perfdhcp { class CommandOptions : public boost::noncopyable { public: + /// @brief A vector holding MAC addresses. + typedef std::vector<std::vector<uint8_t> > MacAddrsVector; + /// \brief A class encapsulating the type of lease being requested from the /// server. /// @@ -269,11 +272,31 @@ public: /// \return true if server-iD to be taken from first package. bool isUseFirst() const { return use_first_; } + /// \brief Check if generated DHCPv6 messages shuold appear as relayed. + /// + /// \return true if generated traffic should appear as relayed. + bool isUseRelayedV6() const { return (v6_relay_encapsulation_level_ > 0); } + /// \brief Returns template file names. /// /// \return template file names. std::vector<std::string> getTemplateFiles() const { return template_file_; } + /// \brief Returns location of the file containing list of MAC addresses. + /// + /// MAC addresses read from the file are used by the perfdhcp in message + /// exchanges with the DHCP server. + /// + /// \return Location of the file containing list of MAC addresses. + std::string getMacListFile() const { return mac_list_file_; } + + /// \brief Returns reference to a vector of MAC addresses read from a file. + /// + /// Every MAC address is represented as a vector. + /// + /// \return Reference to a vector of vectors. + const MacAddrsVector& getMacsFromFile() const { return mac_list_; } + /// brief Returns template offsets for xid. /// /// \return template offsets for xid. @@ -427,7 +450,7 @@ private: /// /// \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); + void decodeMacBase(const std::string& base); /// \brief Decodes base DUID provided with -b<base>. /// @@ -454,6 +477,14 @@ private: /// \throw isc::InvalidParameter if string does not represent hex byte. uint8_t convertHexString(const std::string& hex_text) const; + /// \brief Opens the text file containing list of macs (one per line) + /// and adds them to the mac_list_ vector. + void loadMacs(); + + /// \brief Decodes a mac string into a vector of uint8_t and adds it to the + /// mac_list_ vector. + bool decodeMacString(const std::string& line); + /// IP protocol version to be used, expected values are: /// 4 for IPv4 and 6 for IPv6, default value 0 means "not set" uint8_t ipversion_; @@ -528,6 +559,14 @@ private: /// that are used for initiating exchanges. Template packets /// read from files are later tuned with variable data. std::vector<std::string> template_file_; + /// Location of a file containing a list of MAC addresses, one per line. + /// This can be used if you don't want to generate MAC address from a + /// base MAC address, but rather provide the file with a list of MAC + /// addresses to be randomly picked. Note that in DHCPv6 those MAC + /// addresses will be used to generate DUID-LL. + std::string mac_list_file_; + /// List of MAC addresses loaded from a file. + std::vector<std::vector<uint8_t> > mac_list_; /// Offset of transaction id in template files. First vector /// element points to offset for DISCOVER/SOLICIT messages, /// second element points to transaction id offset for @@ -551,6 +590,8 @@ private: std::string wrapped_; /// Server name specified as last argument of command line. std::string server_name_; + /// Indicates how many DHCPv6 relay agents are simulated. + uint8_t v6_relay_encapsulation_level_; }; } // namespace perfdhcp diff --git a/src/bin/perfdhcp/perfdhcp.xml b/src/bin/perfdhcp/perfdhcp.xml index f6967f811c..79d0f94673 100644 --- a/src/bin/perfdhcp/perfdhcp.xml +++ b/src/bin/perfdhcp/perfdhcp.xml @@ -11,7 +11,7 @@ <refentry> <refentryinfo> - <date>February 19, 2014</date> + <date>August 31, 2016</date> </refentryinfo> <refmeta> @@ -27,7 +27,7 @@ <docinfo> <copyright> - <year>2014</year> + <year>2016</year> <holder>Internet Systems Consortium, Inc. ("ISC")</holder> </copyright> </docinfo> @@ -37,6 +37,7 @@ <command>perfdhcp</command> <arg><option>-1</option></arg> <arg><option>-4|-6</option></arg> + <arg><option>-A <replaceable class="parameter">encapsulation-level</replaceable></option></arg> <arg><option>-a <replaceable class="parameter">aggressivity</replaceable></option></arg> <arg><option>-b <replaceable class="parameter">base</replaceable></option></arg> <arg><option>-B</option></arg> @@ -52,6 +53,7 @@ <arg><option>-I <replaceable class="parameter">ip-offset</replaceable></option></arg> <arg><option>-l <replaceable class="parameter">local-address|interface</replaceable></option></arg> <arg><option>-L <replaceable class="parameter">local-port</replaceable></option></arg> + <arg><option>-M <replaceable class="parameter">mac-list-file</replaceable></option></arg> <arg><option>-n <replaceable class="parameter">num-request</replaceable></option></arg> <arg><option>-O <replaceable class="parameter">random-offset</replaceable></option></arg> <arg><option>-p <replaceable class="parameter">test-period</replaceable></option></arg> @@ -393,6 +395,19 @@ </varlistentry> <varlistentry> + <term><option>-M <replaceable class="parameter">mac-list-file</replaceable></option></term> + <listitem> + <para> + A text file containing a list of MAC addresses, + one per line. If provided, a MAC address will be choosen randomly + from this list for every new exchange. In the DHCPv6 case, MAC + addresses are used to generate DUID-LLs. This parameter must not be + used in conjunction with the -b parameter. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><option>-P <replaceable class="parameter">preload</replaceable></option></term> <listitem> <para> @@ -594,6 +609,20 @@ </listitem> </varlistentry> + <varlistentry> + <term><option>-A <replaceable class="parameter">encapsulation-level</replaceable></option></term> + <listitem> + <para> + Specifies that relayed traffic must be + generated. The argument specifies the level of encapsulation, i.e. + how many relay agents are simulated. Currently the only supported + <replaceable class="parameter">encapsulation-level</replaceable> + value is 1, which means that the generated traffic is an equivalent + of the traffic passing through a single relay agent. + </para> + </listitem> + </varlistentry> + </variablelist> </refsect2> diff --git a/src/bin/perfdhcp/test_control.cc b/src/bin/perfdhcp/test_control.cc index bcb28f303a..5c79b2cc02 100644 --- a/src/bin/perfdhcp/test_control.cc +++ b/src/bin/perfdhcp/test_control.cc @@ -21,6 +21,7 @@ #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/foreach.hpp> +#include <algorithm> #include <fstream> #include <stdio.h> #include <stdlib.h> @@ -79,8 +80,9 @@ TestControl::instance() { return (test_control); } -TestControl::TestControl() { - reset(); +TestControl::TestControl() + : number_generator_(0, CommandOptions::instance().getMacsFromFile().size()) { + reset(); } void @@ -464,38 +466,51 @@ TestControl::factoryRequestList4(Option::Universe u, } std::vector<uint8_t> -TestControl::generateMacAddress(uint8_t& randomized) const { +TestControl::generateMacAddress(uint8_t& randomized) { CommandOptions& options = CommandOptions::instance(); - uint32_t clients_num = options.getClientsNum(); - if (clients_num < 2) { - return (options.getMacTemplate()); - } - // Get the base MAC address. We are going to randomize part of it. - std::vector<uint8_t> mac_addr(options.getMacTemplate()); - if (mac_addr.size() != HW_ETHER_LEN) { - isc_throw(BadValue, "invalid MAC address template specified"); - } - uint32_t r = macaddr_gen_->generate(); - randomized = 0; - // Randomize MAC address octets. - for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1; - it >= mac_addr.begin(); - --it) { - // Add the random value to the current octet. - (*it) += r; - ++randomized; - if (r < 256) { - // If we are here it means that there is no sense - // to randomize the remaining octets of MAC address - // because the following bytes of random value - // are zero and it will have no effect. - break; - } - // Randomize the next octet with the following - // byte of random value. - r >>= 8; + + const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile(); + // if we are using the -M option return a random one from the list... + if (macs.size() > 0) { + uint16_t r = number_generator_(); + if (r >= macs.size()) { + r = 0; + } + return macs[r]; + + } else { + // ... otherwise use the standard behavior + uint32_t clients_num = options.getClientsNum(); + if (clients_num < 2) { + return (options.getMacTemplate()); + } + // Get the base MAC address. We are going to randomize part of it. + std::vector<uint8_t> mac_addr(options.getMacTemplate()); + if (mac_addr.size() != HW_ETHER_LEN) { + isc_throw(BadValue, "invalid MAC address template specified"); + } + uint32_t r = macaddr_gen_->generate(); + randomized = 0; + // Randomize MAC address octets. + for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1; + it >= mac_addr.begin(); + --it) { + // Add the random value to the current octet. + (*it) += r; + ++randomized; + if (r < 256) { + // If we are here it means that there is no sense + // to randomize the remaining octets of MAC address + // because the following bytes of random value + // are zero and it will have no effect. + break; + } + // Randomize the next octet with the following + // byte of random value. + r >>= 8; + } + return (mac_addr); } - return (mac_addr); } OptionPtr @@ -508,20 +523,50 @@ TestControl::generateClientId(const dhcp::HWAddrPtr& hwaddr) const { } std::vector<uint8_t> -TestControl::generateDuid(uint8_t& randomized) const { +TestControl::generateDuid(uint8_t& randomized) { CommandOptions& options = CommandOptions::instance(); - uint32_t clients_num = options.getClientsNum(); - if ((clients_num == 0) || (clients_num == 1)) { - return (options.getDuidTemplate()); - } - // Get the base DUID. We are going to randomize part of it. - std::vector<uint8_t> duid(options.getDuidTemplate()); - // @todo: add support for DUIDs of different sizes. std::vector<uint8_t> mac_addr(generateMacAddress(randomized)); - duid.resize(duid.size()); - std::copy(mac_addr.begin(), mac_addr.end(), - duid.begin() + duid.size() - mac_addr.size()); - return (duid); + const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile(); + // pick a random mac address if we are using option -M.. + if (macs.size() > 0) { + uint16_t r = number_generator_(); + if (r >= macs.size()) { + r = 0; + } + std::vector<uint8_t> mac = macs[r]; + // DUID_LL is in this format + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | 3 | hardware type (16 bits) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // . . + // . link-layer address (variable length) . + // . . + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // No C++11 so initializer list support, building a vector<uint8_t> is a + // pain... + uint8_t duid_ll[] = {0, 3, 0, 1, 0, 0, 0, 0, 0, 0}; + // copy duid_ll array into the vector + std::vector<uint8_t> duid(duid_ll, + duid_ll + sizeof(duid_ll) / sizeof(duid_ll[0])); + // put the mac address bytes at the end + std::copy(mac.begin(), mac.end(), duid.begin() + 4); + return (duid); + } else { + uint32_t clients_num = options.getClientsNum(); + if ((clients_num == 0) || (clients_num == 1)) { + return (options.getDuidTemplate()); + } + // Get the base DUID. We are going to randomize part of it. + std::vector<uint8_t> duid(options.getDuidTemplate()); + // @todo: add support for DUIDs of different sizes. + duid.resize(duid.size()); + std::copy(mac_addr.begin(), mac_addr.end(), + duid.begin() + duid.size() - mac_addr.size()); + return (duid); + } } uint32_t @@ -745,7 +790,12 @@ TestControl::openSocket() const { if (port == 0) { if (family == AF_INET6) { + // need server port (547) because the server is acting as a relay agent port = DHCP6_CLIENT_PORT; + // if acting as a relay agent change port. + if (options.isUseRelayedV6()) { + port = DHCP6_SERVER_PORT; + } } else if (options.getIpVersion() == 4) { port = 67; // TODO: find out why port 68 is wrong here. } @@ -2192,6 +2242,18 @@ TestControl::setDefaults6(const TestControlSocket& socket, pkt->setLocalAddr(socket.addr_); // The remote server's name or IP. pkt->setRemoteAddr(IOAddress(options.getServerName())); + + // only act as a relay agent when told so. + // TODO: support more level of encapsulation, at the moment we only support + // one, via -A1 option. + if (options.isUseRelayedV6()) { + Pkt6::RelayInfo relay_info; + relay_info.msg_type_ = DHCPV6_RELAY_FORW; + relay_info.hop_count_ = 1; + relay_info.linkaddr_ = IOAddress(socket.addr_); + relay_info.peeraddr_ = IOAddress(socket.addr_); + pkt->addRelayInfo(relay_info); + } } bool diff --git a/src/bin/perfdhcp/test_control.h b/src/bin/perfdhcp/test_control.h index 8caf4dbbf3..342854ee42 100644 --- a/src/bin/perfdhcp/test_control.h +++ b/src/bin/perfdhcp/test_control.h @@ -15,6 +15,7 @@ #include <dhcp/dhcp6.h> #include <dhcp/pkt4.h> #include <dhcp/pkt6.h> +#include <util/random/random_number_generator.h> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> @@ -281,6 +282,9 @@ protected: /// only via \ref instance method. TestControl(); + /// Generate uniformly distributed integers in range of [min, max] + isc::util::random::UniformRandomIntegerGenerator number_generator_; + /// \brief Check if test exit conditions fulfilled. /// /// Method checks if the test exit conditions are fulfilled. @@ -465,7 +469,7 @@ protected: /// is ignored). /// \throw isc::BadValue if \ref generateMacAddress throws. /// \return vector representing DUID. - std::vector<uint8_t> generateDuid(uint8_t& randomized) const; + std::vector<uint8_t> generateDuid(uint8_t& randomized); /// \brief Generate MAC address. /// @@ -481,7 +485,7 @@ protected: /// \throw isc::BadValue if MAC address template (default or specified /// from the command line) has invalid size (expected 6 octets). /// \return generated MAC address. - std::vector<uint8_t> generateMacAddress(uint8_t& randomized) const; + std::vector<uint8_t> generateMacAddress(uint8_t& randomized); /// \brief generate transaction id. /// diff --git a/src/bin/perfdhcp/tests/command_options_unittest.cc b/src/bin/perfdhcp/tests/command_options_unittest.cc index 5cdafb7551..607a395712 100644 --- a/src/bin/perfdhcp/tests/command_options_unittest.cc +++ b/src/bin/perfdhcp/tests/command_options_unittest.cc @@ -7,9 +7,10 @@ #include <config.h> #include <cstddef> +#include <fstream> +#include <gtest/gtest.h> #include <stdint.h> #include <string> -#include <gtest/gtest.h> #include <boost/date_time/posix_time/posix_time.hpp> #include <dhcp/iface_mgr.h> @@ -152,6 +153,19 @@ protected: return (CommandOptionsHelper::process(cmdline)); } + /// \brief Get full path to a file in testdata directory. + /// + /// \param filename filename being appended to absolute + /// path to testdata directory + /// + /// \return full path to a file in testdata directory. + std::string getFullPath(const std::string& filename) const { + std::ostringstream stream; + stream << TEST_DATA_DIR << "/" << filename; + return (stream.str()); + } + + /// \brief Check default initialized values /// /// Check if initialized values are correct @@ -263,6 +277,15 @@ TEST_F(CommandOptionsTest, UseFirst) { EXPECT_NO_THROW(process("perfdhcp -1 -B -l ethx all")); EXPECT_TRUE(opt.isUseFirst()); } + +TEST_F(CommandOptionsTest, UseRelayV6) { + CommandOptions& opt = CommandOptions::instance(); + EXPECT_NO_THROW(process("perfdhcp -6 -A1 -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + // -4 and -A must not coexist + EXPECT_THROW(process("perfdhcp -4 -A1 -l ethx all"), isc::InvalidParameter); +} + TEST_F(CommandOptionsTest, IpVersion) { CommandOptions& opt = CommandOptions::instance(); EXPECT_NO_THROW(process("perfdhcp -6 -l ethx -c -i all")); @@ -821,3 +844,25 @@ TEST_F(CommandOptionsTest, Server) { ASSERT_NO_THROW(process("perfdhcp -6 abc")); EXPECT_EQ("abc", opt.getServerName()); } + +TEST_F(CommandOptionsTest, LoadMacsFromFile) { + CommandOptions &opt = CommandOptions::instance(); + + std::string mac_list_full_path = getFullPath("mac-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -M " << mac_list_full_path << " abc"; + EXPECT_NO_THROW(process(cmd.str())); + EXPECT_EQ(mac_list_full_path, opt.getMacListFile()); + + const CommandOptions::MacAddrsVector& m = opt.getMacsFromFile(); + EXPECT_EQ(4, m.size()); +} + +TEST_F(CommandOptionsTest, LoadMacsFromFileNegativeCases) { + // Negative test cases + // Too many -M parameters, expected only 1 + EXPECT_THROW(process("perfdhcp -M foo -M foo1 all"), isc::InvalidParameter); + // -M option can't use with -b option + EXPECT_THROW(process("perfdhcp -M foo -b mac=1234 all"), + isc::InvalidParameter); +} diff --git a/src/bin/perfdhcp/tests/test_control_unittest.cc b/src/bin/perfdhcp/tests/test_control_unittest.cc index 6473bdbea1..0aa1d2b927 100644 --- a/src/bin/perfdhcp/tests/test_control_unittest.cc +++ b/src/bin/perfdhcp/tests/test_control_unittest.cc @@ -17,6 +17,7 @@ #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/foreach.hpp> +#include <algorithm> #include <cstddef> #include <stdint.h> #include <string> @@ -1119,6 +1120,33 @@ TEST_F(TestControlTest, GenerateDuid) { // Simulate 50 clients. Different DUID will be generated. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all")); testDuid(); + + // Checks that the random mac address returned by generateDuid + // is in the list of mac addresses in the mac-list.txt data file + std::string mac_list_full_path = getFullPath("mac-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -M " << mac_list_full_path << " abc"; + ASSERT_NO_THROW(processCmdLine(cmd.str())); + // Initialize Test Controller. + NakedTestControl tc; + uint8_t randomized = 0; + std::vector<uint8_t> generated_duid = tc.generateDuid(randomized); + + // Check that generated_duid is DUID_LL + ASSERT_EQ(10, generated_duid.size()); + DuidPtr duid(new DUID(generated_duid)); + ASSERT_EQ(duid->getType(), DUID::DUID_LL); + + // Make sure it's on the list + CommandOptions& options = CommandOptions::instance(); + const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile(); + // DUID LL comprises 2 bytes of duid type, 2 bytes of hardware type, + // then 6 bytes of HW address. + vector<uint8_t> mac(6); + std::copy(generated_duid.begin() + 4, generated_duid.begin() + 10, + mac.begin()); + // Check that mac is in macs. + ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end()); } TEST_F(TestControlTest, MisMatchVerionServer) { @@ -1142,6 +1170,24 @@ TEST_F(TestControlTest, GenerateMacAddress) { // Simulate 50 clients. Different MAC addresses will be generated. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all")); testMacAddress(); + + // Checks that the random mac address returned by generateMacAddress + // is in the list of mac addresses in the mac-list.txt data file + std::string mac_list_full_path = getFullPath("mac-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -M " << mac_list_full_path << " abc"; + ASSERT_NO_THROW(processCmdLine(cmd.str())); + // Initialize Test Controller. + NakedTestControl tc; + uint8_t randomized = 0; + // Generate MAC adddress and sanity check its size. + std::vector<uint8_t> mac = tc.generateMacAddress(randomized); + ASSERT_EQ(6, mac.size()); + // Make sure that the generated MAC address belongs to the MAC addresses + // read from a file. + CommandOptions& options = CommandOptions::instance(); + const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile(); + ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end()); } TEST_F(TestControlTest, Options4) { @@ -1362,6 +1408,45 @@ TEST_F(TestControlTest, Packet6) { EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); EXPECT_EQ(sock.addr_, pkt6->getLocalAddr()); EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); + // Packet must not be relayed. + EXPECT_TRUE(pkt6->relay_info_.empty()); + + } else { + std::cout << "Unable to find the loopback interface. Skip test. " + << std::endl; + } +} + +TEST_F(TestControlTest, Packet6Relayed) { + // Use Interface Manager to get the local loopback interface. + // If the interface can't be found we don't want to fail test. + std::string loopback_iface(getLocalLoopback()); + if (!loopback_iface.empty()) { + ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface + + " -A1 -L 10547 servers")); + NakedTestControl tc; + int sock_handle = 0; + // Create the socket. It will be needed to set packet's + // parameters. + ASSERT_NO_THROW(sock_handle = tc.openSocket()); + TestControl::TestControlSocket sock(sock_handle); + uint32_t transid = 123; + boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + // Set packet's parameters. + ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6)); + // Validate if parameters have been set correctly. + EXPECT_EQ(loopback_iface, pkt6->getIface()); + EXPECT_EQ(sock.ifindex_, pkt6->getIndex()); + EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort()); + EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); + EXPECT_EQ(sock.addr_, pkt6->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); + // Packet should be relayed. + EXPECT_EQ(pkt6->relay_info_.size(), 1); + EXPECT_EQ(pkt6->relay_info_[0].hop_count_, 1); + EXPECT_EQ(pkt6->relay_info_[0].msg_type_, DHCPV6_RELAY_FORW); + EXPECT_EQ(pkt6->relay_info_[0].linkaddr_, sock.addr_); + EXPECT_EQ(pkt6->relay_info_[0].peeraddr_, sock.addr_); } else { std::cout << "Unable to find the loopback interface. Skip test. " << std::endl; diff --git a/src/bin/perfdhcp/tests/testdata/Makefile.am b/src/bin/perfdhcp/tests/testdata/Makefile.am index 2de16431c0..30c3329de6 100644 --- a/src/bin/perfdhcp/tests/testdata/Makefile.am +++ b/src/bin/perfdhcp/tests/testdata/Makefile.am @@ -2,3 +2,4 @@ SUBDIRS = . EXTRA_DIST = discover-example.hex request4-example.hex EXTRA_DIST += solicit-example.hex request6-example.hex +EXTRA_DIST += mac-list.txt diff --git a/src/bin/perfdhcp/tests/testdata/mac-list.txt b/src/bin/perfdhcp/tests/testdata/mac-list.txt new file mode 100644 index 0000000000..e9e30e0af4 --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/mac-list.txt @@ -0,0 +1,4 @@ +11:22:33:44:55:66 +11:22:33:44:55:77 +11:22:33:44:55:88 +11:22:33:44:55:99 |