LOG4CPLUS_LIBS="-L${log4cplus_path}/lib"
else
# If not specified, try some common paths.
- log4cplusdirs="/usr/local /usr/pkg /opt /opt/local"
+ log4cplusdirs="/usr /usr/local /usr/pkg /opt /opt/local"
for d in $log4cplusdirs
do
if test -f $d/include/log4cplus/logger.h; then
LOG4CPLUS_INCLUDES="-I$d/include"
- LOG4CPLUS_LIBS="-L$d/lib"
+ LOG4CPLUS_LIBS="-L$d/lib -L$d/lib64"
break
fi
done
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
+#include <fstream>
using namespace std;
mac_template_.assign(mac, mac + 6);
duid_template_.clear();
base_.clear();
+ mac_file_list_.clear();
+ mac_list_.clear();
num_request_.clear();
period_ = 0;
drop_time_set_ = 0;
broadcast_ = false;
rapid_commit_ = false;
use_first_ = false;
+ use_relayed_v6_ = false;
template_file_.clear();
rnd_offset_.clear();
xid_offset_.clear();
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) {
use_first_ = true;
break;
+ // act as a relay Agent (single char option and R/r are taken already).
+ case 'A':
+ use_relayed_v6_ = true;
+ // TODO: actually use level, at the moment we support only 1 level.
+ // See comment in https://github.com/isc-projects/kea/pull/22#issuecomment-243405600
+ int level;
+ level = positiveInteger(
+ " -A<encapusulation_levels> must be a positive integer");
+ if (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;
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_file_list_ = std::string(optarg);
+ loadMacs();
+ break;
+
case 'n':
num_req = positiveInteger("value of num-request:"
" -n<value> must be a positive integer");
// 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 {
}
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"
return ui;
}
+void CommandOptions::loadMacs() {
+ std::string line;
+ std::ifstream infile(mac_file_list_.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),
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
if (use_first_) {
std::cout << "use-first" << std::endl;
}
+ if (!mac_file_list_.empty()) {
+ std::cout << "mac-file-list=" << mac_file_list_ << std::endl;
+ }
for (size_t i = 0; i < template_file_.size(); ++i) {
std::cout << "template-file[" << i << "]=" << template_file_[i] << std::endl;
}
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_levels>] [-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"
" 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-file-list>: A text file containing a list of macs, one per line.\n"
+ " If provided a random mac will be choosen for every exchange.\n"
+ " Must not be used in conjunction with the -b parameter.\n"
+ " In the v6 case MAC addresses are used to generate DUID-LLs.\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"
" 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_levels>: When acting in DHCPv6 mode, send out relay packets.\n"
+ " <encapusulation_levels> specifies how many relays forwarded this message\n"
"\n"
"The remaining options are used only in conjunction with -r:\n"
"\n"
/// \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 use_relayed_v6_; }
+
/// \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 mac_template file name.
+ std::string getMacListFile() const { return mac_file_list_; }
+
+ /// \brief Returns the list of macs, every mac is a vector<uint8_t>
+ ///
+ /// \return mac_list_ vector of vectors.
+ const std::vector<std::vector<uint8_t> >& getAllMacs() const { return mac_list_; }
+
/// brief Returns template offsets for xid.
///
/// \return template offsets for xid.
///
/// \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>.
///
/// \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_;
/// that are used for initiating exchanges. Template packets
/// read from files are later tuned with variable data.
std::vector<std::string> template_file_;
+ /// A file containing a list of macs, one per line. This can be used if
+ /// you don't want to genrate Mac starting from a base mac but rather provide
+ /// the tool with a list of macs it should randomize on.
+ std::string mac_file_list_;
+ 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
std::string wrapped_;
/// Server name specified as last argument of command line.
std::string server_name_;
+ /// Controls whether generated dhcpv6 test traffic should be relayed.
+ bool use_relayed_v6_;
};
} // namespace perfdhcp
<command>perfdhcp</command>
<arg><option>-1</option></arg>
<arg><option>-4|-6</option></arg>
+ <arg><option>-A</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>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-A</option></term>
+ <listitem>
+ <para>
+ When acting as a DHCPv6 behave like a relay Agent.
+ Send out packets as if they were relayed from an agent.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-a <replaceable class="parameter">aggressivity</replaceable></option></term>
<listitem>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/foreach.hpp>
+#include <algorithm>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
return (test_control);
}
-TestControl::TestControl() {
- reset();
+TestControl::TestControl()
+ : number_generator_(0, CommandOptions::instance().getAllMacs().size()) {
+ reset();
}
void
}
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;
+
+ vector<vector<uint8_t> > macs = options.getAllMacs();
+ // 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
}
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);
+ vector<vector<uint8_t> > macs = options.getAllMacs();
+ // 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
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.
}
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
#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>
/// 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.
/// 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.
///
/// \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.
///
#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>
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
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"));
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());
+
+ std::vector<std::vector<uint8_t> > m = opt.getAllMacs();
+ 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);
+}
// 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
+ DuidPtr duid(new DUID(generated_duid));
+ ASSERT_EQ(duid->getType(), DUID::DUID_LL);
+ // make sure it's on the list
+ CommandOptions& options = CommandOptions::instance();
+ vector<vector<uint8_t> > macs = options.getAllMacs();
+ // duid_ll is made of 2 bytes of duid type, 2 bytes of hardwaretype,
+ // then 6 bytes of mac
+ 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) {
// 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;
+ std::vector<uint8_t> mac = tc.generateMacAddress(randomized);
+ CommandOptions& options = CommandOptions::instance();
+ vector<vector<uint8_t> > macs = options.getAllMacs();
+ // check that mac is in macs
+ ASSERT_NE(std::find(macs.begin(), macs.end(), mac), macs.end());
}
TEST_F(TestControlTest, Options4) {
}
}
+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());
+ // check relay info
+ 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;
+ }
+}
+
TEST_F(TestControlTest, Packet4Exchange) {
// Get the local loopback interface to open socket on
// it and test packets exchanges. We don't want to fail
EXTRA_DIST = discover-example.hex request4-example.hex
EXTRA_DIST += solicit-example.hex request6-example.hex
+EXTRA_DIST += mac_list.txt
--- /dev/null
+11:22:33:44:55:66
+11:22:33:44:55:77
+11:22:33:44:55:88
+11:22:33:44:55:99