summaryrefslogtreecommitdiffstats
path: root/src/bin
diff options
context:
space:
mode:
authorMarcin Siodelski <marcin@isc.org>2016-09-01 18:03:04 +0200
committerMarcin Siodelski <marcin@isc.org>2016-09-01 18:03:04 +0200
commitc5b4a5981cf642ebb9aecb8acc07b87abdccbd91 (patch)
treecf3cfadbd73e3bb7317fad75abff4ba804c4ac70 /src/bin
parent[master] configure.ac version update (diff)
parent[github22] Updated AUTHORS file. (diff)
downloadkea-c5b4a5981cf642ebb9aecb8acc07b87abdccbd91.tar.xz
kea-c5b4a5981cf642ebb9aecb8acc07b87abdccbd91.zip
[master] Merge branch 'github22'
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/perfdhcp/command_options.cc92
-rw-r--r--src/bin/perfdhcp/command_options.h43
-rw-r--r--src/bin/perfdhcp/perfdhcp.xml33
-rw-r--r--src/bin/perfdhcp/test_control.cc150
-rw-r--r--src/bin/perfdhcp/test_control.h8
-rw-r--r--src/bin/perfdhcp/tests/command_options_unittest.cc47
-rw-r--r--src/bin/perfdhcp/tests/test_control_unittest.cc85
-rw-r--r--src/bin/perfdhcp/tests/testdata/Makefile.am1
-rw-r--r--src/bin/perfdhcp/tests/testdata/mac-list.txt4
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