test_control.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdint.h>
  17. #include <unistd.h>
  18. #include <boost/date_time/posix_time/posix_time.hpp>
  19. #include <dhcp/libdhcp++.h>
  20. #include <dhcp/dhcp4.h>
  21. #include <exceptions/exceptions.h>
  22. #include "test_control.h"
  23. #include "command_options.h"
  24. using namespace std;
  25. using namespace boost;
  26. using namespace boost::posix_time;
  27. using namespace isc;
  28. using namespace isc::dhcp;
  29. namespace isc {
  30. namespace perfdhcp {
  31. TestControl&
  32. TestControl::instance() {
  33. static TestControl test_control;
  34. return (test_control);
  35. }
  36. TestControl::TestControl() :
  37. send_due_(microsec_clock::universal_time()),
  38. last_sent_(send_due_) {
  39. }
  40. bool
  41. TestControl::checkExitConditions() const {
  42. CommandOptions& options = CommandOptions::instance();
  43. if ((options.getNumRequests().size() > 0) &&
  44. (sent_packets_0_ >= options.getNumRequests()[0])) {
  45. return(true);
  46. } else if ((options.getNumRequests().size() == 2) &&
  47. (sent_packets_1_ >= options.getNumRequests()[1])) {
  48. return(true);
  49. }
  50. return(false);
  51. }
  52. Pkt4*
  53. TestControl::createDiscoverPkt4() {
  54. const uint32_t transid = static_cast<uint32_t>(random());
  55. Pkt4* pkt4 = new Pkt4(DHCPDISCOVER, transid);
  56. OptionBuffer opt_request_list_buf();
  57. // createRequestListBuffer4(opt_request_list_buf);
  58. return NULL;
  59. }
  60. OptionPtr
  61. TestControl::factoryRequestList4(Option::Universe u,
  62. uint16_t type,
  63. const OptionBuffer& buf)
  64. {
  65. const uint8_t buf_array[] = {
  66. DHO_SUBNET_MASK,
  67. DHO_BROADCAST_ADDRESS,
  68. DHO_TIME_OFFSET,
  69. DHO_ROUTERS,
  70. DHO_DOMAIN_NAME,
  71. DHO_DOMAIN_NAME_SERVERS,
  72. DHO_HOST_NAME
  73. };
  74. OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
  75. Option* opt = new Option(u, type, buf);
  76. opt->setData(buf_with_options.begin(),
  77. buf_with_options.end());
  78. return OptionPtr(opt);
  79. }
  80. uint64_t
  81. TestControl::getNextExchangesNum() const {
  82. CommandOptions& options = CommandOptions::instance();
  83. // Reset number of exchanges.
  84. uint64_t due_exchanges = 0;
  85. // Get current time.
  86. ptime now(microsec_clock::universal_time());
  87. // The due time indicates when we should start sening next chunk
  88. // of packets. If it is already due time, we should calculate
  89. // how many packets to send.
  90. if (now >= send_due_) {
  91. // If rate is specified from the command line we have to
  92. // synchornize with it.
  93. if (options.getRate() != 0) {
  94. time_period period(send_due_, now);
  95. // Null condition should not occur because we
  96. // have checked it in the first if statement but
  97. // let's keep this check just in case.
  98. if (period.is_null()) {
  99. return (0);
  100. }
  101. time_duration duration = period.length();
  102. // due_factor indicates the number of seconds that
  103. // sending next chunk of packets will take.
  104. double due_factor = duration.fractional_seconds() /
  105. time_duration::ticks_per_second();
  106. due_factor += duration.total_seconds();
  107. // Multiplying due_factor by expected rate gives the number
  108. // of exchanges to be initiated.
  109. due_exchanges = static_cast<uint64_t>(due_factor * options.getRate());
  110. // We want to make sure that at least one packet goes out.
  111. due_exchanges += 1;
  112. // We should not exceed aggressivity as it could have been
  113. // restricted from command line.
  114. if (due_exchanges > options.getAggressivity()) {
  115. due_exchanges = options.getAggressivity();
  116. }
  117. } else {
  118. // Rate is not specified so we rely on aggressivity
  119. // which is the number of packets to be sent in
  120. // one chunk.
  121. due_exchanges = options.getAggressivity();
  122. }
  123. return (due_exchanges);
  124. }
  125. return (0);
  126. }
  127. void
  128. TestControl::registerOptionFactories4() const {
  129. static bool factories_registered = false;
  130. if (!factories_registered) {
  131. LibDHCP::OptionFactoryRegister(Option::V4,
  132. DHO_DHCP_PARAMETER_REQUEST_LIST,
  133. &TestControl::factoryRequestList4);
  134. }
  135. factories_registered = true;
  136. }
  137. void
  138. TestControl::registerOptionFactories6() const {
  139. static bool factories_registered = false;
  140. if (!factories_registered) {
  141. }
  142. factories_registered = true;
  143. }
  144. void
  145. TestControl::registerOptionFactories() const {
  146. CommandOptions& options = CommandOptions::instance();
  147. switch(options.getIpVersion()) {
  148. case 4:
  149. registerOptionFactories4();
  150. break;
  151. case 6:
  152. registerOptionFactories6();
  153. break;
  154. default:
  155. isc_throw(InvalidOperation, "command line options have to be parsed "
  156. "before DHCP option factories can be registered");
  157. }
  158. }
  159. void
  160. TestControl::run() {
  161. sent_packets_0_ = 0;
  162. sent_packets_1_ = 0;
  163. CommandOptions& options = CommandOptions::instance();
  164. // Ip version is not set ONLY in case the command options
  165. // where not parsed. This surely means that parse() function
  166. // was not called prior to starting the test. This is fatal
  167. // error.
  168. if (options.getIpVersion() == 0) {
  169. isc_throw(InvalidOperation, "command options must be parsed before running "
  170. "a test");
  171. }
  172. registerOptionFactories();
  173. uint64_t packets_sent = 0;
  174. for (;;) {
  175. updateSendDue();
  176. if (checkExitConditions()) {
  177. break;
  178. }
  179. uint64_t packets_due = getNextExchangesNum();
  180. for (uint64_t i = packets_due; i > 0; --i) {
  181. startExchange();
  182. ++packets_sent;
  183. cout << "Packets sent " << packets_sent << endl;
  184. }
  185. }
  186. }
  187. void
  188. TestControl::startExchange() {
  189. ++sent_packets_0_;
  190. last_sent_ = microsec_clock::universal_time();
  191. }
  192. void
  193. TestControl::updateSendDue() {
  194. // If default constructor was called, this should not happen but
  195. // if somebody has changed default constructor it is better to
  196. // keep this check.
  197. if (last_sent_.is_not_a_date_time()) {
  198. isc_throw(Unexpected, "time of last sent packet not initialized");
  199. }
  200. // Get the expected exchange rate.
  201. CommandOptions& options = CommandOptions::instance();
  202. int rate = options.getRate();
  203. // If rate was not specified we will wait just one clock tick to
  204. // send next packet. This simulates best effort conditions.
  205. long duration = 1;
  206. if (rate != 0) {
  207. // We use number of ticks instead of nanoseconds because
  208. // nanosecond resolution may not be available on some
  209. // machines. Number of ticks guarantees the highest possible
  210. // timer resolution.
  211. duration = time_duration::ticks_per_second() / rate;
  212. }
  213. // Calculate due time to initate next chunk of exchanges.
  214. send_due_ = last_sent_ + time_duration(0, 0, 0, duration);
  215. }
  216. } // namespace perfdhcp
  217. } // namespace isc