From: Marcin Siodelski Date: Wed, 31 Aug 2016 09:12:22 +0000 (+0200) Subject: [github22] Squashed changes from pallotron/perfdhcp_random_mac_from_list. X-Git-Tag: trac5004_base~1^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=277322dc7b6852478185e905ada1ac82eb6b18a0;p=thirdparty%2Fkea.git [github22] Squashed changes from pallotron/perfdhcp_random_mac_from_list. This change includes MAC address lists for perfdhcp as well as a command line option for generating relayed traffic in DHCPv6. This patch was contributed by Angelo Failla. --- diff --git a/configure.ac b/configure.ac index 1117c5b0e4..515dd27c92 100644 --- a/configure.ac +++ b/configure.ac @@ -1094,12 +1094,12 @@ elif test "${log4cplus_path}" != "yes" ; then 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 diff --git a/src/bin/perfdhcp/command_options.cc b/src/bin/perfdhcp/command_options.cc index 4c8405117c..330f5e7a0a 100644 --- a/src/bin/perfdhcp/command_options.cc +++ b/src/bin/perfdhcp/command_options.cc @@ -20,6 +20,7 @@ #include #include #include +#include using namespace std; @@ -117,6 +118,8 @@ CommandOptions::reset() { 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; @@ -133,6 +136,7 @@ CommandOptions::reset() { broadcast_ = false; rapid_commit_ = false; use_first_ = false; + use_relayed_v6_ = false; template_file_.clear(); rnd_offset_.clear(); xid_offset_.clear(); @@ -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(opt); if (optarg) { @@ -219,6 +224,19 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { 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 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; @@ -340,6 +358,13 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { boost::lexical_cast(std::numeric_limits::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 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 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_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 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 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 must be set to " "use -I"); - + 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_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; } @@ -910,15 +972,16 @@ CommandOptions::printCommandLine() const { void CommandOptions::usage() const { std::cout << - "perfdhcp [-hv] [-4|-6] [-e] [-r] [-f]\n" + "perfdhcp [-hv] [-4|-6] [-A] [-e]" + " [-r] [-f]\n" " [-F] [-t] [-R] [-b]\n" " [-n] [-p] [-d]\n" " [-D] [-l] [-P]\n" " [-a] [-L] [-s] [-i] [-B]\n" - " [-c] [-1] [-T] [-X]\n" - " [-O] [-S]\n" - " [-I] [-x] [-w]\n" - " [server]\n" + " [-c] [-1] [-M] [-T]\n" + " [-X] [-O]\n" + " [-S] [-I] [-x]\n" + " [-w] [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,10 @@ CommandOptions::usage() const { " via which exchanges are initiated.\n" "-L: Specify the local port to use\n" " (the value 0 means to use the default).\n" + "-M: 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: Offset of the last octet to randomize in the template.\n" "-P: Initiate first exchanges back to back at startup.\n" "-r: Initiate DORA/SARR (or if -i is given, DO/SA)\n" @@ -1018,6 +1085,8 @@ CommandOptions::usage() const { " the exchange rate (given by -r). Furthermore the sum of\n" " this value and the renew-rate (given by -f: When acting in DHCPv6 mode, send out relay packets.\n" + " specifies how many relays forwarded this message\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..6c09c9a128 100644 --- a/src/bin/perfdhcp/command_options.h +++ b/src/bin/perfdhcp/command_options.h @@ -269,11 +269,29 @@ 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 use_relayed_v6_; } + /// \brief Returns template file names. /// /// \return template file names. std::vector 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 + /// + /// \return mac_list_ vector of vectors. + const std::vector >& getAllMacs() const { return mac_list_; } + /// brief Returns template offsets for xid. /// /// \return template offsets for xid. @@ -427,7 +445,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. /// @@ -454,6 +472,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 +554,11 @@ private: /// that are used for initiating exchanges. Template packets /// read from files are later tuned with variable data. std::vector 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 > 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 +582,8 @@ private: 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 diff --git a/src/bin/perfdhcp/perfdhcp.xml b/src/bin/perfdhcp/perfdhcp.xml index cdc3a724dd..eba9a49463 100644 --- a/src/bin/perfdhcp/perfdhcp.xml +++ b/src/bin/perfdhcp/perfdhcp.xml @@ -37,6 +37,7 @@ perfdhcp + @@ -235,6 +236,16 @@ + + + + + When acting as a DHCPv6 behave like a relay Agent. + Send out packets as if they were relayed from an agent. + + + + diff --git a/src/bin/perfdhcp/test_control.cc b/src/bin/perfdhcp/test_control.cc index bcb28f303a..dc4882c8c5 100644 --- a/src/bin/perfdhcp/test_control.cc +++ b/src/bin/perfdhcp/test_control.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -79,8 +80,9 @@ TestControl::instance() { return (test_control); } -TestControl::TestControl() { - reset(); +TestControl::TestControl() + : number_generator_(0, CommandOptions::instance().getAllMacs().size()) { + reset(); } void @@ -464,38 +466,51 @@ TestControl::factoryRequestList4(Option::Universe u, } std::vector -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 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::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 > 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 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::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 -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 duid(options.getDuidTemplate()); - // @todo: add support for DUIDs of different sizes. std::vector 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 > 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 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 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 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 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 #include #include +#include #include #include @@ -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 generateDuid(uint8_t& randomized) const; + std::vector 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 generateMacAddress(uint8_t& randomized) const; + std::vector 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..b2398bbbe9 100644 --- a/src/bin/perfdhcp/tests/command_options_unittest.cc +++ b/src/bin/perfdhcp/tests/command_options_unittest.cc @@ -7,9 +7,10 @@ #include #include +#include +#include #include #include -#include #include #include @@ -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()); + + std::vector > 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); +} diff --git a/src/bin/perfdhcp/tests/test_control_unittest.cc b/src/bin/perfdhcp/tests/test_control_unittest.cc index 6473bdbea1..24b492bf0a 100644 --- a/src/bin/perfdhcp/tests/test_control_unittest.cc +++ b/src/bin/perfdhcp/tests/test_control_unittest.cc @@ -1119,6 +1119,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 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 > macs = options.getAllMacs(); + // duid_ll is made of 2 bytes of duid type, 2 bytes of hardwaretype, + // then 6 bytes of mac + vector 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 +1169,21 @@ 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; + std::vector mac = tc.generateMacAddress(randomized); + CommandOptions& options = CommandOptions::instance(); + vector > macs = options.getAllMacs(); + // check that mac is in macs + ASSERT_NE(std::find(macs.begin(), macs.end(), mac), macs.end()); } TEST_F(TestControlTest, Options4) { @@ -1368,6 +1410,42 @@ TEST_F(TestControlTest, Packet6) { } } +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(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 diff --git a/src/bin/perfdhcp/tests/testdata/Makefile.am b/src/bin/perfdhcp/tests/testdata/Makefile.am index 2de16431c0..f9285b114e 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