return opt;
}
-const std::vector<uint8_t>&
-TestControl::generateMacAddress() {
+std::vector<uint8_t>
+TestControl::generateMacAddress() const {
CommandOptions& options = CommandOptions::instance();
uint32_t clients_num = options.getClientsNum();
if ((clients_num == 0) || (clients_num == 1)) {
- return last_mac_address_;
+ return options.getMacPrefix();
}
- for (std::vector<uint8_t>::iterator it = last_mac_address_.end() - 1;
- it >= last_mac_address_.begin();
+ std::vector<uint8_t> mac_addr(options.getMacPrefix());
+ uint32_t r = random();
+ r %= clients_num + 1;
+ for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
+ it >= mac_addr.begin();
--it) {
- if (++(*it) > 0) {
+ (*it) += r;
+ if (r < 256) {
break;
}
+ r >>= 8;
}
- return last_mac_address_;
+ return mac_addr;
}
uint64_t
uint64_t due_exchanges = 0;
// Get current time.
ptime now(microsec_clock::universal_time());
- // The due time indicates when we should start sening next chunk
+ // The due time indicates when we should start sending next chunk
// of packets. If it is already due time, we should calculate
// how many packets to send.
if (now >= send_due_) {
}
}
-void
-TestControl::resetMacAddress() {
- CommandOptions& options = CommandOptions::instance();
- std::vector<uint8_t> 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;
}
registerOptionFactories();
TestControlSocket socket(openSocket());
- resetMacAddress();
uint64_t packets_sent = 0;
for (;;) {
updateSendDue();
std::vector<uint8_t> mac_address = generateMacAddress();
boost::shared_ptr<Pkt4> 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;
- }
+ pkt4->pack();
+ IfaceMgr::instance().send(pkt4);
}
void
/// \brief Test Control class.
///
-/// This class is responsible for running whole perfdhcp test.
+/// This class is responsible for executing DHCP performance
+/// test end to end.
///
class TestControl : public boost::noncopyable {
public:
+ /// \brief Socket wrapper class.
+ ///
+ /// This is wrapper class that holds descriptor of the socket
+ /// used to run DHCP test. All sockets created with \ref IfaceMgr
+ /// are closed in the destructor. This ensures that socket is
+ /// closed when the function that created the socket ends
+ /// (normally or when exception occurs).
class TestControlSocket {
public:
+ /// \brief Constructor of socket wrapper class.
+ ///
+ /// This constructor uses provided socket descriptor to
+ /// find the name of the interface where socket has been
+ /// bound to.
+ ///
+ /// \param socket socket descriptor.
+ /// \throw isc::BadValue if interface for specified
+ /// socket descriptor does not exist.
TestControlSocket(const int socket);
+
+ /// \brief Destriuctor of the socket wrapper class.
+ ///
+ /// Destructor closes all open sockets on all interfaces.
+ /// TODO: close only the socket being wrapped by this class.
~TestControlSocket();
+ /// \brief Return name of the interface where socket is bound to.
+ ///
+ /// \return name of the interface where socket is bound to.
const std::string& getIface() const { return(iface_); }
private:
+ /// \brief Private default constructor.
+ ///
+ /// Default constructor is private to make sure that valid
+ /// socket descriptor is passed to create object.
+ TestControlSocket();
+
+ /// \brief Initialize name of the interface.
+ ///
+ /// This method intializes the name of the interface where
+ /// socket is bound to. This name can be later retreived by
+ /// client class to set interface name in DHCP packet objects.
+ ///
+ /// \throw isc::BadValue if interface for specified socket
+ /// descriptor does not exist.
void initInterface();
- int socket_;
- std::string iface_;
+ int socket_; ///< Socket descirptor.
+ std::string iface_; ///< Name of the interface.
};
+ /// \brief Length of the Ethernet HW address (MAC) in bytes.
static const uint8_t HW_ETHER_LEN = 6;
/// TestControl is a singleton class. This method returns reference
/// \return true if any of the exit conditions is fulfiled.
bool checkExitConditions() const;
+ /// \brief Create DHCPv4 DISCOVER packet.
+ ///
+ /// Create instance of DHCPv4 DISCOVER packet with ethernet
+ /// HW type and MAC address specified as parameter. The following
+ /// DHCP options are added to the packet:
+ /// - DHO_DHCP_MESSAGE_TYPE with DHCPDISCOVER message type value
+ /// - DHO_DHCP_PARAMETER_REQUEST_LIST with the following options
+ /// being requested from the server:
+ /// - DHO_SUBNET_MASK,
+ /// - DHO_BROADCAST_ADDRESS,
+ /// - DHO_TIME_OFFSET,
+ /// - DHO_ROUTERS,
+ /// - DHO_DOMAIN_NAME,
+ /// - DHO_DOMAIN_NAME_SERVERS,
+ /// - DHO_HOST_NAME.
+ ///
+ /// \param mac_addr MAC address to be set for the packet. MAC address
+ /// has to be exactly 6 octets long.
+ /// \throw isc::Unexpected if failed to create new packet instance.
+ /// \throw isc::BadValue if MAC address has invalid length.
+ /// \return insance of the DHCPv4 DISCOVER packet.
boost::shared_ptr<dhcp::Pkt4>
createDiscoverPkt4(const std::vector<uint8_t>& mac_addr) const;
+ /// \brief Factory function to create generic option.
+ ///
+ /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister.
+ /// Registered factory functions provide a way to create options of the
+ /// same type in the same way. When new option instance is needed the
+ /// corresponding factory function is called to create it. This is done
+ /// by calling \ref Option::factory with DHCP message type specified as
+ /// one of parameters. Some of the parameters passed to factory function
+ /// may be ignored (e.g. option buffer). For generic option however, factory
+ /// function creates option using contents of the buffer.
+ ///
+ /// \param u universe (V6 or V4).
+ /// \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 factoryRequestList4(dhcp::Option::Universe u,
+ /// \brief Factory function to create DHCPv4 Request List option.
+ ///
+ /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister.
+ /// Registered factory functions provide a way to create options of the
+ /// same type in the same way. When new option instance is needed the
+ /// corresponding factory function is called to create it. This is done
+ /// by calling \ref Option::factory with DHCP message type specified as
+ /// one of parameters. This factory function ignores contents of the
+ /// buffer provided and creates option buffer internally with the following
+ /// list of requested options:
+ /// - DHO_SUBNET_MASK,
+ /// - DHO_BROADCAST_ADDRESS,
+ /// - DHO_TIME_OFFSET,
+ /// - DHO_ROUTERS,
+ /// - DHO_DOMAIN_NAME,
+ /// - DHO_DOMAIN_NAME_SERVERS,
+ /// - DHO_HOST_NAME.
+ ///
+ /// \param u universe (V6 or V4).
+ /// \param type option-type.
+ /// \param buf option-buffer.
+ /// \return instance o the generic option.
+ static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& buf);
- const std::vector<uint8_t>& generateMacAddress();
+ /// \brief Generate MAC address.
+ ///
+ /// This method generates MAC address. The number of unique
+ /// MAC addresses it can generate is determined by the number
+ /// simulated DHCP clients specified from command line. It uses
+ /// \ref CommandOptions object to retrieve number of clients.
+ /// Based on this the random value is generated and added to
+ /// the MAC address prefix (default MAC address).
+ ///
+ /// \return generated MAC address.
+ std::vector<uint8_t> generateMacAddress() const;
/// \brief Returns number of exchanges to be started.
///
/// \return number of exchanges to be started immediatelly.
uint64_t getNextExchangesNum() const;
+ /// \brief Open socket to communicate with DHCP server.
+ ///
+ /// Method opens socket and binds it to local address. Function will
+ /// can use either interface name, local address or server address
+ /// 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.
+ ///
+ /// \throw isc::BadValue if socket can't be created.
+ /// \return socket descriptor.
int openSocket() const;
+ /// \brief Register option factory functions for DHCPv4
+ ///
+ /// Method registers option factory functions for DHCPv4.
+ /// These functions are called to create instances of DHCPv4
+ /// options. Call \ref Option::factory to invoke factory
+ /// function for particular option. Don't use this function directly.
+ /// Use \ref registerOptionFactories instead.
void registerOptionFactories4() const;
+ /// \brief Register option factory functions for DHCPv6
+ ///
+ /// Method registers option factory functions for DHCPv6.
+ /// These functions are called to create instances of DHCPv6
+ /// options. Call \ref Option::factory to invoke factory
+ /// function for particular option. Don't use this function directly.
+ /// Use \ref registerOptionFactories instead.
void registerOptionFactories6() const;
- void registerOptionFactories() const;
-
- void resetMacAddress();
+ /// \brief Register option factory functions for DHCPv4 or DHCPv6.
+ ///
+ /// Method registers option factory functions for DHCPv4 or DHCPv6,
+ /// depending in whch mode test is currently running.
+ void registerOptionFactories() const;
/// \brief Start new exchange of DHCP messages.
///
+ /// Method starts new DHCP exchange by sending new DHCPv4 DISCOVER
+ /// or DHCPv6 SOLICIT packet to the server.
+ ///
+ /// \param socket socket used to send DHCP message.
+ /// \throw isc::Unexpected if failed to create or send packet
void startExchange(const TestControlSocket& socket);
/// \brief Update due time to initiate next chunk of exchanges.
boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange
/// was initiated.
- std::vector<uint8_t> last_mac_address_;/// Least generated MAC address.
-
uint64_t sent_packets_0_;
uint64_t sent_packets_1_;
};