test_control.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef __TEST_CONTROL_H
  15. #define __TEST_CONTROL_H
  16. #include <string>
  17. #include <vector>
  18. #include <boost/noncopyable.hpp>
  19. #include <boost/date_time/posix_time/posix_time.hpp>
  20. #include <dhcp/pkt4.h>
  21. #include <dhcp/pkt6.h>
  22. namespace isc {
  23. namespace perfdhcp {
  24. /// \brief Test Control class.
  25. ///
  26. /// This class is responsible for executing DHCP performance
  27. /// test end to end.
  28. ///
  29. class TestControl : public boost::noncopyable {
  30. public:
  31. /// \brief Socket wrapper class.
  32. ///
  33. /// This is wrapper class that holds descriptor of the socket
  34. /// used to run DHCP test. All sockets created with \ref IfaceMgr
  35. /// are closed in the destructor. This ensures that socket is
  36. /// closed when the function that created the socket ends
  37. /// (normally or when exception occurs).
  38. class TestControlSocket {
  39. public:
  40. /// \brief Constructor of socket wrapper class.
  41. ///
  42. /// This constructor uses provided socket descriptor to
  43. /// find the name of the interface where socket has been
  44. /// bound to.
  45. ///
  46. /// \param socket socket descriptor.
  47. /// \throw isc::BadValue if interface for specified
  48. /// socket descriptor does not exist.
  49. TestControlSocket(const int socket);
  50. /// \brief Destriuctor of the socket wrapper class.
  51. ///
  52. /// Destructor closes all open sockets on all interfaces.
  53. /// TODO: close only the socket being wrapped by this class.
  54. ~TestControlSocket();
  55. /// \brief Return name of the interface where socket is bound to.
  56. ///
  57. /// \return name of the interface where socket is bound to.
  58. const std::string& getIface() const { return(iface_); }
  59. /// \brief Return address where socket is bound to.
  60. ///
  61. /// \return address where socket is bound to.
  62. const asiolink::IOAddress& getAddress() const { return(addr_); }
  63. private:
  64. /// \brief Private default constructor.
  65. ///
  66. /// Default constructor is private to make sure that valid
  67. /// socket descriptor is passed to create object.
  68. TestControlSocket();
  69. /// \brief Initialize socket data.
  70. ///
  71. /// This method initializes members of the class that Interface
  72. /// Manager holds: interface name, local address.
  73. ///
  74. /// \throw isc::BadValue if interface for specified socket
  75. /// descriptor does not exist.
  76. void initSocketData();
  77. int socket_; ///< Socket descirptor.
  78. std::string iface_; ///< Name of the interface.
  79. asiolink::IOAddress addr_; ///< Address bound.
  80. };
  81. /// \brief Length of the Ethernet HW address (MAC) in bytes.
  82. static const uint8_t HW_ETHER_LEN = 6;
  83. /// TestControl is a singleton class. This method returns reference
  84. /// to its sole instance.
  85. ///
  86. /// \return the only existing instance of test control
  87. static TestControl& instance();
  88. /// Run performance test.
  89. ///
  90. /// Method runs whole performance test. Command line options must
  91. /// be parsed prior to running this function. Othewise function will
  92. /// throw exception.
  93. ///
  94. /// \throw isc::InvalidOperation if command line options are not parsed.
  95. /// \throw isc::Unexpected if internal Test Controler error occured.
  96. void run();
  97. private:
  98. /// \brief Private default constructor.
  99. ///
  100. /// Default constructor is private as the object can be created
  101. /// only via \ref instance method.
  102. TestControl();
  103. /// \brief Check if test exit condtitions fulfiled.
  104. ///
  105. /// Method checks if test exit conditions are fulfiled.
  106. /// Exit conditions are checked periodically from the
  107. /// main loop. Program should break the main loop when
  108. /// this method returns true. It is calling function
  109. /// responsibility to break main loop gracefully and
  110. /// cleanup after test execution.
  111. ///
  112. /// \return true if any of the exit conditions is fulfiled.
  113. bool checkExitConditions() const;
  114. /// \brief Factory function to create generic option.
  115. ///
  116. /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister.
  117. /// Registered factory functions provide a way to create options of the
  118. /// same type in the same way. When new option instance is needed the
  119. /// corresponding factory function is called to create it. This is done
  120. /// by calling \ref Option::factory with DHCP message type specified as
  121. /// one of parameters. Some of the parameters passed to factory function
  122. /// may be ignored (e.g. option buffer). For generic option however, factory
  123. /// function creates option using contents of the buffer.
  124. ///
  125. /// \param u universe (V6 or V4).
  126. /// \param type option-type.
  127. /// \param buf option-buffer.
  128. /// \return instance o the generic option.
  129. static dhcp::OptionPtr factoryGeneric4(dhcp::Option::Universe u,
  130. uint16_t type,
  131. const dhcp::OptionBuffer& buf);
  132. /// \brief Factory function to create DHCPv4 Request List option.
  133. ///
  134. /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister.
  135. /// Registered factory functions provide a way to create options of the
  136. /// same type in the same way. When new option instance is needed the
  137. /// corresponding factory function is called to create it. This is done
  138. /// by calling \ref Option::factory with DHCP message type specified as
  139. /// one of parameters. This factory function ignores contents of the
  140. /// buffer provided and creates option buffer internally with the following
  141. /// list of requested options:
  142. /// - DHO_SUBNET_MASK,
  143. /// - DHO_BROADCAST_ADDRESS,
  144. /// - DHO_TIME_OFFSET,
  145. /// - DHO_ROUTERS,
  146. /// - DHO_DOMAIN_NAME,
  147. /// - DHO_DOMAIN_NAME_SERVERS,
  148. /// - DHO_HOST_NAME.
  149. ///
  150. /// \param u universe (V6 or V4).
  151. /// \param type option-type.
  152. /// \param buf option-buffer.
  153. /// \return instance o the generic option.
  154. static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u,
  155. uint16_t type,
  156. const dhcp::OptionBuffer& buf);
  157. /// \brief Generate MAC address.
  158. ///
  159. /// This method generates MAC address. The number of unique
  160. /// MAC addresses it can generate is determined by the number
  161. /// simulated DHCP clients specified from command line. It uses
  162. /// \ref CommandOptions object to retrieve number of clients.
  163. /// Based on this the random value is generated and added to
  164. /// the MAC address prefix (default MAC address).
  165. ///
  166. /// \throw isc::BadValue if MAC address prefix (default or specified
  167. /// from the command line) has invalid size (expected 6 octets).
  168. /// \return generated MAC address.
  169. std::vector<uint8_t> generateMacAddress() const;
  170. /// \brief Returns number of exchanges to be started.
  171. ///
  172. /// Method returns number of new exchanges to be started as soon
  173. /// as possible to satisfy expected rate. Calculation used here
  174. /// is based on current time, due time calculated with
  175. /// \ref updateSendTime function and expected rate.
  176. ///
  177. /// \return number of exchanges to be started immediatelly.
  178. uint64_t getNextExchangesNum() const;
  179. /// \brief Open socket to communicate with DHCP server.
  180. ///
  181. /// Method opens socket and binds it to local address. Function will
  182. /// can use either interface name, local address or server address
  183. /// to create a socket, depending on what is available (specified
  184. /// from the command line). If socket can't be created for any
  185. /// reason, exception is thrown.
  186. ///
  187. /// \throw isc::BadValue if socket can't be created.
  188. /// \return socket descriptor.
  189. int openSocket() const;
  190. void receivePackets();
  191. /// \brief Register option factory functions for DHCPv4
  192. ///
  193. /// Method registers option factory functions for DHCPv4.
  194. /// These functions are called to create instances of DHCPv4
  195. /// options. Call \ref Option::factory to invoke factory
  196. /// function for particular option. Don't use this function directly.
  197. /// Use \ref registerOptionFactories instead.
  198. void registerOptionFactories4() const;
  199. /// \brief Register option factory functions for DHCPv6
  200. ///
  201. /// Method registers option factory functions for DHCPv6.
  202. /// These functions are called to create instances of DHCPv6
  203. /// options. Call \ref Option::factory to invoke factory
  204. /// function for particular option. Don't use this function directly.
  205. /// Use \ref registerOptionFactories instead.
  206. void registerOptionFactories6() const;
  207. /// \brief Register option factory functions for DHCPv4 or DHCPv6.
  208. ///
  209. /// Method registers option factory functions for DHCPv4 or DHCPv6,
  210. /// depending in whch mode test is currently running.
  211. void registerOptionFactories() const;
  212. /// \brief Send DHCPv4 DISCOVER message.
  213. ///
  214. /// Method creates and sends DHCPv4 DISCOVER message to the server
  215. /// with the following options:
  216. /// - MESSAGE_TYPE set to DHCPDISCOVER
  217. /// - PARAMETER_REQUEST_LIST with the same list of requested options
  218. /// as described in \ref factoryRequestList.
  219. /// The transaction id and MAC address are randomly generated for
  220. /// the message. Range of unique MAC addresses generated depends
  221. /// on the number of clients specified from the command line.
  222. ///
  223. /// \param socket socket to be used to send the message.
  224. /// \throw isc::Unexpected if failed to create new packet instance.
  225. /// \throw isc::BadValue if MAC address has invalid length.
  226. void sendDiscover4(const TestControlSocket &socket);
  227. /// \brief Set default DHCPv4 packet data.
  228. ///
  229. /// This method sets default data on the DHCPv4 packet:
  230. /// - interface name,
  231. /// - local port = 68 (DHCP client port),
  232. /// - remote port = 67 (DHCP server port),
  233. /// - server's address,
  234. /// - GIADDR = local address where socket is bound to,
  235. /// - hops = 1 (pretending that we are a relay)
  236. ///
  237. /// \param socket socket used to send the packet.
  238. /// \param pkt packet to be configured.
  239. void setDefaults4(const TestControlSocket& socket,
  240. const boost::shared_ptr<dhcp::Pkt4>& pkt);
  241. /// \brief Update due time to initiate next chunk of exchanges.
  242. ///
  243. /// Method updates due time to initiate next chunk of exchanges.
  244. /// Function takes current time, last sent packet's time and
  245. /// expected rate in its calculations.
  246. void updateSendDue();
  247. boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk
  248. ///< of exchanges.
  249. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange
  250. /// was initiated.
  251. uint64_t sent_packets_0_;
  252. uint64_t sent_packets_1_;
  253. };
  254. } // namespace perfdhcp
  255. } // namespace isc
  256. #endif // __COMMAND_OPTIONS_H