From: Marcin Siodelski Date: Fri, 3 Aug 2012 12:49:41 +0000 (+0100) Subject: [1959] Implemented DHCPDISCOVER packet sending. X-Git-Tag: trac2351_base~47^2~11^2~36 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1127bca7125f7fb94fe3340a86e086307f80a9e2;p=thirdparty%2Fkea.git [1959] Implemented DHCPDISCOVER packet sending. --- diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 8072e75461..de9aa1d727 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -19,9 +19,11 @@ #include +#include +#include #include +#include #include -#include #include "test_control.h" #include "command_options.h" @@ -30,10 +32,43 @@ using namespace boost; using namespace boost::posix_time; using namespace isc; using namespace isc::dhcp; +using namespace isc::asiolink; namespace isc { namespace perfdhcp { +TestControl::TestControlSocket::TestControlSocket(int socket) : + socket_(socket) { + initInterface(); +} + +TestControl::TestControlSocket::~TestControlSocket() { + IfaceMgr::instance().closeSockets(); +} + +void +TestControl::TestControlSocket::initInterface() { + const IfaceMgr::IfaceCollection& ifaces = + IfaceMgr::instance().getIfaces(); + for (IfaceMgr::IfaceCollection::const_iterator it = ifaces.begin(); + it != ifaces.end(); + ++it) { + const IfaceMgr::SocketCollection& socket_collection = + it->getSockets(); + for (IfaceMgr::SocketCollection::const_iterator s = + socket_collection.begin(); + s != socket_collection.end(); + ++s) { + if (s->sockfd_ == socket_) { + iface_ = it->getName(); + return; + } + } + } + isc_throw(BadValue, "interface for for specified socket " + "descriptor not found"); +} + TestControl& TestControl::instance() { static TestControl test_control; @@ -59,24 +94,37 @@ TestControl::checkExitConditions() const { } boost::shared_ptr -TestControl::createDiscoverPkt4() const { +TestControl::createDiscoverPkt4(const std::vector& mac_addr) const { const uint32_t transid = static_cast(random()); boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); if (!pkt4) { isc_throw(isc::Unexpected, "failed to create DISCOVER packet"); } - OptionPtr request_list_option = - Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST); - pkt4->addOption(request_list_option); + if (HW_ETHER_LEN != mac_addr.size()) { + isc_throw(BadValue, "invalid MAC address size"); + } + pkt4->setHWAddr(HTYPE_ETHER, HW_ETHER_LEN, mac_addr); + + OptionBuffer buf_msg_type; + buf_msg_type.push_back(DHCPDISCOVER); + pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, buf_msg_type)); + pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST)); return pkt4; } +OptionPtr +TestControl::factoryGeneric4(Option::Universe u, + uint16_t type, + const OptionBuffer& buf) { + OptionPtr opt(new Option(u, type, buf)); + return opt; +} + OptionPtr TestControl::factoryRequestList4(Option::Universe u, uint16_t type, - const OptionBuffer& buf) -{ + const OptionBuffer& buf) { const uint8_t buf_array[] = { DHO_SUBNET_MASK, DHO_BROADCAST_ADDRESS, @@ -88,9 +136,26 @@ TestControl::factoryRequestList4(Option::Universe u, }; OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); - Option* opt = new Option(u, type, buf); + OptionPtr opt(new Option(u, type, buf)); opt->setData(buf_with_options.begin(), buf_with_options.end()); - return OptionPtr(opt); + return opt; +} + +const std::vector& +TestControl::generateMacAddress() { + CommandOptions& options = CommandOptions::instance(); + uint32_t clients_num = options.getClientsNum(); + if ((clients_num == 0) || (clients_num == 1)) { + return last_mac_address_; + } + for (std::vector::iterator it = last_mac_address_.end() - 1; + it >= last_mac_address_.begin(); + --it) { + if (++(*it) > 0) { + break; + } + } + return last_mac_address_; } uint64_t @@ -141,10 +206,57 @@ TestControl::getNextExchangesNum() const { return (0); } +int +TestControl::openSocket() const { + CommandOptions& options = CommandOptions::instance(); + std::string localname = options.getLocalName(); + std::string servername = options.getServerName(); + uint8_t family = AF_INET; + uint16_t port = 67; + int sock = 0; + if (options.getIpVersion() == 6) { + family = AF_INET6; + port = 547; + } + if (!localname.empty()) { + bool is_interface = false;; + try { + sock = IfaceMgr::instance().openSocketFromIface(localname, + port, + family); + is_interface = true; + } catch (...) { + // This is not fatal error. It may be the case that + // parameter given from command line is not interface + // name but local IP address. + } + if (!is_interface) { + IOAddress localaddr(localname); + // We don't catch exception here because parameter given + // must be either interface name or local address. If + // both attempts failed, we want exception to be emited. + sock = IfaceMgr::instance().openSocketFromAddress(localaddr, + port); + } + } else if (!servername.empty()) { + IOAddress remoteaddr(servername); + sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr, + port); + } + if (sock <= 0) { + isc_throw(BadValue, "unable to open socket to communicate with " + "DHCP server"); + } + return sock; +} + void TestControl::registerOptionFactories4() const { static bool factories_registered = false; if (!factories_registered) { + LibDHCP::OptionFactoryRegister(Option::V4, + DHO_DHCP_MESSAGE_TYPE, + &TestControl::factoryGeneric4); LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST, &TestControl::factoryRequestList4); @@ -176,20 +288,32 @@ TestControl::registerOptionFactories() const { } } +void +TestControl::resetMacAddress() { + CommandOptions& options = CommandOptions::instance(); + std::vector mac_prefix(options.getMacPrefix()); + if (mac_prefix.size() != HW_ETHER_LEN) { + isc_throw(Unexpected, "MAC address prefix is invalid"); + } + std::swap(mac_prefix, last_mac_address_); +} + void TestControl::run() { sent_packets_0_ = 0; sent_packets_1_ = 0; CommandOptions& options = CommandOptions::instance(); // Ip version is not set ONLY in case the command options - // where not parsed. This surely means that parse() function + // were not parsed. This surely means that parse() function // was not called prior to starting the test. This is fatal // error. if (options.getIpVersion() == 0) { - isc_throw(InvalidOperation, "command options must be parsed before running " - "a test"); + isc_throw(InvalidOperation, + "command options must be parsed before running a test"); } registerOptionFactories(); + TestControlSocket socket(openSocket()); + resetMacAddress(); uint64_t packets_sent = 0; for (;;) { updateSendDue(); @@ -198,18 +322,26 @@ TestControl::run() { } uint64_t packets_due = getNextExchangesNum(); for (uint64_t i = packets_due; i > 0; --i) { - startExchange(); + startExchange(socket); ++packets_sent; cout << "Packets sent " << packets_sent << endl; } } - } void -TestControl::startExchange() { +TestControl::startExchange(const TestControlSocket& socket) { ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); + std::vector mac_address = generateMacAddress(); + boost::shared_ptr pkt4 = createDiscoverPkt4(mac_address); + pkt4->setIface(socket.getIface()); + try { + pkt4->pack(); + IfaceMgr::instance().send(pkt4); + } catch (const Exception& e) { + std::cout << e.what() << std::endl; + } } void diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index ce5aa4c4b6..676be013c7 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -33,6 +33,24 @@ namespace perfdhcp { /// class TestControl : public boost::noncopyable { public: + + class TestControlSocket { + public: + + TestControlSocket(const int socket); + ~TestControlSocket(); + + const std::string& getIface() const { return(iface_); } + + private: + void initInterface(); + + int socket_; + std::string iface_; + }; + + static const uint8_t HW_ETHER_LEN = 6; + /// TestControl is a singleton class. This method returns reference /// to its sole instance. /// @@ -69,12 +87,19 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; - boost::shared_ptr createDiscoverPkt4() const; + boost::shared_ptr + createDiscoverPkt4(const std::vector& mac_addr) const; + + static dhcp::OptionPtr factoryGeneric4(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); + const std::vector& generateMacAddress(); + /// \brief Returns number of exchanges to be started. /// /// Method returns number of new exchanges to be started as soon @@ -85,15 +110,19 @@ private: /// \return number of exchanges to be started immediatelly. uint64_t getNextExchangesNum() const; + int openSocket() const; + void registerOptionFactories4() const; void registerOptionFactories6() const; void registerOptionFactories() const; + void resetMacAddress(); + /// \brief Start new exchange of DHCP messages. /// - void startExchange(); + void startExchange(const TestControlSocket& socket); /// \brief Update due time to initiate next chunk of exchanges. /// @@ -107,6 +136,8 @@ private: boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange /// was initiated. + std::vector last_mac_address_;/// Least generated MAC address. + uint64_t sent_packets_0_; uint64_t sent_packets_1_; }; diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 7a66b03fb3..2cc6b93f53 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -48,7 +48,7 @@ TEST_F(TestControlTest, Run) { // The command line is to run single test iteration and exit. // We have to declare argv as const walk around the problem // of deprecated conversion from string to char*. - const char* argv[] = { "perfdhcp", "-l", "eth0", "-r", "10", "-n", "1" }; + const char* argv[] = { "perfdhcp", "-l", "127.0.0.1", "-r", "10", "-n", "1" }; const int argc = sizeof(argv) / sizeof(argv[0]); CommandOptions& options = CommandOptions::instance();