BIND 10 trac1959, updated. ce6188b38f1b684459bc645a13b951453c526108 [1959] Added multicast option on the socket if remote addr is multicast.
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Aug 9 07:18:52 UTC 2012
The branch, trac1959 has been updated
via ce6188b38f1b684459bc645a13b951453c526108 (commit)
via 967e3ec6188b8a41e7f830bd13deda30afe5fa44 (commit)
via 25ae3625bc6da890c449bdca3d6b6f27a1fff0a2 (commit)
from 8bbc241df84bd1612644de8a8ff7d727a86ae485 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ce6188b38f1b684459bc645a13b951453c526108
Author: Marcin Siodelski <marcin at isc.org>
Date: Wed Aug 8 20:04:20 2012 +0200
[1959] Added multicast option on the socket if remote addr is multicast.
commit 967e3ec6188b8a41e7f830bd13deda30afe5fa44
Author: Marcin Siodelski <marcin at isc.org>
Date: Wed Aug 8 20:03:13 2012 +0200
[1959] Added generation of DUID prefix if it is not given by user.
commit 25ae3625bc6da890c449bdca3d6b6f27a1fff0a2
Author: Marcin Siodelski <marcin at isc.org>
Date: Tue Aug 7 20:10:47 2012 +0200
[1959] Enabled Solicit packets creation and send.
-----------------------------------------------------------------------
Summary of changes:
tests/tools/perfdhcp/command_options.cc | 38 ++++
tests/tools/perfdhcp/command_options.h | 6 +
tests/tools/perfdhcp/test_control.cc | 185 ++++++++++++++++++--
tests/tools/perfdhcp/test_control.h | 49 +++++-
.../perfdhcp/tests/command_options_unittest.cc | 16 +-
5 files changed, 271 insertions(+), 23 deletions(-)
-----------------------------------------------------------------------
diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc
index 55380d0..210ed04 100644
--- a/tests/tools/perfdhcp/command_options.cc
+++ b/tests/tools/perfdhcp/command_options.cc
@@ -20,8 +20,10 @@
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
#include <exceptions/exceptions.h>
+#include <dhcp/dhcp6.h>
#include <dhcp/iface_mgr.h>
#include "command_options.h"
@@ -367,6 +369,12 @@ CommandOptions::initialize(int argc, char** argv) {
isc_throw(InvalidParameter,
"without an inteface server is required");
}
+
+ // If DUID is not specified from command line we need to
+ // generate one.
+ if (duid_prefix_.size() == 0) {
+ generateDuidPrefix();
+ }
}
void
@@ -476,6 +484,36 @@ CommandOptions::decodeDuid(const std::string& base) {
}
}
+void
+CommandOptions::generateDuidPrefix() {
+ using namespace boost::posix_time;
+ // Duid prefix will be most likely generated only once but
+ // it is ok if it is called more then once so we simply
+ // regenerate it and discard previous value.
+ duid_prefix_.clear();
+ const uint8_t duid_prefix_len = 14;
+ duid_prefix_.resize(duid_prefix_len);
+ // The first four octets consist of DUID LLT and hardware type.
+ duid_prefix_[0] = DUID_LLT >> 8;
+ duid_prefix_[1] = DUID_LLT & 0xff;
+ duid_prefix_[2] = HWTYPE_ETHERNET >> 8;
+ duid_prefix_[3] = HWTYPE_ETHERNET & 0xff;
+
+ // As described in RFC3315: 'the time value is the time
+ // that the DUID is generated represented in seconds
+ // since midnight (UTC), January 1, 2000, modulo 2^32.'
+ ptime now = microsec_clock::universal_time();
+ ptime duid_epoch(from_iso_string("20000101T000000"));
+ time_period period(duid_epoch, now);
+ uint32_t duration_sec = htonl(period.length().total_seconds());
+ memcpy(&duid_prefix_[4], &duration_sec, 4);
+
+ // Set link layer address (6 octets). This value may be
+ // randomized before sending a packet to simulate different
+ // clients.
+ memcpy(&duid_prefix_[8], &mac_prefix_[0], 6);
+}
+
uint8_t
CommandOptions::convertHexString(const std::string& text) const {
unsigned int ui = 0;
diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h
index 459efa5..b75c438 100644
--- a/tests/tools/perfdhcp/command_options.h
+++ b/tests/tools/perfdhcp/command_options.h
@@ -346,6 +346,12 @@ private:
/// \param base Base string given as -b duid=0F1234
/// \throws isc::InvalidParameter if DUID is invalid
void decodeDuid(const std::string& base);
+
+ /// \brief Generates DUID-LLT (based on link layer address).
+ ///
+ /// Function generates DUID based on link layer address and
+ /// initiates duid_prefix_ value with it.
+ void generateDuidPrefix();
/// \brief Converts two-digit hexadecimal string to a byte
///
diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc
index ffa4d3e..ed9018e 100644
--- a/tests/tools/perfdhcp/test_control.cc
+++ b/tests/tools/perfdhcp/test_control.cc
@@ -62,6 +62,7 @@ TestControl::TestControlSocket::initSocketData() {
++s) {
if (s->sockfd_ == socket_) {
iface_ = it->getName();
+ ifindex_ = it->getIndex();
addr_ = s->addr_;
return;
}
@@ -96,14 +97,51 @@ TestControl::checkExitConditions() const {
}
OptionPtr
-TestControl::factoryGeneric4(Option::Universe u,
- uint16_t type,
- const OptionBuffer& buf) {
+TestControl::factoryElapsedTimeSolicit6(Option::Universe, uint16_t,
+ const OptionBuffer&) {
+ return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
+ OptionBuffer(2, 0)));
+}
+
+OptionPtr
+TestControl::factoryGeneric(Option::Universe u, uint16_t type,
+ const OptionBuffer& buf) {
OptionPtr opt(new Option(u, type, buf));
return opt;
}
OptionPtr
+TestControl::factoryIana6(Option::Universe, uint16_t,
+ const OptionBuffer&) {
+ const uint8_t buf_array[] = {
+ 0, 0, 0, 1, // IAID = 1
+ 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600
+ 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
+ };
+ OptionBuffer buf(buf_array, buf_array + sizeof(buf_array));
+ return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf));
+}
+
+OptionPtr
+TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
+ const OptionBuffer&) {
+ return OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer()));
+}
+
+OptionPtr
+TestControl::factoryOptionRequestOption6(Option::Universe,
+ uint16_t,
+ const OptionBuffer&) {
+ const uint8_t buf_array[] = {
+ D6O_NAME_SERVERS,
+ D6O_DOMAIN_SEARCH
+ };
+ OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
+ return OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options));
+}
+
+
+OptionPtr
TestControl::factoryRequestList4(Option::Universe u,
uint16_t type,
const OptionBuffer& buf) {
@@ -123,6 +161,8 @@ TestControl::factoryRequestList4(Option::Universe u,
return opt;
}
+
+
std::vector<uint8_t>
TestControl::generateMacAddress() const {
CommandOptions& options = CommandOptions::instance();
@@ -160,6 +200,18 @@ TestControl::generateMacAddress() const {
return mac_addr;
}
+std::vector<uint8_t>
+TestControl::generateDuid() const {
+ CommandOptions& options = CommandOptions::instance();
+ uint32_t clients_num = options.getClientsNum();
+ if ((clients_num == 0) || (clients_num == 1)) {
+ return options.getDuidPrefix();
+ }
+ // Get the base MAC address. We are going to randomize part of it.
+ std::vector<uint8_t> duid(options.getDuidPrefix());
+ return duid;
+}
+
uint64_t
TestControl::getNextExchangesNum() const {
CommandOptions& options = CommandOptions::instance();
@@ -216,6 +268,7 @@ TestControl::openSocket() const {
uint8_t family = AF_INET;
uint16_t port = 67;
int sock = 0;
+ IOAddress remoteaddr(servername);
if (options.getIpVersion() == 6) {
family = AF_INET6;
port = 547;
@@ -238,7 +291,6 @@ TestControl::openSocket() const {
} else if (!servername.empty()) {
// If only server name is given we will need to try to resolve
// the local address to bind socket to based on remote address.
- IOAddress remoteaddr(servername);
sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr,
port);
}
@@ -258,8 +310,34 @@ TestControl::openSocket() const {
isc_throw(InvalidOperation,
"unable to set broadcast option on the socket");
}
+ } else if (options.getIpVersion() == 6) {
+ // If remote address is multicast we need to enable it on
+ // the socket that has been created.
+ asio::ip::address_v6 remote_v6 = remoteaddr.getAddress().to_v6();
+ if (remote_v6.is_multicast()) {
+ int hops = 1;
+ int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &hops, sizeof(hops));
+ // If user specified interface name with '-l' the
+ // IPV6_MULTICAST_IF has to be set.
+ if ((ret >= 0) && options.isInterface()) {
+ IfaceMgr::Iface* iface =
+ IfaceMgr::instance().getIface(options.getLocalName());
+ if (iface == NULL) {
+ isc_throw(Unexpected, "unknown interface "
+ << options.getLocalName());
+ }
+ int idx = iface->getIndex();
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ &idx, sizeof(idx));
+ }
+ if (ret < 0) {
+ isc_throw(InvalidOperation,
+ "unable to enable multicast on socket " << sock
+ << ". errno = " << errno);
+ }
+ }
}
-
return(sock);
}
@@ -268,14 +346,23 @@ TestControl::receivePackets() {
int timeout = 0;
bool receiving = true;
while (receiving) {
- Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout);
- if (!pkt4) {
- receiving = false;
- } else {
- // TODO: replace this with use of StatsMgr to increase
- // number of received packets. This can be done once
- // the 1958 ticket is reviewed and checked-in.
- std::cout << "Received packet" << std::endl;
+ if (CommandOptions::instance().getIpVersion() == 4) {
+ Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout);
+ if (!pkt4) {
+ receiving = false;
+ } else {
+ // TODO: replace this with use of StatsMgr to increase
+ // number of received packets. This can be done once
+ // the 1958 ticket is reviewed and checked-in.
+ std::cout << "Received packet" << std::endl;
+ }
+ } else if (CommandOptions::instance().getIpVersion() == 6) {
+ Pkt6Ptr pkt6 = IfaceMgr::instance().receive6();
+ if (!pkt6) {
+ receiving = false;
+ } else {
+ std::cout << "Received DHCPv6 packet" << std::endl;
+ }
}
}
}
@@ -287,7 +374,7 @@ TestControl::registerOptionFactories4() const {
// DHCP_MESSAGE_TYPE option factory.
LibDHCP::OptionFactoryRegister(Option::V4,
DHO_DHCP_MESSAGE_TYPE,
- &TestControl::factoryGeneric4);
+ &TestControl::factoryGeneric);
// DHCP_PARAMETER_REQUEST_LIST option factory.
LibDHCP::OptionFactoryRegister(Option::V4,
DHO_DHCP_PARAMETER_REQUEST_LIST,
@@ -300,7 +387,24 @@ void
TestControl::registerOptionFactories6() const {
static bool factories_registered = false;
if (!factories_registered) {
- // This is a placeholder for v6 factories.
+ LibDHCP::OptionFactoryRegister(Option::V6,
+ D6O_ELAPSED_TIME,
+ &TestControl::factoryElapsedTimeSolicit6);
+ LibDHCP::OptionFactoryRegister(Option::V6,
+ D6O_RAPID_COMMIT,
+ &TestControl::factoryRapidCommit6);
+ LibDHCP::OptionFactoryRegister(Option::V6,
+ D6O_ORO,
+ &TestControl::factoryOptionRequestOption6);
+ LibDHCP::OptionFactoryRegister(Option::V6,
+ D6O_CLIENTID,
+ &TestControl::factoryGeneric);
+
+ LibDHCP::OptionFactoryRegister(Option::V6,
+ D6O_IA_NA,
+ &TestControl::factoryIana6);
+
+
}
factories_registered = true;
}
@@ -347,7 +451,11 @@ TestControl::run() {
receivePackets();
for (uint64_t i = packets_due; i > 0; --i) {
- sendDiscover4(socket);
+ if (options.getIpVersion() == 4) {
+ sendDiscover4(socket);
+ } else {
+ sendSolicit6(socket);
+ }
++packets_sent;
cout << "Packets sent " << packets_sent << endl;
}
@@ -382,11 +490,38 @@ TestControl::sendDiscover4(const TestControlSocket& socket) {
}
void
-TestControl::setDefaults4(const TestControlSocket &socket,
+TestControl::sendSolicit6(const TestControlSocket& socket) {
+ ++sent_packets_0_;
+ last_sent_ = microsec_clock::universal_time();
+ // Generate the MAC address to be passed in the packet.
+ std::vector<uint8_t> mac_address = generateMacAddress();
+ // Generate DUID to be passed to the packet
+ std::vector<uint8_t> duid = generateDuid();
+ // Generate trasnaction id to be set for the new exchange.
+ const uint32_t transid = static_cast<uint32_t>(random());
+ boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
+ if (!pkt6) {
+ isc_throw(Unexpected, "failed to create SOLICIT packet");
+ }
+ pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
+ pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT));
+ pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
+ pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
+ pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
+
+ setDefaults6(socket, pkt6);
+ pkt6->pack();
+ IfaceMgr::instance().send(pkt6);
+}
+
+void
+TestControl::setDefaults4(const TestControlSocket& socket,
const boost::shared_ptr<Pkt4>& pkt) {
CommandOptions& options = CommandOptions::instance();
// Interface name.
pkt->setIface(socket.getIface());
+ // Interface index.
+ pkt->setIndex(socket.getIfIndex());
// Local client's port (68)
pkt->setLocalPort(DHCP4_CLIENT_PORT);
// Server's port (67)
@@ -400,6 +535,22 @@ TestControl::setDefaults4(const TestControlSocket &socket,
}
void
+TestControl::setDefaults6(const TestControlSocket& socket,
+ const boost::shared_ptr<Pkt6>& pkt) {
+ CommandOptions& options = CommandOptions::instance();
+ // Interface name.
+ pkt->setIface(socket.getIface());
+ // Interface index.
+ pkt->setIndex(socket.getIfIndex());
+ // Local client's port (547)
+ pkt->setLocalPort(DHCP6_CLIENT_PORT);
+ // Server's port (548)
+ pkt->setRemotePort(DHCP6_SERVER_PORT);
+ // The remote server's name or IP.
+ pkt->setRemoteAddr(IOAddress(options.getServerName()));
+}
+
+void
TestControl::updateSendDue() {
// If default constructor was called, this should not happen but
// if somebody has changed default constructor it is better to
diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h
index bb1f283..9670cb7 100644
--- a/tests/tools/perfdhcp/test_control.h
+++ b/tests/tools/perfdhcp/test_control.h
@@ -21,6 +21,7 @@
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <dhcp/dhcp6.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
@@ -67,6 +68,11 @@ public:
/// \return name of the interface where socket is bound to.
const std::string& getIface() const { return(iface_); }
+ /// \brief Return interface index where socket is bound to.
+ ///
+ /// \return index fo the interface where sockert is bound to.
+ int getIfIndex() const { return(ifindex_); }
+
/// \brief Return address where socket is bound to.
///
/// \return address where socket is bound to.
@@ -90,6 +96,7 @@ public:
int socket_; ///< Socket descirptor.
std::string iface_; ///< Name of the interface.
+ int ifindex_; ///< Index of the interface.
asiolink::IOAddress addr_; ///< Address bound.
};
@@ -132,6 +139,12 @@ private:
/// \return true if any of the exit conditions is fulfiled.
bool checkExitConditions() const;
+ static dhcp::OptionPtr
+ factoryElapsedTimeSolicit6(dhcp::Option::Universe u,
+ uint16_t type,
+ const dhcp::OptionBuffer& buf);
+
+
/// \brief Factory function to create generic option.
///
/// Factory function is registered using \ref LibDHCP::OptionFactoryRegister.
@@ -147,9 +160,23 @@ private:
/// \param type option-type.
/// \param buf option-buffer.
/// \return instance o the generic option.
- static dhcp::OptionPtr factoryGeneric4(dhcp::Option::Universe u,
- uint16_t type,
- const dhcp::OptionBuffer& buf);
+ static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u,
+ uint16_t type,
+ const dhcp::OptionBuffer& buf);
+
+ static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u,
+ uint16_t type,
+ const dhcp::OptionBuffer& buf);
+
+ static dhcp::OptionPtr
+ factoryOptionRequestOption6(dhcp::Option::Universe u,
+ uint16_t type,
+ const dhcp::OptionBuffer& buf);
+
+ static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u,
+ uint16_t type,
+ const dhcp::OptionBuffer& buf);
+
/// \brief Factory function to create DHCPv4 Request List option.
///
@@ -177,6 +204,8 @@ private:
uint16_t type,
const dhcp::OptionBuffer& buf);
+ std::vector<uint8_t> generateDuid() const;
+
/// \brief Generate MAC address.
///
/// This method generates MAC address. The number of unique
@@ -208,11 +237,16 @@ private:
/// to create a socket, depending on what is available (specified
/// from the command line). If socket can't be created for any
/// reason, exception is thrown.
+ /// If destination address is broadcast (for DHCPv4) or multicast
+ /// (for DHCPv6) than broadcast or multicast option is set on
+ /// the socket.
///
/// \throw isc::BadValue if socket can't be created for given
/// interface, local address or remote address.
/// \throw isc::InvalidOperation if broadcast option can't be
- /// set for the socket.
+ /// set for the v4 socket or if multicast option cat't be set
+ /// for the v6 socket.
+ /// \throw isc::Unexpected if interal unexpected error occured.
/// \return socket descriptor.
int openSocket() const;
@@ -256,7 +290,9 @@ private:
/// \param socket socket to be used to send the message.
/// \throw isc::Unexpected if failed to create new packet instance.
/// \throw isc::BadValue if MAC address has invalid length.
- void sendDiscover4(const TestControlSocket &socket);
+ void sendDiscover4(const TestControlSocket& socket);
+
+ void sendSolicit6(const TestControlSocket& socket);
/// \brief Set default DHCPv4 packet data.
///
@@ -273,6 +309,9 @@ private:
void setDefaults4(const TestControlSocket& socket,
const boost::shared_ptr<dhcp::Pkt4>& pkt);
+ void setDefaults6(const TestControlSocket& socket,
+ const boost::shared_ptr<dhcp::Pkt6>& pkt);
+
/// \brief Update due time to initiate next chunk of exchanges.
///
/// Method updates due time to initiate next chunk of exchanges.
diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc
index 669d792..e3e3384 100644
--- a/tests/tools/perfdhcp/tests/command_options_unittest.cc
+++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc
@@ -71,11 +71,25 @@ protected:
EXPECT_EQ(0, opt.getClientsNum());
// default mac
- uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 };
+ const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 };
std::vector<uint8_t> v1 = opt.getMacPrefix();
ASSERT_EQ(6, v1.size());
EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
+ // Check if DUID is initialized. The DUID-LLT is expected
+ // to start with DUID_LLT value of 1 and hardware ethernet
+ // type equal to 1 (HWETHER_TYPE).
+ const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 };
+ // We assume DUID-LLT length 14. This includes 4 octets of
+ // DUID_LLT value, two octets of hardware type, 4 octets
+ // of time value and 6 octets of variable link layer (MAC)
+ // address.
+ const int duid_llt_size = 14;
+ std::vector<uint8_t> v2 = opt.getDuidPrefix();
+ ASSERT_EQ(duid_llt_size, opt.getDuidPrefix().size());
+ EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4,
+ duid_llt_and_hw));
+
EXPECT_EQ(0, opt.getBase().size());
EXPECT_EQ(0, opt.getNumRequests().size());
EXPECT_EQ(0, opt.getPeriod());
More information about the bind10-changes
mailing list