test_control.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  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 <exceptions/exceptions.h>
  20. #include <asiolink/io_address.h>
  21. #include <dhcp/libdhcp++.h>
  22. #include <dhcp/iface_mgr.h>
  23. #include <dhcp/dhcp4.h>
  24. #include "test_control.h"
  25. #include "command_options.h"
  26. using namespace std;
  27. using namespace boost;
  28. using namespace boost::posix_time;
  29. using namespace isc;
  30. using namespace isc::dhcp;
  31. using namespace isc::asiolink;
  32. namespace isc {
  33. namespace perfdhcp {
  34. TestControl::TestControlSocket::TestControlSocket(int socket) :
  35. socket_(socket),
  36. addr_("127.0.0.1") {
  37. initSocketData();
  38. }
  39. TestControl::TestControlSocket::~TestControlSocket() {
  40. IfaceMgr::instance().closeSockets();
  41. }
  42. void
  43. TestControl::TestControlSocket::initSocketData() {
  44. const IfaceMgr::IfaceCollection& ifaces =
  45. IfaceMgr::instance().getIfaces();
  46. for (IfaceMgr::IfaceCollection::const_iterator it = ifaces.begin();
  47. it != ifaces.end();
  48. ++it) {
  49. const IfaceMgr::SocketCollection& socket_collection =
  50. it->getSockets();
  51. for (IfaceMgr::SocketCollection::const_iterator s =
  52. socket_collection.begin();
  53. s != socket_collection.end();
  54. ++s) {
  55. if (s->sockfd_ == socket_) {
  56. iface_ = it->getName();
  57. ifindex_ = it->getIndex();
  58. addr_ = s->addr_;
  59. return;
  60. }
  61. }
  62. }
  63. isc_throw(BadValue, "interface for for specified socket "
  64. "descriptor not found");
  65. }
  66. TestControl&
  67. TestControl::instance() {
  68. static TestControl test_control;
  69. return (test_control);
  70. }
  71. TestControl::TestControl() :
  72. send_due_(microsec_clock::universal_time()),
  73. last_sent_(send_due_) {
  74. }
  75. bool
  76. TestControl::checkExitConditions() const {
  77. CommandOptions& options = CommandOptions::instance();
  78. if ((options.getNumRequests().size() > 0) &&
  79. (sent_packets_0_ >= options.getNumRequests()[0])) {
  80. return(true);
  81. } else if ((options.getNumRequests().size() == 2) &&
  82. (sent_packets_1_ >= options.getNumRequests()[1])) {
  83. return(true);
  84. }
  85. return(false);
  86. }
  87. OptionPtr
  88. TestControl::factoryElapsedTime6(Option::Universe, uint16_t,
  89. const OptionBuffer& buf) {
  90. if (buf.size() == 2) {
  91. return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf));
  92. } else if (buf.size() == 0) {
  93. return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
  94. OptionBuffer(2, 0)));
  95. }
  96. isc_throw(isc::BadValue,
  97. "elapsed time option buffer size has to be 0 or 2");
  98. }
  99. OptionPtr
  100. TestControl::factoryGeneric(Option::Universe u, uint16_t type,
  101. const OptionBuffer& buf) {
  102. OptionPtr opt(new Option(u, type, buf));
  103. return opt;
  104. }
  105. OptionPtr
  106. TestControl::factoryIana6(Option::Universe, uint16_t,
  107. const OptionBuffer& buf) {
  108. const uint8_t buf_array[] = {
  109. 0, 0, 0, 1, // IAID = 1
  110. 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600
  111. 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
  112. };
  113. OptionBuffer buf_ia_na(buf_array, buf_array + sizeof(buf_array));
  114. for (int i = 0; i < buf.size(); ++i) {
  115. buf_ia_na.push_back(buf[i]);
  116. }
  117. return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na));
  118. }
  119. OptionPtr
  120. TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
  121. const OptionBuffer&) {
  122. return OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer()));
  123. }
  124. OptionPtr
  125. TestControl::factoryOptionRequestOption6(Option::Universe,
  126. uint16_t,
  127. const OptionBuffer&) {
  128. const uint8_t buf_array[] = {
  129. D6O_NAME_SERVERS,
  130. D6O_DOMAIN_SEARCH
  131. };
  132. OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
  133. return OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options));
  134. }
  135. OptionPtr
  136. TestControl::factoryRequestList4(Option::Universe u,
  137. uint16_t type,
  138. const OptionBuffer& buf) {
  139. const uint8_t buf_array[] = {
  140. DHO_SUBNET_MASK,
  141. DHO_BROADCAST_ADDRESS,
  142. DHO_TIME_OFFSET,
  143. DHO_ROUTERS,
  144. DHO_DOMAIN_NAME,
  145. DHO_DOMAIN_NAME_SERVERS,
  146. DHO_HOST_NAME
  147. };
  148. OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
  149. OptionPtr opt(new Option(u, type, buf));
  150. opt->setData(buf_with_options.begin(), buf_with_options.end());
  151. return opt;
  152. }
  153. std::vector<uint8_t>
  154. TestControl::generateMacAddress() const {
  155. CommandOptions& options = CommandOptions::instance();
  156. uint32_t clients_num = options.getClientsNum();
  157. if ((clients_num == 0) || (clients_num == 1)) {
  158. return options.getMacPrefix();
  159. }
  160. // Get the base MAC address. We are going to randomize part of it.
  161. std::vector<uint8_t> mac_addr(options.getMacPrefix());
  162. if (mac_addr.size() != HW_ETHER_LEN) {
  163. isc_throw(BadValue, "invalid MAC address prefix specified");
  164. }
  165. uint32_t r = random();
  166. // The random number must be in the range 0..clients_num. This
  167. // will guarantee that every client has exactly one random MAC
  168. // address assigned.
  169. r %= clients_num;
  170. // Randomize MAC address octets.
  171. for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
  172. it >= mac_addr.begin();
  173. --it) {
  174. // Add the random value to the current octet.
  175. (*it) += r;
  176. if (r < 256) {
  177. // If we are here it means that there is no sense
  178. // to randomize the remaining octets of MAC address
  179. // because the following bytes of random value
  180. // are zero and it will have no effect.
  181. break;
  182. }
  183. // Randomize the next octet with the following
  184. // byte of random value.
  185. r >>= 8;
  186. }
  187. return mac_addr;
  188. }
  189. std::vector<uint8_t>
  190. TestControl::generateDuid() const {
  191. CommandOptions& options = CommandOptions::instance();
  192. uint32_t clients_num = options.getClientsNum();
  193. if ((clients_num == 0) || (clients_num == 1)) {
  194. return options.getDuidPrefix();
  195. }
  196. // Get the base DUID. We are going to randomize part of it.
  197. std::vector<uint8_t> duid(options.getDuidPrefix());
  198. std::vector<uint8_t> mac_addr(generateMacAddress());
  199. duid.resize(duid.size() - mac_addr.size());
  200. for (int i = 0; i < mac_addr.size(); ++i) {
  201. duid.push_back(mac_addr[i]);
  202. }
  203. return duid;
  204. }
  205. uint64_t
  206. TestControl::getNextExchangesNum() const {
  207. CommandOptions& options = CommandOptions::instance();
  208. // Reset number of exchanges.
  209. uint64_t due_exchanges = 0;
  210. // Get current time.
  211. ptime now(microsec_clock::universal_time());
  212. // The due time indicates when we should start sending next chunk
  213. // of packets. If it is already due time, we should calculate
  214. // how many packets to send.
  215. if (now >= send_due_) {
  216. // If rate is specified from the command line we have to
  217. // synchornize with it.
  218. if (options.getRate() != 0) {
  219. time_period period(send_due_, now);
  220. time_duration duration = period.length();
  221. // due_factor indicates the number of seconds that
  222. // sending next chunk of packets will take.
  223. double due_factor = duration.fractional_seconds() /
  224. time_duration::ticks_per_second();
  225. due_factor += duration.total_seconds();
  226. // Multiplying due_factor by expected rate gives the number
  227. // of exchanges to be initiated.
  228. due_exchanges = static_cast<uint64_t>(due_factor * options.getRate());
  229. // We want to make sure that at least one packet goes out.
  230. due_exchanges += 1;
  231. // We should not exceed aggressivity as it could have been
  232. // restricted from command line.
  233. if (due_exchanges > options.getAggressivity()) {
  234. due_exchanges = options.getAggressivity();
  235. }
  236. } else {
  237. // Rate is not specified so we rely on aggressivity
  238. // which is the number of packets to be sent in
  239. // one chunk.
  240. due_exchanges = options.getAggressivity();
  241. }
  242. return (due_exchanges);
  243. }
  244. return (0);
  245. }
  246. void
  247. TestControl::initializeStatsMgr() {
  248. CommandOptions& options = CommandOptions::instance();
  249. if (options.getIpVersion() == 4) {
  250. stats_mgr4_.reset();
  251. stats_mgr4_ = StatsMgr4Ptr(new StatsMgr4());
  252. stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_DO);
  253. if (options.getExchangeMode() == CommandOptions::DO_SA) {
  254. stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RA);
  255. }
  256. } else if (options.getIpVersion() == 6) {
  257. stats_mgr6_.reset();
  258. stats_mgr6_ = StatsMgr6Ptr(new StatsMgr6());
  259. stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_SA);
  260. if (options.getExchangeMode() == CommandOptions::DO_SA) {
  261. stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RR);
  262. }
  263. }
  264. }
  265. int
  266. TestControl::openSocket(uint16_t port) const {
  267. CommandOptions& options = CommandOptions::instance();
  268. std::string localname = options.getLocalName();
  269. std::string servername = options.getServerName();
  270. uint8_t family = AF_INET;
  271. int sock = 0;
  272. IOAddress remoteaddr(servername);
  273. if (port == 0) {
  274. if (options.getIpVersion() == 6) {
  275. port = DHCP6_CLIENT_PORT;
  276. } else if (options.getIpVersion() == 4) {
  277. port = 67; // TODO: find out why port 68 is wrong here.
  278. }
  279. }
  280. if (options.getIpVersion() == 6) {
  281. family = AF_INET6;
  282. }
  283. // Local name is specified along with '-l' option.
  284. // It may point to interface name or local address.
  285. if (!localname.empty()) {
  286. // CommandOptions should be already aware wether local name
  287. // is interface name or address because it uses IfaceMgr to
  288. // scan interfaces and get's their names.
  289. if (options.isInterface()) {
  290. sock = IfaceMgr::instance().openSocketFromIface(localname,
  291. port,
  292. family);
  293. } else {
  294. IOAddress localaddr(localname);
  295. sock = IfaceMgr::instance().openSocketFromAddress(localaddr,
  296. port);
  297. }
  298. } else if (!servername.empty()) {
  299. // If only server name is given we will need to try to resolve
  300. // the local address to bind socket to based on remote address.
  301. sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr,
  302. port);
  303. }
  304. if (sock <= 0) {
  305. isc_throw(BadValue, "unable to open socket to communicate with "
  306. "DHCP server");
  307. }
  308. // IfaceMgr does not set broadcast option on the socket. We rely
  309. // on CommandOptions object to find out if socket has to have
  310. // broadcast enabled.
  311. if ((options.getIpVersion() == 4) && options.isBroadcast()) {
  312. int broadcast_enable = 1;
  313. int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
  314. &broadcast_enable, sizeof(broadcast_enable));
  315. if (ret < 0) {
  316. isc_throw(InvalidOperation,
  317. "unable to set broadcast option on the socket");
  318. }
  319. } else if (options.getIpVersion() == 6) {
  320. // If remote address is multicast we need to enable it on
  321. // the socket that has been created.
  322. asio::ip::address_v6 remote_v6 = remoteaddr.getAddress().to_v6();
  323. if (remote_v6.is_multicast()) {
  324. int hops = 1;
  325. int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
  326. &hops, sizeof(hops));
  327. // If user specified interface name with '-l' the
  328. // IPV6_MULTICAST_IF has to be set.
  329. if ((ret >= 0) && options.isInterface()) {
  330. IfaceMgr::Iface* iface =
  331. IfaceMgr::instance().getIface(options.getLocalName());
  332. if (iface == NULL) {
  333. isc_throw(Unexpected, "unknown interface "
  334. << options.getLocalName());
  335. }
  336. int idx = iface->getIndex();
  337. ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
  338. &idx, sizeof(idx));
  339. }
  340. if (ret < 0) {
  341. isc_throw(InvalidOperation,
  342. "unable to enable multicast on socket " << sock
  343. << ". errno = " << errno);
  344. }
  345. }
  346. }
  347. return(sock);
  348. }
  349. void
  350. TestControl::printStats() const {
  351. CommandOptions& options = CommandOptions::instance();
  352. if (options.getIpVersion() == 4) {
  353. if (!stats_mgr4_) {
  354. isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
  355. "hasn't been initialized");
  356. }
  357. stats_mgr4_->printStats();
  358. } else if (options.getIpVersion() == 6) {
  359. if (!stats_mgr6_) {
  360. isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
  361. "hasn't been initialized");
  362. }
  363. stats_mgr6_->printStats();
  364. }
  365. }
  366. void
  367. TestControl::receivePacket4(Pkt4Ptr& pkt4) {
  368. switch(pkt4->getType()) {
  369. case DHCPOFFER :
  370. stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO, pkt4);
  371. break;
  372. case DHCPACK :
  373. stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4);
  374. break;
  375. default:
  376. isc_throw(BadValue, "unknown type " << pkt4->getType()
  377. << " of received DHCPv4 packet");
  378. }
  379. }
  380. void
  381. TestControl::receivePacket6(Pkt6Ptr& pkt6) {
  382. switch(pkt6->getType()) {
  383. case DHCPV6_ADVERTISE :
  384. stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_SA, pkt6);
  385. break;
  386. case DHCPV6_REPLY :
  387. stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6);
  388. break;
  389. default:
  390. isc_throw(BadValue, "unknown type " << pkt6->getType()
  391. << " of received DHCPv6 packet");
  392. }
  393. }
  394. void
  395. TestControl::receivePackets() {
  396. int timeout = 0;
  397. bool receiving = true;
  398. while (receiving) {
  399. if (CommandOptions::instance().getIpVersion() == 4) {
  400. Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout);
  401. if (!pkt4) {
  402. receiving = false;
  403. } else {
  404. pkt4->unpack();
  405. receivePacket4(pkt4);
  406. }
  407. } else if (CommandOptions::instance().getIpVersion() == 6) {
  408. Pkt6Ptr pkt6 = IfaceMgr::instance().receive6(timeout);
  409. if (!pkt6) {
  410. receiving = false;
  411. } else {
  412. if (pkt6->unpack()) {
  413. receivePacket6(pkt6);
  414. }
  415. }
  416. }
  417. }
  418. }
  419. void
  420. TestControl::registerOptionFactories4() const {
  421. static bool factories_registered = false;
  422. if (!factories_registered) {
  423. // DHCP_MESSAGE_TYPE option factory.
  424. LibDHCP::OptionFactoryRegister(Option::V4,
  425. DHO_DHCP_MESSAGE_TYPE,
  426. &TestControl::factoryGeneric);
  427. // DHCP_PARAMETER_REQUEST_LIST option factory.
  428. LibDHCP::OptionFactoryRegister(Option::V4,
  429. DHO_DHCP_PARAMETER_REQUEST_LIST,
  430. &TestControl::factoryRequestList4);
  431. }
  432. factories_registered = true;
  433. }
  434. void
  435. TestControl::registerOptionFactories6() const {
  436. static bool factories_registered = false;
  437. if (!factories_registered) {
  438. LibDHCP::OptionFactoryRegister(Option::V6,
  439. D6O_ELAPSED_TIME,
  440. &TestControl::factoryElapsedTime6);
  441. LibDHCP::OptionFactoryRegister(Option::V6,
  442. D6O_RAPID_COMMIT,
  443. &TestControl::factoryRapidCommit6);
  444. LibDHCP::OptionFactoryRegister(Option::V6,
  445. D6O_ORO,
  446. &TestControl::factoryOptionRequestOption6);
  447. LibDHCP::OptionFactoryRegister(Option::V6,
  448. D6O_CLIENTID,
  449. &TestControl::factoryGeneric);
  450. LibDHCP::OptionFactoryRegister(Option::V6,
  451. D6O_IA_NA,
  452. &TestControl::factoryIana6);
  453. }
  454. factories_registered = true;
  455. }
  456. void
  457. TestControl::registerOptionFactories() const {
  458. CommandOptions& options = CommandOptions::instance();
  459. switch(options.getIpVersion()) {
  460. case 4:
  461. registerOptionFactories4();
  462. break;
  463. case 6:
  464. registerOptionFactories6();
  465. break;
  466. default:
  467. isc_throw(InvalidOperation, "command line options have to be parsed "
  468. "before DHCP option factories can be registered");
  469. }
  470. }
  471. void
  472. TestControl::run() {
  473. sent_packets_0_ = 0;
  474. sent_packets_1_ = 0;
  475. CommandOptions& options = CommandOptions::instance();
  476. // Ip version is not set ONLY in case the command options
  477. // were not parsed. This surely means that parse() function
  478. // was not called prior to starting the test. This is fatal
  479. // error.
  480. if (options.getIpVersion() == 0) {
  481. isc_throw(InvalidOperation,
  482. "command options must be parsed before running a test");
  483. }
  484. registerOptionFactories();
  485. TestControlSocket socket(openSocket());
  486. initializeStatsMgr();
  487. uint64_t packets_sent = 0;
  488. for (;;) {
  489. updateSendDue();
  490. if (checkExitConditions()) {
  491. break;
  492. }
  493. uint64_t packets_due = getNextExchangesNum();
  494. receivePackets();
  495. for (uint64_t i = packets_due; i > 0; --i) {
  496. if (options.getIpVersion() == 4) {
  497. sendDiscover4(socket);
  498. } else {
  499. sendSolicit6(socket);
  500. }
  501. ++packets_sent;
  502. }
  503. }
  504. printStats();
  505. }
  506. void
  507. TestControl::sendDiscover4(const TestControlSocket& socket) {
  508. ++sent_packets_0_;
  509. last_sent_ = microsec_clock::universal_time();
  510. // Generate the MAC address to be passed in the packet.
  511. std::vector<uint8_t> mac_address = generateMacAddress();
  512. // Generate trasnaction id to be set for the new exchange.
  513. const uint32_t transid = static_cast<uint32_t>(random() % 0x00FFFFFF);
  514. boost::shared_ptr<Pkt4> pkt4(new Pkt4(DHCPDISCOVER, transid));
  515. if (!pkt4) {
  516. isc_throw(Unexpected, "failed to create DISCOVER packet");
  517. }
  518. // Set options: DHCP_MESSAGE_TYPE and DHCP_PARAMETER_REQUEST_LIST
  519. OptionBuffer buf_msg_type;
  520. buf_msg_type.push_back(DHCPDISCOVER);
  521. pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
  522. buf_msg_type));
  523. pkt4->addOption(Option::factory(Option::V4,
  524. DHO_DHCP_PARAMETER_REQUEST_LIST));
  525. // Set client's and server's ports as well as server's address,
  526. // and local (relay) address.
  527. setDefaults4(socket, pkt4);
  528. pkt4->pack();
  529. IfaceMgr::instance().send(pkt4);
  530. if (!stats_mgr4_) {
  531. isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
  532. "hasn't been initialized");
  533. }
  534. stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, pkt4);
  535. }
  536. void
  537. TestControl::sendSolicit6(const TestControlSocket& socket) {
  538. ++sent_packets_0_;
  539. last_sent_ = microsec_clock::universal_time();
  540. // Generate the MAC address to be passed in the packet.
  541. std::vector<uint8_t> mac_address = generateMacAddress();
  542. // Generate DUID to be passed to the packet
  543. std::vector<uint8_t> duid = generateDuid();
  544. // Generate trasnaction id to be set for the new exchange.
  545. const uint32_t transid = static_cast<uint32_t>(random() % 0x00FFFFFF);
  546. boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
  547. if (!pkt6) {
  548. isc_throw(Unexpected, "failed to create SOLICIT packet");
  549. }
  550. pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
  551. pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT));
  552. pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
  553. pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
  554. pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
  555. setDefaults6(socket, pkt6);
  556. pkt6->pack();
  557. IfaceMgr::instance().send(pkt6);
  558. if (!stats_mgr6_) {
  559. isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
  560. "hasn't been initialized");
  561. }
  562. stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6);
  563. }
  564. void
  565. TestControl::setDefaults4(const TestControlSocket& socket,
  566. const boost::shared_ptr<Pkt4>& pkt) {
  567. CommandOptions& options = CommandOptions::instance();
  568. // Interface name.
  569. pkt->setIface(socket.getIface());
  570. // Interface index.
  571. pkt->setIndex(socket.getIfIndex());
  572. // Local client's port (68)
  573. pkt->setLocalPort(DHCP4_CLIENT_PORT);
  574. // Server's port (67)
  575. pkt->setRemotePort(DHCP4_SERVER_PORT);
  576. // The remote server's name or IP.
  577. pkt->setRemoteAddr(IOAddress(options.getServerName()));
  578. // Set local addresss.
  579. pkt->setLocalAddr(IOAddress(socket.getAddress()));
  580. // Set relay (GIADDR) address to local address.
  581. pkt->setGiaddr(IOAddress(socket.getAddress()));
  582. // Pretend that we have one relay (which is us).
  583. pkt->setHops(1);
  584. }
  585. void
  586. TestControl::setDefaults6(const TestControlSocket& socket,
  587. const boost::shared_ptr<Pkt6>& pkt) {
  588. CommandOptions& options = CommandOptions::instance();
  589. // Interface name.
  590. pkt->setIface(socket.getIface());
  591. // Interface index.
  592. pkt->setIndex(socket.getIfIndex());
  593. // Local client's port (547)
  594. pkt->setLocalPort(DHCP6_CLIENT_PORT);
  595. // Server's port (548)
  596. pkt->setRemotePort(DHCP6_SERVER_PORT);
  597. // Set local address.
  598. pkt->setLocalAddr(socket.getAddress());
  599. // The remote server's name or IP.
  600. pkt->setRemoteAddr(IOAddress(options.getServerName()));
  601. }
  602. void
  603. TestControl::updateSendDue() {
  604. // If default constructor was called, this should not happen but
  605. // if somebody has changed default constructor it is better to
  606. // keep this check.
  607. if (last_sent_.is_not_a_date_time()) {
  608. isc_throw(Unexpected, "time of last sent packet not initialized");
  609. }
  610. // Get the expected exchange rate.
  611. CommandOptions& options = CommandOptions::instance();
  612. int rate = options.getRate();
  613. // If rate was not specified we will wait just one clock tick to
  614. // send next packet. This simulates best effort conditions.
  615. long duration = 1;
  616. if (rate != 0) {
  617. // We use number of ticks instead of nanoseconds because
  618. // nanosecond resolution may not be available on some
  619. // machines. Number of ticks guarantees the highest possible
  620. // timer resolution.
  621. duration = time_duration::ticks_per_second() / rate;
  622. }
  623. // Calculate due time to initate next chunk of exchanges.
  624. send_due_ = last_sent_ + time_duration(0, 0, 0, duration);
  625. }
  626. } // namespace perfdhcp
  627. } // namespace isc