Kea  1.5.0
test_control.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
10 #include <asiolink/io_address.h>
11 #include <dhcp/libdhcp++.h>
12 #include <dhcp/iface_mgr.h>
13 #include <dhcp/dhcp4.h>
14 #include <dhcp/option6_ia.h>
16 #include "test_control.h"
17 #include "command_options.h"
18 #include "perf_pkt4.h"
19 #include "perf_pkt6.h"
20 
21 #include <boost/date_time/posix_time/posix_time.hpp>
22 #include <boost/foreach.hpp>
23 
24 #include <algorithm>
25 #include <fstream>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <sstream>
32 #include <sys/wait.h>
33 
34 using namespace std;
35 using namespace boost::posix_time;
36 using namespace isc;
37 using namespace isc::dhcp;
38 using namespace isc::asiolink;
39 
40 namespace isc {
41 namespace perfdhcp {
42 
43 bool TestControl::interrupted_ = false;
44 
45 ptime late_exit_target_time_ = ptime(not_a_date_time);
46 
47 bool
48 TestControl::hasLateExitCommenced() const {
49  return !late_exit_target_time_.is_not_a_date_time();
50 }
51 
52 bool
53 TestControl::waitToExit() const {
54  static ptime exit_time = ptime(not_a_date_time);
55  CommandOptions& options = CommandOptions::instance();
56  uint32_t wait_time = options.getExitWaitTime();
57 
58  // If we care and not all packets are in yet
59  if (wait_time && !haveAllPacketsBeenReceived()) {
60  const ptime now = microsec_clock::universal_time();
61 
62  // Init the end time if it hasn't started yet
63  if (exit_time.is_not_a_date_time()) {
64  exit_time = now + time_duration(microseconds(wait_time));
65  }
66 
67  // If we're not at end time yet, return true
68  return (now < exit_time);
69  }
70 
71  // No need to wait, return false;
72  return (false);
73 }
74 
75 bool
76 TestControl::haveAllPacketsBeenReceived() const {
77  const CommandOptions& options = CommandOptions::instance();
78  const uint8_t& ipversion = options.getIpVersion();
79  const std::vector<int>& num_request = options.getNumRequests();
80  const size_t& num_request_size = num_request.size();
81 
82  if (num_request_size == 0) {
83  return false;
84  }
85 
86  uint32_t responses = 0;
87  uint32_t requests = num_request[0];
88  if (num_request_size >= 2) {
89  requests += num_request[1];
90  }
91 
92  if (ipversion == 4) {
93  responses = stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) +
94  stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_RA);
95  } else {
96  responses = stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) +
97  stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_RR);
98  }
99 
100  return (responses == requests);
101 }
102 
103 TestControl::TestControlSocket::TestControlSocket(const int socket) :
104  SocketInfo(asiolink::IOAddress("127.0.0.1"), 0, socket),
105  ifindex_(0), valid_(true) {
106  try {
107  initSocketData();
108  } catch (const Exception&) {
109  valid_ = false;
110  }
111 }
112 
114  IfacePtr iface = IfaceMgr::instance().getIface(ifindex_);
115  if (iface) {
116  iface->delSocket(sockfd_);
117  }
118 }
119 
120 void
121 TestControl::TestControlSocket::initSocketData() {
122  BOOST_FOREACH(IfacePtr iface, IfaceMgr::instance().getIfaces()) {
123  BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
124  if (s.sockfd_ == sockfd_) {
125  ifindex_ = iface->getIndex();
126  addr_ = s.addr_;
127  return;
128  }
129  }
130  }
131  isc_throw(BadValue, "interface for for specified socket "
132  "descriptor not found");
133 }
134 
137  static TestControl test_control;
138  return (test_control);
139 }
140 
142  : number_generator_(0, CommandOptions::instance().getMacsFromFile().size()) {
143  reset();
144 }
145 
146 void
148  // If diagnostics is disabled, there is no need to log late sent messages.
149  // If it is enabled and the rate control object indicates that the last
150  // sent message was late, bump up the counter in Stats Manager.
151  if (rate_control.isLateSent() && testDiags('i')) {
153  if (options.getIpVersion() == 4) {
154  stats_mgr4_->incrementCounter("latesend");
155  } else if (options.getIpVersion() == 6) {
156  stats_mgr6_->incrementCounter("latesend");
157  }
158  }
159 }
160 
161 void
164  // When Renews are not sent, Reply packets are not cached so there
165  // is nothing to do.
166  if (options.getRenewRate() == 0) {
167  return;
168  }
169 
170  static boost::posix_time::ptime last_clean =
171  microsec_clock::universal_time();
172 
173  // Check how much time has passed since last cleanup.
174  time_period time_since_clean(last_clean,
175  microsec_clock::universal_time());
176  // Cleanup every 1 second.
177  if (time_since_clean.length().total_seconds() >= 1) {
178  // Calculate how many cached packets to remove. Actually we could
179  // just leave enough packets to handle Renews for 1 second but
180  // since we want to randomize leases to be renewed so leave 5
181  // times more packets to randomize from.
182  // @todo The cache size might be controlled from the command line.
183  if (reply_storage_.size() > 5 * options.getRenewRate()) {
184  reply_storage_.clear(reply_storage_.size() -
185  5 * options.getRenewRate());
186  }
187  // Remember when we performed a cleanup for the last time.
188  // We want to do the next cleanup not earlier than in one second.
189  last_clean = microsec_clock::universal_time();
190  }
191 }
192 
193 void
194 TestControl::copyIaOptions(const Pkt6Ptr& pkt_from, Pkt6Ptr& pkt_to) {
195  if (!pkt_from || !pkt_to) {
196  isc_throw(BadValue, "NULL pointers must not be specified as arguments"
197  " for the copyIaOptions function");
198  }
199  // IA_NA
200  if (CommandOptions::instance().getLeaseType()
202  OptionPtr option = pkt_from->getOption(D6O_IA_NA);
203  if (!option) {
204  isc_throw(OptionNotFound, "IA_NA option not found in the"
205  " server's response");
206  }
207  pkt_to->addOption(option);
208  }
209  // IA_PD
210  if (CommandOptions::instance().getLeaseType()
212  OptionPtr option = pkt_from->getOption(D6O_IA_PD);
213  if (!option) {
214  isc_throw(OptionNotFound, "IA_PD option not found in the"
215  " server's response");
216  }
217  pkt_to->addOption(option);
218  }
219 
220 
221 }
222 
223 std::string
224 TestControl::byte2Hex(const uint8_t b) const {
225  const int b1 = b / 16;
226  const int b0 = b % 16;
227  ostringstream stream;
228  stream << std::hex << b1 << b0 << std::dec;
229  return (stream.str());
230 }
231 
232 bool
234  if (interrupted_) {
235  return (true);
236  }
238  bool test_period_reached = false;
239  // Check if test period passed.
240  if (options.getPeriod() != 0) {
241  if (options.getIpVersion() == 4) {
242  time_period period(stats_mgr4_->getTestPeriod());
243  if (period.length().total_seconds() >= options.getPeriod()) {
244  test_period_reached = true;
245  }
246  } else if (options.getIpVersion() == 6) {
247  time_period period = stats_mgr6_->getTestPeriod();
248  if (period.length().total_seconds() >= options.getPeriod()) {
249  test_period_reached = true;
250  }
251  }
252  }
253  if (test_period_reached) {
254  if (testDiags('e')) {
255  std::cout << "reached test-period." << std::endl;
256  }
257  if (!waitToExit()) {
258  return true;
259  }
260  }
261 
262  bool max_requests = false;
263  // Check if we reached maximum number of DISCOVER/SOLICIT sent.
264  if (options.getNumRequests().size() > 0) {
265  if (options.getIpVersion() == 4) {
267  options.getNumRequests()[0]) {
268  max_requests = true;
269  }
270  } else if (options.getIpVersion() == 6) {
271  if (stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA) >=
272  options.getNumRequests()[0]) {
273  max_requests = true;
274  }
275  }
276  }
277  // Check if we reached maximum number REQUEST packets.
278  if (options.getNumRequests().size() > 1) {
279  if (options.getIpVersion() == 4) {
280  if (stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) >=
281  options.getNumRequests()[1]) {
282  max_requests = true;
283  }
284  } else if (options.getIpVersion() == 6) {
285  if (stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) >=
286  options.getNumRequests()[1]) {
287  max_requests = true;
288  }
289  }
290  }
291  if (max_requests) {
292  if (testDiags('e')) {
293  std::cout << "Reached max requests limit." << std::endl;
294  }
295  if (!waitToExit()) {
296  return true;
297  }
298  }
299 
300  // Check if we reached maximum number of drops of OFFER/ADVERTISE packets.
301  bool max_drops = false;
302  if (options.getMaxDrop().size() > 0) {
303  if (options.getIpVersion() == 4) {
304  if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_DO) >=
305  options.getMaxDrop()[0]) {
306  max_drops = true;
307  }
308  } else if (options.getIpVersion() == 6) {
309  if (stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_SA) >=
310  options.getMaxDrop()[0]) {
311  max_drops = true;
312  }
313  }
314  }
315  // Check if we reached maximum number of drops of ACK/REPLY packets.
316  if (options.getMaxDrop().size() > 1) {
317  if (options.getIpVersion() == 4) {
318  if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) >=
319  options.getMaxDrop()[1]) {
320  max_drops = true;
321  }
322  } else if (options.getIpVersion() == 6) {
323  if (stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) >=
324  options.getMaxDrop()[1]) {
325  max_drops = true;
326  }
327  }
328  }
329  if (max_drops) {
330  if (testDiags('e')) {
331  std::cout << "Reached maximum drops number." << std::endl;
332  }
333  if (!waitToExit()) {
334  return true;
335  }
336  }
337 
338  // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets.
339  bool max_pdrops = false;
340  if (options.getMaxDropPercentage().size() > 0) {
341  if (options.getIpVersion() == 4) {
342  if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_DO) > 10) &&
343  ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_DO) /
344  stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_DO)) >=
345  options.getMaxDropPercentage()[0])) {
346  max_pdrops = true;
347 
348  }
349  } else if (options.getIpVersion() == 6) {
350  if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA) > 10) &&
351  ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_SA) /
352  stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA)) >=
353  options.getMaxDropPercentage()[0])) {
354  max_pdrops = true;
355  }
356  }
357  }
358  // Check if we reached maximum drops percentage of ACK/REPLY packets.
359  if (options.getMaxDropPercentage().size() > 1) {
360  if (options.getIpVersion() == 4) {
361  if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) > 10) &&
362  ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) /
363  stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA)) >=
364  options.getMaxDropPercentage()[1])) {
365  max_pdrops = true;
366  }
367  } else if (options.getIpVersion() == 6) {
368  if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) > 10) &&
369  ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) /
370  stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR)) >=
371  options.getMaxDropPercentage()[1])) {
372  max_pdrops = true;
373  }
374  }
375  }
376  if (max_pdrops) {
377  if (testDiags('e')) {
378  std::cout << "Reached maximum percentage of drops." << std::endl;
379  }
380  if (!waitToExit()) {
381  return true;
382  }
383  }
384  return (false);
385 }
386 
387 Pkt4Ptr
389  if (!ack) {
390  isc_throw(isc::BadValue, "Unable to create DHCPREQUEST from a"
391  " null DHCPACK message");
392  } else if (ack->getYiaddr().isV4Zero()) {
393  isc_throw(isc::BadValue, "Unable to create DHCPREQUEST from a"
394  " DHCPACK message containing yiaddr of 0");
395  }
397  msg->setCiaddr(ack->getYiaddr());
398  msg->setHWAddr(ack->getHWAddr());
399  msg->addOption(generateClientId(msg->getHWAddr()));
400  return (msg);
401 }
402 
403 Pkt6Ptr
404 TestControl::createMessageFromReply(const uint16_t msg_type,
405  const dhcp::Pkt6Ptr& reply) {
406  // Restrict messages to Release and Renew.
407  if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
408  isc_throw(isc::BadValue, "invalid message type " << msg_type
409  << " to be created from Reply, expected DHCPV6_RENEW or"
410  " DHCPV6_RELEASE");
411  }
412  // Get the string representation of the message - to be used for error
413  // logging purposes.
414  const char* msg_type_str = (msg_type == DHCPV6_RENEW ? "Renew" : "Release");
415  // Reply message must be specified.
416  if (!reply) {
417  isc_throw(isc::BadValue, "Unable to create " << msg_type_str
418  << " message from the Reply message because the instance of"
419  " the Reply message is NULL");
420  }
421 
422  Pkt6Ptr msg(new Pkt6(msg_type, generateTransid()));
423  // Client id.
424  OptionPtr opt_clientid = reply->getOption(D6O_CLIENTID);
425  if (!opt_clientid) {
426  isc_throw(isc::Unexpected, "failed to create " << msg_type_str
427  << " message because client id option has not been found"
428  " in the Reply message");
429  }
430  msg->addOption(opt_clientid);
431  // Server id.
432  OptionPtr opt_serverid = reply->getOption(D6O_SERVERID);
433  if (!opt_serverid) {
434  isc_throw(isc::Unexpected, "failed to create " << msg_type_str
435  << " because server id option has not been found in the"
436  " Reply message");
437  }
438  msg->addOption(opt_serverid);
439  copyIaOptions(reply, msg);
440  return (msg);
441 }
442 
443 OptionPtr
445  const OptionBuffer& buf) {
446  if (buf.size() == 2) {
447  return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf)));
448  } else if (buf.size() == 0) {
449  return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
450  OptionBuffer(2, 0))));
451  }
453  "elapsed time option buffer size has to be 0 or 2");
454 }
455 
456 OptionPtr
458  const OptionBuffer& buf) {
459  OptionPtr opt(new Option(u, type, buf));
460  return (opt);
461 }
462 
463 OptionPtr
465  const OptionBuffer& buf) {
466  // @todo allow different values of T1, T2 and IAID.
467  const uint8_t buf_array[] = {
468  0, 0, 0, 1, // IAID = 1
469  0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
470  0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
471  };
472  OptionBuffer buf_ia_na(buf_array, buf_array + sizeof(buf_array));
473  for (size_t i = 0; i < buf.size(); ++i) {
474  buf_ia_na.push_back(buf[i]);
475  }
476  return (OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)));
477 }
478 
479 OptionPtr
481  const OptionBuffer& buf) {
482  // @todo allow different values of T1, T2 and IAID.
483  static const uint8_t buf_array[] = {
484  0, 0, 0, 1, // IAID = 1
485  0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
486  0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
487  };
488  OptionBuffer buf_ia_pd(buf_array, buf_array + sizeof(buf_array));
489  // Append sub-options to IA_PD.
490  buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
491  return (OptionPtr(new Option(Option::V6, D6O_IA_PD, buf_ia_pd)));
492 }
493 
494 
495 OptionPtr
497  const OptionBuffer&) {
498  return (OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())));
499 }
500 
501 OptionPtr
503  uint16_t,
504  const OptionBuffer&) {
505  const uint8_t buf_array[] = {
506  0, D6O_NAME_SERVERS,
508  };
509  OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
510  return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)));
511 }
512 
513 
514 OptionPtr
516  uint16_t type,
517  const OptionBuffer& buf) {
518  const uint8_t buf_array[] = {
522  DHO_ROUTERS,
526  };
527 
528  OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
529  OptionPtr opt(new Option(u, type, buf));
530  opt->setData(buf_with_options.begin(), buf_with_options.end());
531  return (opt);
532 }
533 
534 std::vector<uint8_t>
535 TestControl::generateMacAddress(uint8_t& randomized) {
537 
538  const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
539  // if we are using the -M option return a random one from the list...
540  if (macs.size() > 0) {
541  uint16_t r = number_generator_();
542  if (r >= macs.size()) {
543  r = 0;
544  }
545  return macs[r];
546 
547  } else {
548  // ... otherwise use the standard behavior
549  uint32_t clients_num = options.getClientsNum();
550  if (clients_num < 2) {
551  return (options.getMacTemplate());
552  }
553  // Get the base MAC address. We are going to randomize part of it.
554  std::vector<uint8_t> mac_addr(options.getMacTemplate());
555  if (mac_addr.size() != HW_ETHER_LEN) {
556  isc_throw(BadValue, "invalid MAC address template specified");
557  }
558  uint32_t r = macaddr_gen_->generate();
559  randomized = 0;
560  // Randomize MAC address octets.
561  for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
562  it >= mac_addr.begin();
563  --it) {
564  // Add the random value to the current octet.
565  (*it) += r;
566  ++randomized;
567  if (r < 256) {
568  // If we are here it means that there is no sense
569  // to randomize the remaining octets of MAC address
570  // because the following bytes of random value
571  // are zero and it will have no effect.
572  break;
573  }
574  // Randomize the next octet with the following
575  // byte of random value.
576  r >>= 8;
577  }
578  return (mac_addr);
579  }
580 }
581 
582 OptionPtr
584  std::vector<uint8_t> client_id(1, static_cast<uint8_t>(hwaddr->htype_));
585  client_id.insert(client_id.end(), hwaddr->hwaddr_.begin(),
586  hwaddr->hwaddr_.end());
587  return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
588  client_id)));
589 }
590 
591 std::vector<uint8_t>
592 TestControl::generateDuid(uint8_t& randomized) {
594  std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
595  const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
596  // pick a random mac address if we are using option -M..
597  if (macs.size() > 0) {
598  uint16_t r = number_generator_();
599  if (r >= macs.size()) {
600  r = 0;
601  }
602  std::vector<uint8_t> mac = macs[r];
603  // DUID_LL is in this format
604  // 0 1 2 3
605  // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
606  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
607  // | 3 | hardware type (16 bits) |
608  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
609  // . .
610  // . link-layer address (variable length) .
611  // . .
612  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613 
614  // No C++11 so initializer list support, building a vector<uint8_t> is a
615  // pain...
616  uint8_t duid_ll[] = {0, 3, 0, 1, 0, 0, 0, 0, 0, 0};
617  // copy duid_ll array into the vector
618  std::vector<uint8_t> duid(duid_ll,
619  duid_ll + sizeof(duid_ll) / sizeof(duid_ll[0]));
620  // put the mac address bytes at the end
621  std::copy(mac.begin(), mac.end(), duid.begin() + 4);
622  return (duid);
623  } else {
624  uint32_t clients_num = options.getClientsNum();
625  if ((clients_num == 0) || (clients_num == 1)) {
626  return (options.getDuidTemplate());
627  }
628  // Get the base DUID. We are going to randomize part of it.
629  std::vector<uint8_t> duid(options.getDuidTemplate());
630  // @todo: add support for DUIDs of different sizes.
631  duid.resize(duid.size());
632  std::copy(mac_addr.begin(), mac_addr.end(),
633  duid.begin() + duid.size() - mac_addr.size());
634  return (duid);
635  }
636 }
637 
638 uint32_t
641  ptime now(microsec_clock::universal_time());
642  // Check that we haven't passed the moment to send the next set of
643  // packets.
644  if (now >= basic_rate_control_.getDue() ||
645  (options.getRenewRate() != 0 && now >= renew_rate_control_.getDue()) ||
646  (options.getReleaseRate() != 0 &&
647  now >= release_rate_control_.getDue())) {
648  return (0);
649  }
650 
651  // Let's assume that the due time for Solicit is the soonest.
652  ptime due = basic_rate_control_.getDue();
653  // If we are sending Renews and due time for Renew occurs sooner,
654  // set the due time to Renew due time.
655  if ((options.getRenewRate()) != 0 && (renew_rate_control_.getDue() < due)) {
656  due = renew_rate_control_.getDue();
657  }
658  // If we are sending Releases and the due time for Release occurs
659  // sooner than the current due time, let's use the due for Releases.
660  if ((options.getReleaseRate() != 0) &&
661  (release_rate_control_.getDue() < due)) {
663  }
664  // Return the timeout in microseconds.
665  return (time_period(now, due).length().total_microseconds());
666 }
667 
668 int
670  int elp_offset = CommandOptions::instance().getIpVersion() == 4 ?
671  DHCPV4_ELAPSED_TIME_OFFSET : DHCPV6_ELAPSED_TIME_OFFSET;
674  }
675  return (elp_offset);
676 }
677 
678 template<class T>
679 uint32_t
680 TestControl::getElapsedTime(const T& pkt1, const T& pkt2) {
681  using namespace boost::posix_time;
682  ptime pkt1_time = pkt1->getTimestamp();
683  ptime pkt2_time = pkt2->getTimestamp();
684  if (pkt1_time.is_not_a_date_time() ||
685  pkt2_time.is_not_a_date_time()) {
686  isc_throw(InvalidOperation, "packet timestamp not set");;
687  }
688  time_period elapsed_period(pkt1_time, pkt2_time);
689  return (elapsed_period.is_null() ? 0 :
690  elapsed_period.length().total_milliseconds());
691 }
692 
693 int
694 TestControl::getRandomOffset(const int arg_idx) const {
695  int rand_offset = CommandOptions::instance().getIpVersion() == 4 ?
696  DHCPV4_RANDOMIZATION_OFFSET : DHCPV6_RANDOMIZATION_OFFSET;
697  if (CommandOptions::instance().getRandomOffset().size() > arg_idx) {
698  rand_offset = CommandOptions::instance().getRandomOffset()[arg_idx];
699  }
700  return (rand_offset);
701 }
702 
703 int
705  int rip_offset = CommandOptions::instance().getIpVersion() == 4 ?
706  DHCPV4_REQUESTED_IP_OFFSET : DHCPV6_IA_NA_OFFSET;
709  }
710  return (rip_offset);
711 }
712 
713 uint64_t
715  uint8_t ip_version = CommandOptions::instance().getIpVersion();
716  if (ip_version == 4) {
717  return (stats_mgr4_->getRcvdPacketsNum(xchg_type));
718  }
719  return (stats_mgr6_->
720  getRcvdPacketsNum(static_cast<StatsMgr6::ExchangeType>(xchg_type)));
721 }
722 
723 uint64_t
725  uint8_t ip_version = CommandOptions::instance().getIpVersion();
726  if (ip_version == 4) {
727  return (stats_mgr4_->getSentPacketsNum(xchg_type));
728  }
729  return (stats_mgr6_->
730  getSentPacketsNum(static_cast<StatsMgr6::ExchangeType>(xchg_type)));
731 }
732 
733 int
735  int srvid_offset = CommandOptions::instance().getIpVersion() == 4 ?
736  DHCPV4_SERVERID_OFFSET : DHCPV6_SERVERID_OFFSET;
738  srvid_offset = CommandOptions::instance().getServerIdOffset();
739  }
740  return (srvid_offset);
741 }
742 
744 TestControl::getTemplateBuffer(const size_t idx) const {
745  if (template_buffers_.size() > idx) {
746  return (template_buffers_[idx]);
747  }
748  isc_throw(OutOfRange, "invalid buffer index");
749 }
750 
751 int
752 TestControl::getTransactionIdOffset(const int arg_idx) const {
753  int xid_offset = CommandOptions::instance().getIpVersion() == 4 ?
754  DHCPV4_TRANSID_OFFSET : DHCPV6_TRANSID_OFFSET;
755  if (CommandOptions::instance().getTransactionIdOffset().size() > arg_idx) {
756  xid_offset = CommandOptions::instance().getTransactionIdOffset()[arg_idx];
757  }
758  return (xid_offset);
759 }
760 
761 void
763  int status = 0;
764  while (wait3(&status, WNOHANG, NULL) > 0) {
765  // continue
766  }
767 }
768 
769 void
771  interrupted_ = true;
772 }
773 
774 void
776  template_packets_v4_.clear();
777  template_packets_v6_.clear();
778  template_buffers_.clear();
780  std::vector<std::string> template_files = options.getTemplateFiles();
781  for (std::vector<std::string>::const_iterator it = template_files.begin();
782  it != template_files.end(); ++it) {
783  readPacketTemplate(*it);
784  }
785 }
786 
787 void
790  // Check if packet archive mode is required. If user
791  // requested diagnostics option -x t we have to enable
792  // it so as StatsMgr preserves all packets.
793  const bool archive_mode = testDiags('t') ? true : false;
794  if (options.getIpVersion() == 4) {
795  stats_mgr4_.reset();
796  stats_mgr4_ = StatsMgr4Ptr(new StatsMgr4(archive_mode));
797  stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_DO,
798  options.getDropTime()[0]);
799  if (options.getExchangeMode() == CommandOptions::DORA_SARR) {
800  stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RA,
801  options.getDropTime()[1]);
802  }
803  if (options.getRenewRate() != 0) {
804  stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RNA);
805  }
806 
807  } else if (options.getIpVersion() == 6) {
808  stats_mgr6_.reset();
809  stats_mgr6_ = StatsMgr6Ptr(new StatsMgr6(archive_mode));
810  stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_SA,
811  options.getDropTime()[0]);
812  if (options.getExchangeMode() == CommandOptions::DORA_SARR) {
813  stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RR,
814  options.getDropTime()[1]);
815  }
816  if (options.getRenewRate() != 0) {
817  stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RN);
818  }
819  if (options.getReleaseRate() != 0) {
820  stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RL);
821  }
822  }
823  if (testDiags('i')) {
824  if (options.getIpVersion() == 4) {
825  stats_mgr4_->addCustomCounter("latesend", "Late sent packets");
826  stats_mgr4_->addCustomCounter("shortwait", "Short waits for packets");
827  stats_mgr4_->addCustomCounter("multircvd", "Multiple packets receives");
828  stats_mgr4_->addCustomCounter("latercvd", "Late received packets");
829  } else if (options.getIpVersion() == 6) {
830  stats_mgr6_->addCustomCounter("latesend", "Late sent packets");
831  stats_mgr6_->addCustomCounter("shortwait", "Short waits for packets");
832  stats_mgr6_->addCustomCounter("multircvd", "Multiple packets receives");
833  stats_mgr6_->addCustomCounter("latercvd", "Late received packets");
834  }
835  }
836 }
837 
838 int
841  std::string localname = options.getLocalName();
842  std::string servername = options.getServerName();
843  uint16_t port = options.getLocalPort();
844  int sock = 0;
845 
846  uint8_t family = (options.getIpVersion() == 6) ? AF_INET6 : AF_INET;
847  IOAddress remoteaddr(servername);
848 
849  // Check for mismatch between IP option and server address
850  if (family != remoteaddr.getFamily()) {
852  "Values for IP version: " <<
853  static_cast<unsigned int>(options.getIpVersion()) <<
854  " and server address: " << servername << " are mismatched.");
855  }
856 
857  if (port == 0) {
858  if (family == AF_INET6) {
859  // need server port (547) because the server is acting as a relay agent
860  port = DHCP6_CLIENT_PORT;
861  // if acting as a relay agent change port.
862  if (options.isUseRelayedV6()) {
863  port = DHCP6_SERVER_PORT;
864  }
865  } else if (options.getIpVersion() == 4) {
866  port = 67; // TODO: find out why port 68 is wrong here.
867  }
868  }
869 
870  // Local name is specified along with '-l' option.
871  // It may point to interface name or local address.
872  if (!localname.empty()) {
873  // CommandOptions should be already aware whether local name
874  // is interface name or address because it uses IfaceMgr to
875  // scan interfaces and get's their names.
876  if (options.isInterface()) {
877  sock = IfaceMgr::instance().openSocketFromIface(localname,
878  port,
879  family);
880  } else {
881  IOAddress localaddr(localname);
882  sock = IfaceMgr::instance().openSocketFromAddress(localaddr,
883  port);
884  }
885  } else if (!servername.empty()) {
886  // If only server name is given we will need to try to resolve
887  // the local address to bind socket to based on remote address.
888  sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr,
889  port);
890  }
891  if (sock <= 0) {
892  isc_throw(BadValue, "unable to open socket to communicate with "
893  "DHCP server");
894  }
895 
896  // IfaceMgr does not set broadcast option on the socket. We rely
897  // on CommandOptions object to find out if socket has to have
898  // broadcast enabled.
899  if ((options.getIpVersion() == 4) && options.isBroadcast()) {
900  int broadcast_enable = 1;
901  int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
902  &broadcast_enable, sizeof(broadcast_enable));
903  if (ret < 0) {
905  "unable to set broadcast option on the socket");
906  }
907  } else if (options.getIpVersion() == 6) {
908  // If remote address is multicast we need to enable it on
909  // the socket that has been created.
910  if (remoteaddr.isV6Multicast()) {
911  int hops = 1;
912  int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
913  &hops, sizeof(hops));
914  // If user specified interface name with '-l' the
915  // IPV6_MULTICAST_IF has to be set.
916  if ((ret >= 0) && options.isInterface()) {
917  IfacePtr iface =
918  IfaceMgr::instance().getIface(options.getLocalName());
919  if (iface == NULL) {
920  isc_throw(Unexpected, "unknown interface "
921  << options.getLocalName());
922  }
923  int idx = iface->getIndex();
924  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
925  &idx, sizeof(idx));
926  }
927  if (ret < 0) {
929  "unable to enable multicast on socket " << sock
930  << ". errno = " << errno);
931  }
932  }
933  }
934 
935  return (sock);
936 }
937 
938 void
940  const uint64_t packets_num,
941  const bool preload /* = false */) {
943  for (uint64_t i = packets_num; i > 0; --i) {
944  if (options.getIpVersion() == 4) {
945  // No template packets means that no -T option was specified.
946  // We have to build packets ourselves.
947  if (template_buffers_.empty()) {
948  sendDiscover4(socket, preload);
949  } else {
950  // @todo add defines for packet type index that can be
951  // used to access template_buffers_.
952  sendDiscover4(socket, template_buffers_[0], preload);
953  }
954  } else {
955  // No template packets means that no -T option was specified.
956  // We have to build packets ourselves.
957  if (template_buffers_.empty()) {
958  sendSolicit6(socket, preload);
959  } else {
960  // @todo add defines for packet type index that can be
961  // used to access template_buffers_.
962  sendSolicit6(socket, template_buffers_[0], preload);
963  }
964  }
965  // If we preload server we don't want to receive any packets.
966  if (!preload) {
967  uint64_t latercvd = receivePackets(socket);
968  if (testDiags('i')) {
969  if (options.getIpVersion() == 4) {
970  stats_mgr4_->incrementCounter("latercvd", latercvd);
971  } else if (options.getIpVersion() == 6) {
972  stats_mgr6_->incrementCounter("latercvd", latercvd);
973  }
974  }
975  }
976  }
977 }
978 
979 uint64_t
981  const uint64_t msg_num) {
982  for (uint64_t i = 0; i < msg_num; ++i) {
983  if (!sendRequestFromAck(socket)) {
984  return (i);
985  }
986  }
987  return (msg_num);
988 }
989 
990 uint64_t
992  const uint32_t msg_type,
993  const uint64_t msg_num) {
994  for (uint64_t i = 0; i < msg_num; ++i) {
995  if (!sendMessageFromReply(msg_type, socket)) {
996  return (i);
997  }
998  }
999  return (msg_num);
1000 }
1001 
1002 void
1005  if (testDiags('a')) {
1006  // Print all command line parameters.
1007  options.printCommandLine();
1008  // Print MAC and DUID.
1009  std::cout << "Set MAC to " << vector2Hex(options.getMacTemplate(), "::")
1010  << std::endl;
1011  if (options.getDuidTemplate().size() > 0) {
1012  std::cout << "Set DUID to " << vector2Hex(options.getDuidTemplate()) << std::endl;
1013  }
1014  }
1015 }
1016 
1017 void
1018 TestControl::printTemplate(const uint8_t packet_type) const {
1019  std::string hex_buf;
1020  int arg_idx = 0;
1021  if (CommandOptions::instance().getIpVersion() == 4) {
1022  if (packet_type == DHCPREQUEST) {
1023  arg_idx = 1;
1024  }
1025  std::map<uint8_t, dhcp::Pkt4Ptr>::const_iterator pkt_it =
1026  template_packets_v4_.find(packet_type);
1027  if ((pkt_it != template_packets_v4_.end()) &&
1028  pkt_it->second) {
1029  const util::OutputBuffer& out_buf(pkt_it->second->getBuffer());
1030  const char* out_buf_data =
1031  static_cast<const char*>(out_buf.getData());
1032  std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
1033  hex_buf = vector2Hex(buf);
1034  }
1035  } else if (CommandOptions::instance().getIpVersion() == 6) {
1036  if (packet_type == DHCPV6_REQUEST) {
1037  arg_idx = 1;
1038  }
1039  std::map<uint8_t, dhcp::Pkt6Ptr>::const_iterator pkt_it =
1040  template_packets_v6_.find(packet_type);
1041  if (pkt_it != template_packets_v6_.end() &&
1042  pkt_it->second) {
1043  const util::OutputBuffer& out_buf(pkt_it->second->getBuffer());
1044  const char* out_buf_data =
1045  static_cast<const char*>(out_buf.getData());
1046  std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
1047  hex_buf = vector2Hex(buf);
1048  }
1049  }
1050  std::cout << "xid-offset=" << getTransactionIdOffset(arg_idx) << std::endl;
1051  std::cout << "random-offset=" << getRandomOffset(arg_idx) << std::endl;
1052  if (arg_idx > 0) {
1053  std::cout << "srvid-offset=" << getServerIdOffset() << std::endl;
1054  std::cout << "time-offset=" << getElapsedTimeOffset() << std::endl;
1055  std::cout << "ip-offset=" << getRequestedIpOffset() << std::endl;
1056  }
1057 
1058  std::cout << "contents: " << std::endl;
1059  int line_len = 32;
1060  int i = 0;
1061  while (line_len == 32) {
1062  if (hex_buf.length() - i < 32) {
1063  line_len = hex_buf.length() - i;
1064  };
1065  if (line_len > 0) {
1066  std::cout << setfill('0') << setw(4) << std::hex << i << std::dec
1067  << " " << hex_buf.substr(i, line_len) << std::endl;
1068  }
1069  i += 32;
1070  }
1071  std::cout << std::endl;
1072 }
1073 
1074 void
1077  if (options.getIpVersion() == 4) {
1080  } else if (options.getIpVersion() == 6) {
1083  }
1084 }
1085 
1086 void
1088  double rate = 0;
1090  std::string exchange_name = "4-way exchanges";
1091  if (options.getIpVersion() == 4) {
1092  StatsMgr4::ExchangeType xchg_type =
1093  options.getExchangeMode() == CommandOptions::DO_SA ?
1095  if (xchg_type == StatsMgr4::XCHG_DO) {
1096  exchange_name = "DISCOVER-OFFER";
1097  }
1098  double duration =
1099  stats_mgr4_->getTestPeriod().length().total_nanoseconds() / 1e9;
1100  rate = stats_mgr4_->getRcvdPacketsNum(xchg_type) / duration;
1101  } else if (options.getIpVersion() == 6) {
1102  StatsMgr6::ExchangeType xchg_type =
1103  options.getExchangeMode() == CommandOptions::DO_SA ?
1105  if (xchg_type == StatsMgr6::XCHG_SA) {
1106  exchange_name = options.isRapidCommit() ? "Solicit-Reply" :
1107  "Solicit-Advertise";
1108  }
1109  double duration =
1110  stats_mgr6_->getTestPeriod().length().total_nanoseconds() / 1e9;
1111  rate = stats_mgr6_->getRcvdPacketsNum(xchg_type) / duration;
1112  }
1113  std::ostringstream s;
1114  s << "***Rate statistics***" << std::endl;
1115  s << "Rate: " << rate << " " << exchange_name << "/second";
1116  if (options.getRate() > 0) {
1117  s << ", expected rate: " << options.getRate() << std::endl;
1118  }
1119 
1120  std::cout << s.str() << std::endl;
1121 }
1122 
1123 void
1126  int delay = options.getReportDelay();
1127  ptime now = microsec_clock::universal_time();
1128  time_period time_since_report(last_report_, now);
1129  if (time_since_report.length().total_seconds() >= delay) {
1130  if (options.getIpVersion() == 4) {
1131  stats_mgr4_->printIntermediateStats();
1132  } else if (options.getIpVersion() == 6) {
1133  stats_mgr6_->printIntermediateStats();
1134  }
1135  last_report_ = now;
1136  }
1137 }
1138 
1139 void
1141  printRate();
1143  if (options.getIpVersion() == 4) {
1144  if (!stats_mgr4_) {
1145  isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
1146  "hasn't been initialized");
1147  }
1148  stats_mgr4_->printStats();
1149  if (testDiags('i')) {
1150  stats_mgr4_->printCustomCounters();
1151  }
1152  } else if (options.getIpVersion() == 6) {
1153  if (!stats_mgr6_) {
1154  isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
1155  "hasn't been initialized");
1156  }
1157  stats_mgr6_->printStats();
1158  if (testDiags('i')) {
1159  stats_mgr6_->printCustomCounters();
1160  }
1161  }
1162 }
1163 
1164 std::string
1165 TestControl::vector2Hex(const std::vector<uint8_t>& vec,
1166  const std::string& separator /* ="" */) const {
1167  std::ostringstream stream;
1168  for (std::vector<uint8_t>::const_iterator it = vec.begin();
1169  it != vec.end();
1170  ++it) {
1171  if (it == vec.begin()) {
1172  stream << byte2Hex(*it);
1173  } else {
1174  stream << separator << byte2Hex(*it);
1175  }
1176  }
1177  return (stream.str());
1178 }
1179 
1180 void
1181 TestControl::readPacketTemplate(const std::string& file_name) {
1182  std::ifstream temp_file;
1183  temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate);
1184  if (!temp_file.is_open()) {
1185  isc_throw(BadValue, "unable to open template file " << file_name);
1186  }
1187  // Read template file contents.
1188  std::streampos temp_size = temp_file.tellg();
1189  if (temp_size == std::streampos(0)) {
1190  temp_file.close();
1191  isc_throw(OutOfRange, "the template file " << file_name << " is empty");
1192  }
1193  temp_file.seekg(0, ios::beg);
1194  std::vector<char> file_contents(temp_size);
1195  temp_file.read(&file_contents[0], temp_size);
1196  temp_file.close();
1197  // Spaces are allowed so we have to strip the contents
1198  // from them. In the same time we want to make sure that
1199  // apart from spaces the file contains hexadecimal digits
1200  // only.
1201  std::vector<char> hex_digits;
1202  for (size_t i = 0; i < file_contents.size(); ++i) {
1203  if (isxdigit(file_contents[i])) {
1204  hex_digits.push_back(file_contents[i]);
1205  } else if (!isxdigit(file_contents[i]) &&
1206  !isspace(file_contents[i])) {
1207  isc_throw(BadValue, "'" << file_contents[i] << "' is not a"
1208  " hexadecimal digit");
1209  }
1210  }
1211  // Expect even number of digits.
1212  if (hex_digits.size() % 2 != 0) {
1213  isc_throw(OutOfRange, "odd number of digits in template file");
1214  } else if (hex_digits.empty()) {
1215  isc_throw(OutOfRange, "template file " << file_name << " is empty");
1216  }
1217  std::vector<uint8_t> binary_stream;
1218  for (size_t i = 0; i < hex_digits.size(); i += 2) {
1219  stringstream s;
1220  s << "0x" << hex_digits[i] << hex_digits[i+1];
1221  int b;
1222  s >> std::hex >> b;
1223  binary_stream.push_back(static_cast<uint8_t>(b));
1224  }
1225  template_buffers_.push_back(binary_stream);
1226 }
1227 
1228 void
1230  const Pkt4Ptr& pkt4) {
1231  if (pkt4->getType() == DHCPOFFER) {
1232  Pkt4Ptr discover_pkt4(stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO,
1233  pkt4));
1234  CommandOptions::ExchangeMode xchg_mode =
1236  if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
1237  if (template_buffers_.size() < 2) {
1238  sendRequest4(socket, discover_pkt4, pkt4);
1239  } else {
1240  // @todo add defines for packet type index that can be
1241  // used to access template_buffers_.
1242  sendRequest4(socket, template_buffers_[1], discover_pkt4, pkt4);
1243  }
1244  }
1245  } else if (pkt4->getType() == DHCPACK) {
1246  // If received message is DHCPACK, we have to check if this is
1247  // a response to 4-way exchange. We'll match this packet with
1248  // a DHCPREQUEST sent as part of the 4-way exchanges.
1249  if (stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4)) {
1250  // The DHCPACK belongs to DHCPREQUEST-DHCPACK exchange type.
1251  // So, we may need to keep this DHCPACK in the storage if renews.
1252  // Note that, DHCPACK messages hold the information about
1253  // leases assigned. We use this information to renew.
1254  if (stats_mgr4_->hasExchangeStats(StatsMgr4::XCHG_RNA)) {
1255  // Renew messages are sent, because StatsMgr has the
1256  // specific exchange type specified. Let's append the DHCPACK.
1257  // message to a storage
1258  ack_storage_.append(pkt4);
1259  }
1260  // The DHCPACK message is not a server's response to the DHCPREQUEST
1261  // message sent within the 4-way exchange. It may be a response to a
1262  // renewal. In this case we first check if StatsMgr has exchange type
1263  // for renew specified, and if it has, if there is a corresponding
1264  // renew message for the received DHCPACK.
1265  } else if (stats_mgr4_->hasExchangeStats(StatsMgr4::XCHG_RNA)) {
1266  stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RNA, pkt4);
1267  }
1268  }
1269 }
1270 
1271 void
1273  const Pkt6Ptr& pkt6) {
1274  uint8_t packet_type = pkt6->getType();
1275  if (packet_type == DHCPV6_ADVERTISE) {
1276  Pkt6Ptr solicit_pkt6(stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_SA,
1277  pkt6));
1278  CommandOptions::ExchangeMode xchg_mode =
1280  if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
1281  // \todo check whether received ADVERTISE packet is sane.
1282  // We might want to check if STATUS_CODE option is non-zero
1283  // and if there is IAADR option in IA_NA.
1284  if (template_buffers_.size() < 2) {
1285  sendRequest6(socket, pkt6);
1286  } else {
1287  // @todo add defines for packet type index that can be
1288  // used to access template_buffers_.
1289  sendRequest6(socket, template_buffers_[1], pkt6);
1290  }
1291  }
1292  } else if (packet_type == DHCPV6_REPLY) {
1293  // If the received message is Reply, we have to find out which exchange
1294  // type the Reply message belongs to. It is doable by matching the Reply
1295  // transaction id with the transaction id of the sent Request, Renew
1296  // or Release. First we start with the Request.
1297  if (stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6)) {
1298  // The Reply belongs to Request-Reply exchange type. So, we may need
1299  // to keep this Reply in the storage if Renews or/and Releases are
1300  // being sent. Note that, Reply messages hold the information about
1301  // leases assigned. We use this information to construct Renew and
1302  // Release messages.
1303  if (stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RN) ||
1304  stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RL)) {
1305  // Renew or Release messages are sent, because StatsMgr has the
1306  // specific exchange type specified. Let's append the Reply
1307  // message to a storage.
1308  reply_storage_.append(pkt6);
1309  }
1310  // The Reply message is not a server's response to the Request message
1311  // sent within the 4-way exchange. It may be a response to the Renew
1312  // or Release message. In the if clause we first check if StatsMgr
1313  // has exchange type for Renew specified, and if it has, if there is
1314  // a corresponding Renew message for the received Reply. If not,
1315  // we check that StatsMgr has exchange type for Release specified,
1316  // as possibly the Reply has been sent in response to Release.
1317  } else if (!(stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RN) &&
1318  stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RN, pkt6)) &&
1319  stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RL)) {
1320  // At this point, it is only possible that the Reply has been sent
1321  // in response to a Release. Try to match the Reply with Release.
1322  stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RL, pkt6);
1323  }
1324  }
1325 }
1326 
1327 uint64_t
1329  bool receiving = true;
1330  uint64_t received = 0;
1331  while (receiving) {
1332  if (CommandOptions::instance().getIpVersion() == 4) {
1333  Pkt4Ptr pkt4;
1334  try {
1335  pkt4 = IfaceMgr::instance().receive4(0, getCurrentTimeout());
1336  } catch (const Exception& e) {
1337  std::cerr << "Failed to receive DHCPv4 packet: "
1338  << e.what() << std::endl;
1339  }
1340  if (!pkt4) {
1341  receiving = false;
1342  } else {
1343  ++received;
1344  if ((received > 1) && testDiags('i')) {
1345  stats_mgr4_->incrementCounter("multircvd");
1346  }
1347 
1350  pkt4->unpack();
1351  processReceivedPacket4(socket, pkt4);
1352  }
1353  } else if (CommandOptions::instance().getIpVersion() == 6) {
1354  Pkt6Ptr pkt6;
1355  try {
1356  pkt6 = IfaceMgr::instance().receive6(0, getCurrentTimeout());
1357  } catch (const Exception& e) {
1358  std::cerr << "Failed to receive DHCPv6 packet: "
1359  << e.what() << std::endl;
1360  }
1361  if (!pkt6) {
1362  receiving = false;
1363  } else {
1364  ++received;
1365  if ((received > 1) && testDiags('i')) {
1366  stats_mgr6_->incrementCounter("multircvd");
1367  }
1368 
1371  pkt6->unpack();
1372  processReceivedPacket6(socket, pkt6);
1373  }
1374  }
1375  }
1376  return (received);
1377 }
1378 
1379 void
1381  static bool factories_registered = false;
1382  if (!factories_registered) {
1383  // DHCP_MESSAGE_TYPE option factory.
1384  LibDHCP::OptionFactoryRegister(Option::V4,
1387  // DHCP_SERVER_IDENTIFIER option factory.
1388  LibDHCP::OptionFactoryRegister(Option::V4,
1391  // DHCP_PARAMETER_REQUEST_LIST option factory.
1392  LibDHCP::OptionFactoryRegister(Option::V4,
1395  }
1396  factories_registered = true;
1397 }
1398 
1399 void
1401  static bool factories_registered = false;
1402  if (!factories_registered) {
1403  // D60_ELAPSED_TIME
1404  LibDHCP::OptionFactoryRegister(Option::V6,
1407  // D6O_RAPID_COMMIT
1408  LibDHCP::OptionFactoryRegister(Option::V6,
1411  // D6O_ORO (option request option) factory.
1412  LibDHCP::OptionFactoryRegister(Option::V6,
1413  D6O_ORO,
1415  // D6O_CLIENTID option factory.
1416  LibDHCP::OptionFactoryRegister(Option::V6,
1417  D6O_CLIENTID,
1419  // D6O_SERVERID option factory.
1420  LibDHCP::OptionFactoryRegister(Option::V6,
1421  D6O_SERVERID,
1423  // D6O_IA_NA option factory.
1424  LibDHCP::OptionFactoryRegister(Option::V6,
1425  D6O_IA_NA,
1427 
1428  // D6O_IA_PD option factory.
1429  LibDHCP::OptionFactoryRegister(Option::V6,
1430  D6O_IA_PD,
1432 
1433 
1434  }
1435  factories_registered = true;
1436 }
1437 
1438 void
1441  switch(options.getIpVersion()) {
1442  case 4:
1444  break;
1445  case 6:
1447  break;
1448  default:
1449  isc_throw(InvalidOperation, "command line options have to be parsed "
1450  "before DHCP option factories can be registered");
1451  }
1452 }
1453 
1454 void
1458  basic_rate_control_.setRate(options.getRate());
1463 
1464  transid_gen_.reset();
1465  last_report_ = microsec_clock::universal_time();
1466  // Actual generators will have to be set later on because we need to
1467  // get command line parameters first.
1470  first_packet_serverid_.clear();
1471  interrupted_ = false;
1472 }
1473 
1474 int
1476  // Reset singleton state before test starts.
1477  reset();
1478 
1480  // Ip version is not set ONLY in case the command options
1481  // were not parsed. This surely means that parse() function
1482  // was not called prior to starting the test. This is fatal
1483  // error.
1484  if (options.getIpVersion() == 0) {
1486  "command options must be parsed before running a test");
1487  } else if (options.getIpVersion() == 4) {
1488  // Turn off packet queueing.
1489  IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, data::ElementPtr());
1491  } else {
1492  // Turn off packet queueing.
1493  IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, data::ElementPtr());
1495  }
1496 
1497  uint32_t clients_num = options.getClientsNum() == 0 ?
1498  1 : options.getClientsNum();
1500 
1501  // Diagnostics are command line options mainly.
1502  printDiagnostics();
1503  // Option factories have to be registered.
1505  TestControlSocket socket(openSocket());
1506  if (!socket.valid_) {
1507  isc_throw(Unexpected, "invalid socket descriptor");
1508  }
1509  // Initialize packet templates.
1511  // Initialize randomization seed.
1512  if (options.isSeeded()) {
1513  srandom(options.getSeed());
1514  } else {
1515  // Seed with current time.
1516  time_period duration(from_iso_string("20111231T235959"),
1517  microsec_clock::universal_time());
1518  srandom(duration.length().total_seconds()
1519  + duration.length().fractional_seconds());
1520  }
1521  // If user interrupts the program we will exit gracefully.
1522  signal(SIGINT, TestControl::handleInterrupt);
1523 
1524  // Preload server with the number of packets.
1525  sendPackets(socket, options.getPreload(), true);
1526 
1527  // Fork and run command specified with -w<wrapped-command>
1528  if (!options.getWrapped().empty()) {
1529  runWrapped();
1530  }
1531 
1532  // Initialize Statistics Manager. Release previous if any.
1534  for (;;) {
1535  // Calculate number of packets to be sent to stay
1536  // catch up with rate.
1537  uint64_t packets_due = basic_rate_control_.getOutboundMessageCount();
1539  if ((packets_due == 0) && testDiags('i')) {
1540  if (options.getIpVersion() == 4) {
1541  stats_mgr4_->incrementCounter("shortwait");
1542  } else if (options.getIpVersion() == 6) {
1543  stats_mgr6_->incrementCounter("shortwait");
1544  }
1545  }
1546 
1547  // @todo: set non-zero timeout for packets once we implement
1548  // microseconds timeout in IfaceMgr.
1549  receivePackets(socket);
1550 
1551  // If test period finished, maximum number of packet drops
1552  // has been reached or test has been interrupted we have to
1553  // finish the test.
1554  if (checkExitConditions()) {
1555  break;
1556  }
1557 
1558  if (!hasLateExitCommenced()) {
1559  // Initiate new DHCP packet exchanges.
1560  sendPackets(socket, packets_due);
1561  }
1562 
1563  // If -f<renew-rate> option was specified we have to check how many
1564  // Renew packets should be sent to catch up with a desired rate.
1565  if (options.getRenewRate() != 0) {
1566  uint64_t renew_packets_due =
1569 
1570  // Send multiple renews to satisfy the desired rate.
1571  if (options.getIpVersion() == 4) {
1572  sendMultipleRequests(socket, renew_packets_due);
1573  } else {
1574  sendMultipleMessages6(socket, DHCPV6_RENEW, renew_packets_due);
1575  }
1576  }
1577 
1578  // If -F<release-rate> option was specified we have to check how many
1579  // Release messages should be sent to catch up with a desired rate.
1580  if ((options.getIpVersion() == 6) && (options.getReleaseRate() != 0)) {
1581  uint64_t release_packets_due =
1584  // Send Release messages.
1585  sendMultipleMessages6(socket, DHCPV6_RELEASE, release_packets_due);
1586  }
1587 
1588  // Report delay means that user requested printing number
1589  // of sent/received/dropped packets repeatedly.
1590  if (options.getReportDelay() > 0) {
1592  }
1593 
1594  // If we are sending Renews to the server, the Reply packets are cached
1595  // so as leases for which we send Renews can be identified. The major
1596  // issue with this approach is that most of the time we are caching
1597  // more packets than we actually need. This function removes excessive
1598  // Reply messages to reduce the memory and CPU utilization. Note that
1599  // searches in the long list of Reply packets increases CPU utilization.
1601  }
1602  printStats();
1603 
1604  if (!options.getWrapped().empty()) {
1605  // true means that we execute wrapped command with 'stop' argument.
1606  runWrapped(true);
1607  }
1608 
1609  // Print packet timestamps
1610  if (testDiags('t')) {
1611  if (options.getIpVersion() == 4) {
1612  stats_mgr4_->printTimestamps();
1613  } else if (options.getIpVersion() == 6) {
1614  stats_mgr6_->printTimestamps();
1615  }
1616  }
1617 
1618  // Print server id.
1619  if (testDiags('s') && (first_packet_serverid_.size() > 0)) {
1620  std::cout << "Server id: " << vector2Hex(first_packet_serverid_) << std::endl;
1621  }
1622 
1623  // Diagnostics flag 'e' means show exit reason.
1624  if (testDiags('e')) {
1625  std::cout << "Interrupted" << std::endl;
1626  }
1627  // Print packet templates. Even if -T options have not been specified the
1628  // dynamically build packet will be printed if at least one has been sent.
1629  if (testDiags('T')) {
1630  printTemplates();
1631  }
1632 
1633  int ret_code = 0;
1634  // Check if any packet drops occurred.
1635  if (options.getIpVersion() == 4) {
1636  ret_code = stats_mgr4_->droppedPackets() ? 3 : 0;
1637  } else if (options.getIpVersion() == 6) {
1638  ret_code = stats_mgr6_->droppedPackets() ? 3 : 0;
1639  }
1640  return (ret_code);
1641 }
1642 
1643 void
1644 TestControl::runWrapped(bool do_stop /*= false */) const {
1646  if (!options.getWrapped().empty()) {
1647  pid_t pid = 0;
1648  signal(SIGCHLD, handleChild);
1649  pid = fork();
1650  if (pid < 0) {
1651  isc_throw(Unexpected, "unable to fork");
1652  } else if (pid == 0) {
1653  execlp(options.getWrapped().c_str(),
1654  do_stop ? "stop" : "start",
1655  NULL);
1656  }
1657  }
1658 }
1659 
1660 void
1662  if (testDiags('T')) {
1663  if (template_packets_v4_.find(pkt->getType()) == template_packets_v4_.end()) {
1664  template_packets_v4_[pkt->getType()] = pkt;
1665  }
1666  }
1667 }
1668 
1669 void
1671  if (testDiags('T')) {
1672  if (template_packets_v6_.find(pkt->getType()) == template_packets_v6_.end()) {
1673  template_packets_v6_[pkt->getType()] = pkt;
1674  }
1675  }
1676 }
1677 
1678 void
1680  const bool preload /*= false*/) {
1682  // Generate the MAC address to be passed in the packet.
1683  uint8_t randomized = 0;
1684  std::vector<uint8_t> mac_address = generateMacAddress(randomized);
1685  // Generate transaction id to be set for the new exchange.
1686  const uint32_t transid = generateTransid();
1687  Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, transid));
1688  if (!pkt4) {
1689  isc_throw(Unexpected, "failed to create DISCOVER packet");
1690  }
1691 
1692  // Delete the default Message Type option set by Pkt4
1693  pkt4->delOption(DHO_DHCP_MESSAGE_TYPE);
1694 
1695  // Set options: DHCP_MESSAGE_TYPE and DHCP_PARAMETER_REQUEST_LIST
1696  OptionBuffer buf_msg_type;
1697  buf_msg_type.push_back(DHCPDISCOVER);
1698  pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
1699  buf_msg_type));
1700  pkt4->addOption(Option::factory(Option::V4,
1702 
1703  // Set client's and server's ports as well as server's address,
1704  // and local (relay) address.
1705  setDefaults4(socket, pkt4);
1706 
1707  // Set hardware address
1708  pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address);
1709 
1710  // Set client identifier
1711  pkt4->addOption(generateClientId(pkt4->getHWAddr()));
1712 
1713  // Add any extra options that user may have specified.
1714  addExtraOpts(pkt4);
1715 
1716  pkt4->pack();
1717  IfaceMgr::instance().send(pkt4);
1718  if (!preload) {
1719  if (!stats_mgr4_) {
1720  isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
1721  "hasn't been initialized");
1722  }
1723  stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, pkt4);
1724  }
1725  saveFirstPacket(pkt4);
1726 }
1727 
1728 void
1730  const std::vector<uint8_t>& template_buf,
1731  const bool preload /* = false */) {
1733  // Get the first argument if multiple the same arguments specified
1734  // in the command line. First one refers to DISCOVER packets.
1735  const uint8_t arg_idx = 0;
1736  // Generate the MAC address to be passed in the packet.
1737  uint8_t randomized = 0;
1738  std::vector<uint8_t> mac_address = generateMacAddress(randomized);
1739  // Generate transaction id to be set for the new exchange.
1740  const uint32_t transid = generateTransid();
1741  // Get transaction id offset.
1742  size_t transid_offset = getTransactionIdOffset(arg_idx);
1743  // Get randomization offset.
1744  // We need to go back by HW_ETHER_LEN (MAC address length)
1745  // because this offset points to last octet of MAC address.
1746  size_t rand_offset = getRandomOffset(arg_idx) - HW_ETHER_LEN + 1;
1747  // Create temporary buffer with template contents. We will
1748  // modify this temporary buffer but we don't want to modify
1749  // the original template.
1750  std::vector<uint8_t> in_buf(template_buf.begin(),
1751  template_buf.end());
1752  // Check if we are not going out of bounds.
1753  if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
1754  isc_throw(OutOfRange, "randomization offset is out of bounds");
1755  }
1756  PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
1757  transid_offset,
1758  transid));
1759 
1760  // Replace MAC address in the template with actual MAC address.
1761  pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1762  // Create a packet from the temporary buffer.
1763  setDefaults4(socket, boost::static_pointer_cast<Pkt4>(pkt4));
1764  // Pack the input packet buffer to output buffer so as it can
1765  // be sent to server.
1766  pkt4->rawPack();
1767  IfaceMgr::instance().send(boost::static_pointer_cast<Pkt4>(pkt4));
1768  if (!preload) {
1769  if (!stats_mgr4_) {
1770  isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
1771  "hasn't been initialized");
1772  }
1773  // Update packet stats.
1774  stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO,
1775  boost::static_pointer_cast<Pkt4>(pkt4));
1776  }
1777  saveFirstPacket(pkt4);
1778 }
1779 
1780 bool
1782  // Update timestamp of last sent renewal.
1784 
1785  // Get one of the recorded DHCPACK messages.
1786  Pkt4Ptr ack = ack_storage_.getRandom();
1787  if (!ack) {
1788  return (false);
1789  }
1790 
1791  // Create message of the specified type.
1792  Pkt4Ptr msg = createRequestFromAck(ack);
1793  setDefaults4(socket, msg);
1794 
1795  // Add any extra options that user may have specified.
1796  addExtraOpts(msg);
1797 
1798  msg->pack();
1799  // And send it.
1800  IfaceMgr::instance().send(msg);
1801  if (!stats_mgr4_) {
1802  isc_throw(Unexpected, "Statistics Manager for DHCPv4 "
1803  "hasn't been initialized");
1804  }
1805  stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RNA, msg);
1806  return (true);
1807 }
1808 
1809 
1810 bool
1811 TestControl::sendMessageFromReply(const uint16_t msg_type,
1812  const TestControlSocket& socket) {
1813  // We only permit Release or Renew messages to be sent using this function.
1814  if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
1815  isc_throw(isc::BadValue, "invalid message type " << msg_type
1816  << " to be sent, expected DHCPV6_RENEW or DHCPV6_RELEASE");
1817  }
1818  // We track the timestamp of last Release and Renew in different variables.
1819  if (msg_type == DHCPV6_RENEW) {
1821  } else {
1823  }
1824  Pkt6Ptr reply = reply_storage_.getRandom();
1825  if (!reply) {
1826  return (false);
1827  }
1828  // Prepare the message of the specified type.
1829  Pkt6Ptr msg = createMessageFromReply(msg_type, reply);
1830  setDefaults6(socket, msg);
1831 
1832  // Add any extra options that user may have specified.
1833  addExtraOpts(msg);
1834 
1835  msg->pack();
1836  // And send it.
1837  IfaceMgr::instance().send(msg);
1838  if (!stats_mgr6_) {
1839  isc_throw(Unexpected, "Statistics Manager for DHCPv6 "
1840  "hasn't been initialized");
1841  }
1842  stats_mgr6_->passSentPacket((msg_type == DHCPV6_RENEW ? StatsMgr6::XCHG_RN
1843  : StatsMgr6::XCHG_RL), msg);
1844  return (true);
1845 }
1846 
1847 void
1849  const dhcp::Pkt4Ptr& discover_pkt4,
1850  const dhcp::Pkt4Ptr& offer_pkt4) {
1851  // Use the same transaction id as the one used in the discovery packet.
1852  const uint32_t transid = discover_pkt4->getTransid();
1853  Pkt4Ptr pkt4(new Pkt4(DHCPREQUEST, transid));
1854 
1855  // Use first flags indicates that we want to use the server
1856  // id captured in first packet.
1857  if (CommandOptions::instance().isUseFirst() &&
1858  (first_packet_serverid_.size() > 0)) {
1859  pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_SERVER_IDENTIFIER,
1861  } else {
1862  OptionPtr opt_serverid =
1863  offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
1864  if (!opt_serverid) {
1865  isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
1866  << "in OFFER message");
1867  }
1868  if (stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) {
1869  first_packet_serverid_ = opt_serverid->getData();
1870  }
1871  pkt4->addOption(opt_serverid);
1872  }
1873 
1875  asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
1876  if (!yiaddr.isV4()) {
1877  isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
1878  " IPv4 address");
1879  }
1880  OptionPtr opt_requested_address =
1882  OptionBuffer()));
1883  opt_requested_address->setUint32(yiaddr.toUint32());
1884  pkt4->addOption(opt_requested_address);
1885  OptionPtr opt_parameter_list =
1886  Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST);
1887  pkt4->addOption(opt_parameter_list);
1888  // Set client's and server's ports as well as server's address,
1889  // and local (relay) address.
1890  setDefaults4(socket, pkt4);
1891 
1892  // Add any extra options that user may have specified.
1893  addExtraOpts(pkt4);
1894 
1895  // Set hardware address
1896  pkt4->setHWAddr(offer_pkt4->getHWAddr());
1897  // Set client id.
1898  pkt4->addOption(generateClientId(pkt4->getHWAddr()));
1899  // Set elapsed time.
1900  uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1901  pkt4->setSecs(static_cast<uint16_t>(elapsed_time / 1000));
1902  // Prepare on wire data to send.
1903  pkt4->pack();
1904  IfaceMgr::instance().send(pkt4);
1905  if (!stats_mgr4_) {
1906  isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
1907  "hasn't been initialized");
1908  }
1909  stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA, pkt4);
1910  saveFirstPacket(pkt4);
1911 }
1912 
1913 void
1915  const std::vector<uint8_t>& template_buf,
1916  const dhcp::Pkt4Ptr& discover_pkt4,
1917  const dhcp::Pkt4Ptr& offer_pkt4) {
1918  // Get the second argument if multiple the same arguments specified
1919  // in the command line. Second one refers to REQUEST packets.
1920  const uint8_t arg_idx = 1;
1921  // Use the same transaction id as the one used in the discovery packet.
1922  const uint32_t transid = discover_pkt4->getTransid();
1923  // Get transaction id offset.
1924  size_t transid_offset = getTransactionIdOffset(arg_idx);
1925  // Get the offset of MAC's last octet.
1926  // We need to go back by HW_ETHER_LEN (MAC address length)
1927  // because this offset points to last octet of MAC address.
1928  size_t rand_offset = getRandomOffset(arg_idx) - HW_ETHER_LEN + 1;
1929  // Create temporary buffer from the template.
1930  std::vector<uint8_t> in_buf(template_buf.begin(),
1931  template_buf.end());
1932  // Check if given randomization offset is not out of bounds.
1933  if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
1934  isc_throw(OutOfRange, "randomization offset is out of bounds");
1935  }
1936 
1937  // Create packet from the temporary buffer.
1938  PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
1939  transid_offset,
1940  transid));
1941 
1942  // Set hardware address from OFFER packet received.
1943  HWAddrPtr hwaddr = offer_pkt4->getHWAddr();
1944  std::vector<uint8_t> mac_address(HW_ETHER_LEN, 0);
1945  uint8_t hw_len = hwaddr->hwaddr_.size();
1946  if (hw_len != 0) {
1947  memcpy(&mac_address[0], &hwaddr->hwaddr_[0],
1948  hw_len > HW_ETHER_LEN ? HW_ETHER_LEN : hw_len);
1949  }
1950  pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1951 
1952  // Set elapsed time.
1953  size_t elp_offset = getElapsedTimeOffset();
1954  uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1955  pkt4->writeValueAt<uint16_t>(elp_offset,
1956  static_cast<uint16_t>(elapsed_time / 1000));
1957 
1958  // Get the actual server id offset.
1959  size_t sid_offset = getServerIdOffset();
1960  // Use first flags indicates that we want to use the server
1961  // id captured in first packet.
1962  if (CommandOptions::instance().isUseFirst() &&
1963  (first_packet_serverid_.size() > 0)) {
1964  boost::shared_ptr<LocalizedOption>
1965  opt_serverid(new LocalizedOption(Option::V4,
1968  sid_offset));
1969  pkt4->addOption(opt_serverid);
1970  } else {
1971  // Copy the contents of server identifier received in
1972  // OFFER packet to put this into REQUEST.
1973  OptionPtr opt_serverid_offer =
1974  offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
1975  if (!opt_serverid_offer) {
1976  isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
1977  << "in OFFER message");
1978  }
1979  boost::shared_ptr<LocalizedOption>
1980  opt_serverid(new LocalizedOption(Option::V4,
1982  opt_serverid_offer->getData(),
1983  sid_offset));
1984  pkt4->addOption(opt_serverid);
1985  if (stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) {
1986  first_packet_serverid_ = opt_serverid_offer->getData();
1987  }
1988  }
1989 
1991  asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
1992  if (!yiaddr.isV4()) {
1993  isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
1994  " IPv4 address");
1995  }
1996 
1997  // Get the actual offset of requested ip.
1998  size_t rip_offset = getRequestedIpOffset();
1999  // Place requested IP option at specified position (rip_offset).
2000  boost::shared_ptr<LocalizedOption>
2001  opt_requested_ip(new LocalizedOption(Option::V4,
2003  OptionBuffer(),
2004  rip_offset));
2005  // The IOAddress is convertible to uint32_t and returns exactly what we need.
2006  opt_requested_ip->setUint32(yiaddr.toUint32());
2007  pkt4->addOption(opt_requested_ip);
2008 
2009  setDefaults4(socket, boost::static_pointer_cast<Pkt4>(pkt4));
2010 
2011  // Add any extra options that user may have specified.
2012  addExtraOpts(pkt4);
2013 
2014  // Prepare on-wire data.
2015  pkt4->rawPack();
2016  IfaceMgr::instance().send(boost::static_pointer_cast<Pkt4>(pkt4));
2017  if (!stats_mgr4_) {
2018  isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
2019  "hasn't been initialized");
2020  }
2021  // Update packet stats.
2022  stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA,
2023  boost::static_pointer_cast<Pkt4>(pkt4));
2024  saveFirstPacket(pkt4);
2025 }
2026 
2027 void
2029  const Pkt6Ptr& advertise_pkt6) {
2030  const uint32_t transid = generateTransid();
2031  Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid));
2032  // Set elapsed time.
2033  OptionPtr opt_elapsed_time =
2034  Option::factory(Option::V6, D6O_ELAPSED_TIME);
2035  pkt6->addOption(opt_elapsed_time);
2036  // Set client id.
2037  OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID);
2038  if (!opt_clientid) {
2039  isc_throw(Unexpected, "client id not found in received packet");
2040  }
2041  pkt6->addOption(opt_clientid);
2042 
2043  // Use first flags indicates that we want to use the server
2044  // id captured in first packet.
2045  if (CommandOptions::instance().isUseFirst() &&
2046  (first_packet_serverid_.size() > 0)) {
2047  pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID,
2049  } else {
2050  OptionPtr opt_serverid = advertise_pkt6->getOption(D6O_SERVERID);
2051  if (!opt_serverid) {
2052  isc_throw(Unexpected, "server id not found in received packet");
2053  }
2054  if (stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) {
2055  first_packet_serverid_ = opt_serverid->getData();
2056  }
2057  pkt6->addOption(opt_serverid);
2058  }
2059 
2060  // Copy IA_NA or IA_PD option from the Advertise message to the Request
2061  // message being sent to the server. This will throw exception if the
2062  // option to be copied is not found. Note that this function will copy
2063  // one of IA_NA or IA_PD options, depending on the lease-type value
2064  // specified in the command line.
2065  copyIaOptions(advertise_pkt6, pkt6);
2066 
2067  // Set default packet data.
2068  setDefaults6(socket, pkt6);
2069 
2070  // Add any extra options that user may have specified.
2071  addExtraOpts(pkt6);
2072 
2073  // Prepare on-wire data.
2074  pkt6->pack();
2075  IfaceMgr::instance().send(pkt6);
2076  if (!stats_mgr6_) {
2077  isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
2078  "hasn't been initialized");
2079  }
2080  stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RR, pkt6);
2081  saveFirstPacket(pkt6);
2082 }
2083 
2084 void
2086  const std::vector<uint8_t>& template_buf,
2087  const Pkt6Ptr& advertise_pkt6) {
2088  // Get the second argument if multiple the same arguments specified
2089  // in the command line. Second one refers to REQUEST packets.
2090  const uint8_t arg_idx = 1;
2091  // Generate transaction id.
2092  const uint32_t transid = generateTransid();
2093  // Get transaction id offset.
2094  size_t transid_offset = getTransactionIdOffset(arg_idx);
2095  PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
2096  transid_offset, transid));
2097  // Set elapsed time.
2098  size_t elp_offset = getElapsedTimeOffset();
2099  boost::shared_ptr<LocalizedOption>
2100  opt_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME,
2101  OptionBuffer(), elp_offset));
2102  pkt6->addOption(opt_elapsed_time);
2103 
2104  // Get the actual server id offset.
2105  size_t sid_offset = getServerIdOffset();
2106  // Use first flags indicates that we want to use the server
2107  // id captured in first packet.
2108  if (CommandOptions::instance().isUseFirst() &&
2109  (first_packet_serverid_.size() > 0)) {
2110  boost::shared_ptr<LocalizedOption>
2111  opt_serverid(new LocalizedOption(Option::V6,
2112  D6O_SERVERID,
2114  sid_offset));
2115  pkt6->addOption(opt_serverid);
2116 
2117  } else {
2118  // Copy the contents of server identifier received in
2119  // ADVERTISE packet to put this into REQUEST.
2120  OptionPtr opt_serverid_advertise =
2121  advertise_pkt6->getOption(D6O_SERVERID);
2122  if (!opt_serverid_advertise) {
2123  isc_throw(BadValue, "there is no SERVERID option "
2124  << "in ADVERTISE message");
2125  }
2126  boost::shared_ptr<LocalizedOption>
2127  opt_serverid(new LocalizedOption(Option::V6,
2128  D6O_SERVERID,
2129  opt_serverid_advertise->getData(),
2130  sid_offset));
2131  pkt6->addOption(opt_serverid);
2132  if (stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) {
2133  first_packet_serverid_ = opt_serverid_advertise->getData();
2134  }
2135  }
2136  // Set IA_NA
2137  boost::shared_ptr<Option6IA> opt_ia_na_advertise =
2138  boost::static_pointer_cast<Option6IA>(advertise_pkt6->getOption(D6O_IA_NA));
2139  if (!opt_ia_na_advertise) {
2140  isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
2141  "packet");
2142  }
2143  size_t addr_offset = getRequestedIpOffset();
2144  boost::shared_ptr<LocalizedOption>
2145  opt_ia_na(new LocalizedOption(opt_ia_na_advertise, addr_offset));
2146  if (!opt_ia_na->valid()) {
2147  isc_throw(BadValue, "Option IA_NA in advertise packet is invalid");
2148  }
2149  pkt6->addOption(opt_ia_na);
2150  // Set server id.
2151  OptionPtr opt_serverid_advertise = advertise_pkt6->getOption(D6O_SERVERID);
2152  if (!opt_serverid_advertise) {
2153  isc_throw(Unexpected, "DHCPV6 SERVERID option not found in received "
2154  "packet");
2155  }
2156  size_t srvid_offset = getServerIdOffset();
2157  boost::shared_ptr<LocalizedOption>
2158  opt_serverid(new LocalizedOption(Option::V6, D6O_SERVERID,
2159  opt_serverid_advertise->getData(),
2160  srvid_offset));
2161  pkt6->addOption(opt_serverid);
2162  // Get randomization offset.
2163  size_t rand_offset = getRandomOffset(arg_idx);
2164  OptionPtr opt_clientid_advertise = advertise_pkt6->getOption(D6O_CLIENTID);
2165  if (!opt_clientid_advertise) {
2166  isc_throw(Unexpected, "DHCPV6 CLIENTID option not found in received packet");
2167  }
2168  rand_offset -= (opt_clientid_advertise->len() - 1);
2169  // Set client id.
2170  boost::shared_ptr<LocalizedOption>
2171  opt_clientid(new LocalizedOption(Option::V6, D6O_CLIENTID,
2172  opt_clientid_advertise->getData(),
2173  rand_offset));
2174  pkt6->addOption(opt_clientid);
2175  // Set default packet data.
2176  setDefaults6(socket, pkt6);
2177 
2178  // Add any extra options that user may have specified.
2179  addExtraOpts(pkt6);
2180 
2181  // Prepare on wire data.
2182  pkt6->rawPack();
2183  // Send packet.
2184  IfaceMgr::instance().send(pkt6);
2185  if (!stats_mgr6_) {
2186  isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
2187  "hasn't been initialized");
2188  }
2189  // Update packet stats.
2190  stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RR, pkt6);
2191 
2192  // When 'T' diagnostics flag is specified it means that user requested
2193  // printing packet contents. It will be just one (first) packet which
2194  // contents will be printed. Here we check if this packet has been already
2195  // collected. If it hasn't we save this packet so as we can print its
2196  // contents when test is finished.
2197  if (testDiags('T') &&
2200  }
2201 }
2202 
2203 void
2205  const bool preload /*= false*/) {
2207  // Generate DUID to be passed to the packet
2208  uint8_t randomized = 0;
2209  std::vector<uint8_t> duid = generateDuid(randomized);
2210  // Generate transaction id to be set for the new exchange.
2211  const uint32_t transid = generateTransid();
2212  Pkt6Ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
2213  if (!pkt6) {
2214  isc_throw(Unexpected, "failed to create SOLICIT packet");
2215  }
2216  pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
2217  if (CommandOptions::instance().isRapidCommit()) {
2218  pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT));
2219  }
2220  pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
2221  pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
2222 
2223  // Depending on the lease-type option specified, we should request
2224  // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD) or both.
2225 
2226  // IA_NA
2227  if (CommandOptions::instance().getLeaseType()
2229  pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
2230  }
2231  // IA_PD
2232  if (CommandOptions::instance().getLeaseType()
2233  .includes(CommandOptions::LeaseType::PREFIX)) {
2234  pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
2235  }
2236 
2237  setDefaults6(socket, pkt6);
2238 
2239  // Add any extra options that user may have specified.
2240  addExtraOpts(pkt6);
2241 
2242  pkt6->pack();
2243  IfaceMgr::instance().send(pkt6);
2244  if (!preload) {
2245  if (!stats_mgr6_) {
2246  isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
2247  "hasn't been initialized");
2248  }
2249  stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6);
2250  }
2251 
2252  saveFirstPacket(pkt6);
2253 }
2254 
2255 void
2257  const std::vector<uint8_t>& template_buf,
2258  const bool preload /*= false*/) {
2260  const int arg_idx = 0;
2261  // Get transaction id offset.
2262  size_t transid_offset = getTransactionIdOffset(arg_idx);
2263  // Generate transaction id to be set for the new exchange.
2264  const uint32_t transid = generateTransid();
2265  // Create packet.
2266  PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
2267  transid_offset, transid));
2268  if (!pkt6) {
2269  isc_throw(Unexpected, "failed to create SOLICIT packet");
2270  }
2271  size_t rand_offset = getRandomOffset(arg_idx);
2272  // randomized will pick number of bytes randomized so we can
2273  // just use part of the generated duid and substitute a few bytes
2275  uint8_t randomized = 0;
2276  std::vector<uint8_t> duid = generateDuid(randomized);
2277  if (rand_offset > template_buf.size()) {
2278  isc_throw(OutOfRange, "randomization offset is out of bounds");
2279  }
2280  // Store random part of the DUID into the packet.
2281  pkt6->writeAt(rand_offset - randomized + 1,
2282  duid.end() - randomized, duid.end());
2283 
2284  // Prepare on-wire data.
2285  pkt6->rawPack();
2286  setDefaults6(socket, pkt6);
2287 
2288  // Add any extra options that user may have specified.
2289  addExtraOpts(pkt6);
2290 
2291  // Send solicit packet.
2292  IfaceMgr::instance().send(pkt6);
2293  if (!preload) {
2294  if (!stats_mgr6_) {
2295  isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
2296  "hasn't been initialized");
2297  }
2298  // Update packet stats.
2299  stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6);
2300  }
2301  saveFirstPacket(pkt6);
2302 }
2303 
2304 
2305 void
2307  const Pkt4Ptr& pkt) {
2309  // Interface name.
2310  IfacePtr iface = IfaceMgr::instance().getIface(socket.ifindex_);
2311  if (iface == NULL) {
2312  isc_throw(BadValue, "unable to find interface with given index");
2313  }
2314  pkt->setIface(iface->getName());
2315  // Interface index.
2316  pkt->setIndex(socket.ifindex_);
2317  // Local client's port (68)
2318  pkt->setLocalPort(DHCP4_CLIENT_PORT);
2319  // Server's port (67)
2320  pkt->setRemotePort(DHCP4_SERVER_PORT);
2321  // The remote server's name or IP.
2322  pkt->setRemoteAddr(IOAddress(options.getServerName()));
2323  // Set local address.
2324  pkt->setLocalAddr(IOAddress(socket.addr_));
2325  // Set relay (GIADDR) address to local address.
2326  pkt->setGiaddr(IOAddress(socket.addr_));
2327  // Pretend that we have one relay (which is us).
2328  pkt->setHops(1);
2329 }
2330 
2331 void
2333  const Pkt6Ptr& pkt) {
2335  // Interface name.
2336  IfacePtr iface = IfaceMgr::instance().getIface(socket.ifindex_);
2337  if (iface == NULL) {
2338  isc_throw(BadValue, "unable to find interface with given index");
2339  }
2340  pkt->setIface(iface->getName());
2341  // Interface index.
2342  pkt->setIndex(socket.ifindex_);
2343  // Local client's port (547)
2344  pkt->setLocalPort(DHCP6_CLIENT_PORT);
2345  // Server's port (548)
2346  pkt->setRemotePort(DHCP6_SERVER_PORT);
2347  // Set local address.
2348  pkt->setLocalAddr(socket.addr_);
2349  // The remote server's name or IP.
2350  pkt->setRemoteAddr(IOAddress(options.getServerName()));
2351 
2352  // only act as a relay agent when told so.
2353  // TODO: support more level of encapsulation, at the moment we only support
2354  // one, via -A1 option.
2355  if (options.isUseRelayedV6()) {
2356  Pkt6::RelayInfo relay_info;
2357  relay_info.msg_type_ = DHCPV6_RELAY_FORW;
2358  relay_info.hop_count_ = 1;
2359  relay_info.linkaddr_ = IOAddress(socket.addr_);
2360  relay_info.peeraddr_ = IOAddress(socket.addr_);
2361  pkt->addRelayInfo(relay_info);
2362  }
2363 }
2364 
2365 void
2367  // All all extra options that the user may have specified
2369  const dhcp::OptionCollection& extra_opts = options.getExtraOpts();
2370  for (auto entry : extra_opts) {
2371  pkt->addOption(entry.second);
2372  }
2373 }
2374 
2375 void
2377  // All all extra options that the user may have specified
2379  const dhcp::OptionCollection& extra_opts = options.getExtraOpts();
2380  for (auto entry : extra_opts) {
2381  pkt->addOption(entry.second);
2382  }
2383 }
2384 
2385 bool
2386 TestControl::testDiags(const char diag) const {
2387  std::string diags(CommandOptions::instance().getDiags());
2388  if (diags.find(diag) != std::string::npos) {
2389  return (true);
2390  }
2391  return (false);
2392 }
2393 
2394 } // namespace perfdhcp
2395 } // namespace isc
isc::perfdhcp::TestControl::run
int run()
brief\ Run performance test.
Definition: test_control.cc:1475
isc::dhcp::Pkt6
Represents a DHCPv6 packet.
Definition: pkt6.h:44
isc::perfdhcp::TestControl::TestControlSocket
Socket wrapper structure.
Definition: test_control.h:160
isc::perfdhcp::PerfPkt6Ptr
boost::shared_ptr< PerfPkt6 > PerfPkt6Ptr
Definition: perf_pkt6.h:126
isc::perfdhcp::TestControl::byte2Hex
std::string byte2Hex(const uint8_t b) const
Convert binary value to hex string.
Definition: test_control.cc:224
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
isc::perfdhcp::TestControl::getTransactionIdOffset
int getTransactionIdOffset(const int arg_idx) const
Return transaction id offset in a packet.
Definition: test_control.cc:752
isc::dhcp::Pkt6::RelayInfo::hop_count_
uint8_t hop_count_
number of traversed relays (up to 32)
Definition: pkt6.h:95
isc::perfdhcp::TestControl::initializeStatsMgr
void initializeStatsMgr()
Initializes Statistics Manager.
Definition: test_control.cc:788
isc::data::copy
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1114
isc::perfdhcp::CommandOptions::printCommandLine
void printCommandLine() const
Print command line arguments.
Definition: command_options.cc:920
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
isc::perfdhcp::StatsMgr::XCHG_RN
@ XCHG_RN
DHCPv6 RENEW-REPLY.
Definition: bin/perfdhcp/stats_mgr.h:121
isc::perfdhcp::CommandOptions::DO_SA
@ DO_SA
Definition: command_options.h:105
isc::perfdhcp::CommandOptions::getServerIdOffset
int getServerIdOffset() const
Returns template offset for server-ID.
Definition: command_options.h:324
isc::perfdhcp::CommandOptions::instance
static CommandOptions & instance()
CommandOptions is a singleton class.
Definition: command_options.cc:99
isc::perfdhcp::TestControl::StatsMgr4
StatsMgr< dhcp::Pkt4 > StatsMgr4
Statistics Manager for DHCPv4.
Definition: test_control.h:125
isc::perfdhcp::TestControl::StatsMgr6Ptr
boost::shared_ptr< StatsMgr6 > StatsMgr6Ptr
Pointer to Statistics Manager for DHCPv6.
Definition: test_control.h:131
isc::perfdhcp::StatsMgr::XCHG_RNA
@ XCHG_RNA
DHCPv4 REQUEST-ACK (renewal)
Definition: bin/perfdhcp/stats_mgr.h:118
isc::perfdhcp::RateControl
A message sending rate control class for perfdhcp.
Definition: rate_control.h:38
isc::dhcp::SocketInfo::addr_
isc::asiolink::IOAddress addr_
Definition: socket_info.h:21
iface_mgr.h
isc::perfdhcp::TestControl::sendMultipleMessages6
uint64_t sendMultipleMessages6(const TestControlSocket &socket, const uint32_t msg_type, const uint64_t msg_num)
Send number of DHCPv6 Renew or Release messages to the server.
Definition: test_control.cc:991
isc::perfdhcp::LocalizedOption
DHCP option at specific offset.
Definition: localized_option.h:37
isc::perfdhcp::TestControl::setMacAddrGenerator
void setMacAddrGenerator(const NumberGeneratorPtr &generator)
Set new MAC address generator.
Definition: test_control.h:281
isc::perfdhcp::TestControl::TestControl
TestControl()
Default constructor.
Definition: test_control.cc:141
isc::perfdhcp::TestControl::stats_mgr4_
StatsMgr4Ptr stats_mgr4_
Statistics Manager 4.
Definition: test_control.h:1148
isc::perfdhcp::CommandOptions::getExchangeMode
ExchangeMode getExchangeMode() const
Returns packet exchange mode.
Definition: command_options.h:142
isc::perfdhcp::TestControl::sendRequestFromAck
bool sendRequestFromAck(const TestControlSocket &socket)
Send DHCPv4 renew (DHCPREQUEST) using specified socket.
Definition: test_control.cc:1781
isc::perfdhcp::TestControl::TestControlSocket::ifindex_
uint16_t ifindex_
Interface index.
Definition: test_control.h:162
isc::perfdhcp::late_exit_target_time_
ptime late_exit_target_time_
Definition: test_control.cc:45
isc::perfdhcp::TestControl::copyIaOptions
void copyIaOptions(const dhcp::Pkt6Ptr &pkt_from, dhcp::Pkt6Ptr &pkt_to)
Copies IA_NA or IA_PD option from one packet to another.
Definition: test_control.cc:194
isc::perfdhcp::TestControl::printDiagnostics
void printDiagnostics() const
Print main diagnostics data.
Definition: test_control.cc:1003
isc::perfdhcp::TestControl::checkExitConditions
bool checkExitConditions() const
Check if test exit conditions fulfilled.
Definition: test_control.cc:233
libdhcp++.h
io_address.h
isc::perfdhcp::TestControl::receivePackets
uint64_t receivePackets(const TestControlSocket &socket)
Receive DHCPv4 or DHCPv6 packets from the server.
Definition: test_control.cc:1328
option6_ia.h
D6O_IA_PD
@ D6O_IA_PD
Definition: dhcp6.h:45
D6O_ELAPSED_TIME
@ D6O_ELAPSED_TIME
Definition: dhcp6.h:28
isc::dhcp::DHCPDISCOVER
@ DHCPDISCOVER
Definition: dhcp4.h:228
isc::perfdhcp::TestControl::macaddr_gen_
NumberGeneratorPtr macaddr_gen_
Numbers generator for MAC address.
Definition: test_control.h:1155
isc::perfdhcp::TestControl::vector2Hex
std::string vector2Hex(const std::vector< uint8_t > &vec, const std::string &separator="") const
Convert vector in hexadecimal string.
Definition: test_control.cc:1165
isc::perfdhcp::CommandOptions::MacAddrsVector
std::vector< std::vector< uint8_t > > MacAddrsVector
A vector holding MAC addresses.
Definition: command_options.h:29
isc::dhcp::Pkt6::RelayInfo::peeraddr_
isc::asiolink::IOAddress peeraddr_
fixed field in relay-forw/relay-reply
Definition: pkt6.h:97
isc::dhcp::DHO_SUBNET_MASK
@ DHO_SUBNET_MASK
Definition: dhcp4.h:70
isc::perfdhcp::CommandOptions::getRandomOffset
std::vector< int > getRandomOffset() const
Returns template offsets for rnd.
Definition: command_options.h:314
DHCPV6_RENEW
@ DHCPV6_RENEW
Definition: dhcp6.h:217
isc::dhcp::DHO_DOMAIN_NAME_SERVERS
@ DHO_DOMAIN_NAME_SERVERS
Definition: dhcp4.h:75
isc::perfdhcp::CommandOptions::isUseRelayedV6
bool isUseRelayedV6() const
Check if generated DHCPv6 messages should appear as relayed.
Definition: command_options.h:284
isc::perfdhcp::TestControl::template_packets_v6_
std::map< uint8_t, dhcp::Pkt6Ptr > template_packets_v6_
Definition: test_control.h:1166
isc::perfdhcp::CommandOptions::getTemplateFiles
std::vector< std::string > getTemplateFiles() const
Returns template file names.
Definition: command_options.h:289
isc::perfdhcp::TestControl::generateDuid
std::vector< uint8_t > generateDuid(uint8_t &randomized)
Generate DUID.
Definition: test_control.cc:592
isc::perfdhcp::TestControl::setDefaults6
void setDefaults6(const TestControlSocket &socket, const dhcp::Pkt6Ptr &pkt)
Set default DHCPv6 packet parameters.
Definition: test_control.cc:2332
isc::perfdhcp::StatsMgr::ExchangeType
ExchangeType
DHCP packet exchange types.
Definition: bin/perfdhcp/stats_mgr.h:115
isc::perfdhcp::CommandOptions::isInterface
bool isInterface() const
Checks if interface name was used.
Definition: command_options.h:234
isc::perfdhcp::TestControl::registerOptionFactories6
void registerOptionFactories6() const
Register option factory functions for DHCPv6.
Definition: test_control.cc:1400
isc::perfdhcp::TestControl::printRate
void printRate() const
Print rate statistics.
Definition: test_control.cc:1087
isc::perfdhcp::TestControl::testDiags
bool testDiags(const char diag) const
Find if diagnostic flag has been set.
Definition: test_control.cc:2386
isc::perfdhcp::TestControl::getCurrentTimeout
uint32_t getCurrentTimeout() const
Returns a timeout for packet reception.
Definition: test_control.cc:639
isc::perfdhcp::TestControl::getElapsedTime
uint32_t getElapsedTime(const T &pkt1, const T &pkt2)
Calculate elapsed time between two packets.
Definition: test_control.cc:680
isc::perfdhcp::TestControl::registerOptionFactories
void registerOptionFactories() const
Register option factory functions for DHCPv4 or DHCPv6.
Definition: test_control.cc:1439
isc::perfdhcp::TestControl::runWrapped
void runWrapped(bool do_stop=false) const
Run wrapped command.
Definition: test_control.cc:1644
isc::perfdhcp::CommandOptions::getRequestedIpOffset
int getRequestedIpOffset() const
Returns template offset for requested IP.
Definition: command_options.h:329
isc::perfdhcp::CommandOptions::getRenewRate
int getRenewRate() const
Returns a rate at which DHCPv6 Renew messages are sent.
Definition: command_options.h:157
isc::perfdhcp::CommandOptions::DORA_SARR
@ DORA_SARR
Definition: command_options.h:106
isc::perfdhcp::CommandOptions::getMaxDropPercentage
std::vector< double > getMaxDropPercentage() const
Returns maximal percentage of drops.
Definition: command_options.h:221
isc::perfdhcp::RateControl::setAggressivity
void setAggressivity(const int aggressivity)
Sets the value of aggressivity.
Definition: rate_control.cc:123
DHCPV6_REQUEST
@ DHCPV6_REQUEST
Definition: dhcp6.h:215
isc::dhcp::OptionCollection
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition: option.h:41
isc::perfdhcp::TestControl::handleInterrupt
static void handleInterrupt(int sig)
Handle interrupt signal.
Definition: test_control.cc:770
perf_pkt6.h
D6O_NAME_SERVERS
@ D6O_NAME_SERVERS
Definition: dhcp6.h:43
isc::perfdhcp::CommandOptions::ExchangeMode
ExchangeMode
2-way (cmd line param -i) or 4-way exchanges
Definition: command_options.h:104
isc::perfdhcp::TestControl::TemplateBuffer
std::vector< uint8_t > TemplateBuffer
Packet template buffer.
Definition: test_control.h:135
isc::perfdhcp::TestControl::hasLateExitCommenced
bool hasLateExitCommenced() const
Check if the program is in that period where the program was bound to exit, but was delayed by lateEx...
Definition: test_control.cc:48
isc::perfdhcp::TestControl::StatsMgr4Ptr
boost::shared_ptr< StatsMgr4 > StatsMgr4Ptr
Pointer to Statistics Manager for DHCPv4;.
Definition: test_control.h:127
isc::perfdhcp::CommandOptions::getAggressivity
int getAggressivity() const
Returns aggressivity value.
Definition: command_options.h:244
isc::perfdhcp::TestControl::checkLateMessages
void checkLateMessages(RateControl &rate_control)
Increments counter of late sent messages if required.
Definition: test_control.cc:147
isc::perfdhcp::CommandOptions
Command Options.
Definition: command_options.h:25
isc::Exception
This is a base class for exceptions thrown from the DNS library module.
Definition: exceptions/exceptions.h:23
isc::perfdhcp::PerfPkt6
PerfPkt6 (DHCPv6 packet)
Definition: perf_pkt6.h:40
dhcp4.h
isc::perfdhcp::TestControl::release_rate_control_
RateControl release_rate_control_
A rate control class for Release messages.
Definition: test_control.h:1144
isc::perfdhcp::TestControl::basic_rate_control_
RateControl basic_rate_control_
A rate control class for Discover and Solicit messages.
Definition: test_control.h:1140
isc::perfdhcp::TestControl::registerOptionFactories4
void registerOptionFactories4() const
Register option factory functions for DHCPv4.
Definition: test_control.cc:1380
isc::perfdhcp::TestControl::openSocket
int openSocket() const
Open socket to communicate with DHCP server.
Definition: test_control.cc:839
DHCPV6_REPLY
@ DHCPV6_REPLY
Definition: dhcp6.h:219
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::perfdhcp::StatsMgr::XCHG_RA
@ XCHG_RA
DHCPv4 REQUEST-ACK.
Definition: bin/perfdhcp/stats_mgr.h:117
isc::perfdhcp::TestControl::getTemplateBuffer
TemplateBuffer getTemplateBuffer(const size_t idx) const
Return template buffer.
Definition: test_control.cc:744
isc::dhcp::HWAddrPtr
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
DHCPV6_RELEASE
@ DHCPV6_RELEASE
Definition: dhcp6.h:220
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc::dhcp::Pkt4Ptr
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:546
isc::dhcp::DHO_DHCP_REQUESTED_ADDRESS
@ DHO_DHCP_REQUESTED_ADDRESS
Definition: dhcp4.h:119
isc::perfdhcp::TestControl::stats_mgr6_
StatsMgr6Ptr stats_mgr6_
Statistics Manager 6.
Definition: test_control.h:1149
isc::dhcp::DHO_DHCP_SERVER_IDENTIFIER
@ DHO_DHCP_SERVER_IDENTIFIER
Definition: dhcp4.h:123
isc::perfdhcp::CommandOptions::getIpVersion
uint8_t getIpVersion() const
Returns IP version.
Definition: command_options.h:137
perfdhcp
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::perfdhcp::CommandOptions::getServerName
std::string getServerName() const
Returns server name.
Definition: command_options.h:349
isc::InvalidOperation
A generic exception that is thrown if a function is called in a prohibited way.
Definition: exceptions/exceptions.h:143
isc::dhcp::DHO_DHCP_MESSAGE_TYPE
@ DHO_DHCP_MESSAGE_TYPE
Definition: dhcp4.h:122
isc::InvalidParameter
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
Definition: exceptions/exceptions.h:124
isc::perfdhcp::TestControl::factoryRapidCommit6
static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 RAPID_COMMIT option instance.
Definition: test_control.cc:496
isc::perfdhcp::RateControl::isLateSent
bool isLateSent() const
Returns the value of the late send flag.
Definition: rate_control.h:104
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::perfdhcp::TestControl::getServerIdOffset
int getServerIdOffset() const
Return server id offset in a packet.
Definition: test_control.cc:734
isc::perfdhcp::TestControl::setTransidGenerator
void setTransidGenerator(const NumberGeneratorPtr &generator)
Set new transaction id generator.
Definition: test_control.h:270
isc::perfdhcp::TestControl::generateMacAddress
std::vector< uint8_t > generateMacAddress(uint8_t &randomized)
Generate MAC address.
Definition: test_control.cc:535
isc::perfdhcp::CommandOptions::getPeriod
int getPeriod() const
Returns test period.
Definition: command_options.h:197
isc::perfdhcp::TestControl::reset
void reset()
Resets internal state of the object.
Definition: test_control.cc:1455
isc::perfdhcp::TestControl
Test Control class.
Definition: test_control.h:121
isc::perfdhcp::TestControl::sendMessageFromReply
bool sendMessageFromReply(const uint16_t msg_type, const TestControlSocket &socket)
Send DHCPv6 Renew or Release message using specified socket.
Definition: test_control.cc:1811
isc::perfdhcp::CommandOptions::isBroadcast
bool isBroadcast() const
Checks if broadcast address is to be used.
Definition: command_options.h:269
isc::perfdhcp::CommandOptions::getElapsedTimeOffset
int getElapsedTimeOffset() const
Returns template offset for elapsed time.
Definition: command_options.h:319
D6O_RAPID_COMMIT
@ D6O_RAPID_COMMIT
Definition: dhcp6.h:34
isc::perfdhcp::CommandOptions::getTransactionIdOffset
std::vector< int > getTransactionIdOffset() const
brief Returns template offsets for xid.
Definition: command_options.h:309
isc::perfdhcp::TestControl::last_report_
boost::posix_time::ptime last_report_
Last intermediate report time.
Definition: test_control.h:1146
isc::perfdhcp::TestControl::printIntermediateStats
void printIntermediateStats()
Print intermediate statistics.
Definition: test_control.cc:1124
isc::dhcp::DHO_ROUTERS
@ DHO_ROUTERS
Definition: dhcp4.h:72
isc::perfdhcp::TestControl::factoryElapsedTime6
static dhcp::OptionPtr factoryElapsedTime6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 ELAPSED_TIME option.
Definition: test_control.cc:444
isc::perfdhcp::TestControl::initPacketTemplates
void initPacketTemplates()
Reads packet templates from files.
Definition: test_control.cc:775
isc::perfdhcp::TestControl::processReceivedPacket6
void processReceivedPacket6(const TestControlSocket &socket, const dhcp::Pkt6Ptr &pkt6)
Process received DHCPv6 packet.
Definition: test_control.cc:1272
isc::perfdhcp::TestControl::factoryGeneric
static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create generic option.
Definition: test_control.cc:457
isc::perfdhcp::TestControl::sendPackets
void sendPackets(const TestControlSocket &socket, const uint64_t packets_num, const bool preload=false)
Send number of packets to initiate new exchanges.
Definition: test_control.cc:939
isc::perfdhcp::CommandOptions::getDropTime
std::vector< double > getDropTime() const
Returns drop time.
Definition: command_options.h:205
test_control.h
isc::util::OutputBuffer::getLength
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
D6O_SERVERID
@ D6O_SERVERID
Definition: dhcp6.h:22
isc::dhcp
Definition: ctrl_dhcp4_srv.cc:75
isc::perfdhcp::TestControl::addExtraOpts
void addExtraOpts(const dhcp::Pkt4Ptr &pkt4)
Inserts extra options specified by user.
Definition: test_control.cc:2366
isc::perfdhcp::TestControl::cleanCachedPackets
void cleanCachedPackets()
Removes cached DHCPv6 Reply packets every second.
Definition: test_control.cc:162
DHCPV6_RELAY_FORW
@ DHCPV6_RELAY_FORW
Definition: dhcp6.h:224
isc::perfdhcp::TestControl::createMessageFromReply
dhcp::Pkt6Ptr createMessageFromReply(const uint16_t msg_type, const dhcp::Pkt6Ptr &reply)
Creates DHCPv6 message from the Reply packet.
Definition: test_control.cc:404
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
isc::perfdhcp::TestControl::getRequestedIpOffset
int getRequestedIpOffset() const
Return requested ip offset in a packet.
Definition: test_control.cc:704
isc::perfdhcp::TestControl::StatsMgr6
StatsMgr< dhcp::Pkt6 > StatsMgr6
Statistics Manager for DHCPv6.
Definition: test_control.h:129
isc::perfdhcp::TestControl::sendSolicit6
void sendSolicit6(const TestControlSocket &socket, const bool preload=false)
Send DHCPv6 SOLICIT message.
Definition: test_control.cc:2204
isc::perfdhcp::TestControl::getRandomOffset
int getRandomOffset(const int arg_idx) const
Return randomization offset in a packet.
Definition: test_control.cc:694
isc::perfdhcp::TestControl::template_buffers_
TemplateBufferCollection template_buffers_
Packet template buffers.
Definition: test_control.h:1161
isc::perfdhcp::CommandOptions::getRate
int getRate() const
Returns exchange rate.
Definition: command_options.h:152
isc::perfdhcp::TestControl::number_generator_
isc::util::random::UniformRandomIntegerGenerator number_generator_
Generate uniformly distributed integers in range of [min, max].
Definition: test_control.h:298
isc::perfdhcp::CommandOptions::getMacsFromFile
const MacAddrsVector & getMacsFromFile() const
Returns reference to a vector of MAC addresses read from a file.
Definition: command_options.h:304
isc::perfdhcp::CommandOptions::getExtraOpts
const isc::dhcp::OptionCollection & getExtraOpts() const
Returns extra options to be inserted.
Definition: command_options.h:344
isc::dhcp::Pkt6::RelayInfo::msg_type_
uint8_t msg_type_
message type (RELAY-FORW oro RELAY-REPL)
Definition: pkt6.h:94
perf_pkt4.h
isc::perfdhcp::TestControl::TestControlSocket::valid_
bool valid_
Is socket valid.
Definition: test_control.h:165
isc::perfdhcp::TestControl::ack_storage_
PacketStorage< dhcp::Pkt4 > ack_storage_
A storage for DHCPACK messages.
Definition: test_control.h:1151
isc::perfdhcp::CommandOptions::isRapidCommit
bool isRapidCommit() const
Check if rapid commit option used.
Definition: command_options.h:274
isc::perfdhcp::TestControl::setDefaults4
void setDefaults4(const TestControlSocket &socket, const dhcp::Pkt4Ptr &pkt)
Set default DHCPv4 packet parameters.
Definition: test_control.cc:2306
isc::dhcp::Pkt4
Represents DHCPv4 packet.
Definition: pkt4.h:38
isc::perfdhcp::CommandOptions::getSeed
uint32_t getSeed() const
Returns random seed.
Definition: command_options.h:264
isc::dhcp::Pkt6::RelayInfo
structure that describes a single relay information
Definition: pkt6.h:85
isc::perfdhcp::TestControl::getSentPacketsNum
uint64_t getSentPacketsNum(ExchangeType xchg_type) const
Get number of sent packets.
Definition: test_control.cc:724
isc::perfdhcp::TestControl::SequentialGenerator
Sequential numbers generator class.
Definition: test_control.h:215
isc::perfdhcp::TestControl::sendDiscover4
void sendDiscover4(const TestControlSocket &socket, const bool preload=false)
Send DHCPv4 DISCOVER message.
Definition: test_control.cc:1679
isc::perfdhcp::TestControl::printTemplate
void printTemplate(const uint8_t packet_type) const
Print template information.
Definition: test_control.cc:1018
D6O_IA_NA
@ D6O_IA_NA
Definition: dhcp6.h:23
isc::perfdhcp::TestControl::readPacketTemplate
void readPacketTemplate(const std::string &file_name)
Read DHCP message template from file.
Definition: test_control.cc:1181
isc::perfdhcp::TestControl::HW_ETHER_LEN
static const uint8_t HW_ETHER_LEN
Length of the Ethernet HW address (MAC) in bytes.
Definition: test_control.h:247
isc::perfdhcp::TestControl::saveFirstPacket
void saveFirstPacket(const dhcp::Pkt4Ptr &pkt)
Save the first DHCPv4 sent packet of the specified type.
Definition: test_control.cc:1661
isc::perfdhcp::TestControl::sendMultipleRequests
uint64_t sendMultipleRequests(const TestControlSocket &socket, const uint64_t msg_num)
Send number of DHCPREQUEST (renew) messages to a server.
Definition: test_control.cc:980
isc::perfdhcp::TestControl::template_packets_v4_
std::map< uint8_t, dhcp::Pkt4Ptr > template_packets_v4_
First packets send.
Definition: test_control.h:1165
isc::perfdhcp::TestControl::printTemplates
void printTemplates() const
Print templates information.
Definition: test_control.cc:1075
DHCPV6_ADVERTISE
@ DHCPV6_ADVERTISE
Definition: dhcp6.h:214
isc::perfdhcp::CommandOptions::getNumRequests
std::vector< int > getNumRequests() const
Returns maximum number of exchanges.
Definition: command_options.h:192
isc::perfdhcp::RateControl::setRate
void setRate(const int rate)
Sets the new rate.
Definition: rate_control.cc:132
isc::dhcp::SocketInfo
Holds information about socket.
Definition: socket_info.h:19
isc::perfdhcp::TestControl::factoryRequestList4
static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv4 Request List option.
Definition: test_control.cc:515
isc::perfdhcp::RateControl::getDue
boost::posix_time::ptime getDue() const
Returns current due time to send next message.
Definition: rate_control.h:56
isc::perfdhcp::TestControl::NumberGeneratorPtr
boost::shared_ptr< NumberGenerator > NumberGeneratorPtr
The default generator pointer.
Definition: test_control.h:212
isc::perfdhcp::TestControl::createRequestFromAck
dhcp::Pkt4Ptr createRequestFromAck(const dhcp::Pkt4Ptr &ack)
Creates DHCPREQUEST from a DHCPACK message.
Definition: test_control.cc:388
isc::perfdhcp::StatsMgr::XCHG_SA
@ XCHG_SA
DHCPv6 SOLICIT-ADVERTISE.
Definition: bin/perfdhcp/stats_mgr.h:119
isc::perfdhcp::CommandOptions::getPreload
int getPreload() const
Returns number of preload exchanges.
Definition: command_options.h:239
isc::perfdhcp::RateControl::updateSendTime
void updateSendTime()
Sets the timestamp of the last sent message to current time.
Definition: rate_control.cc:148
isc::dhcp::DHO_HOST_NAME
@ DHO_HOST_NAME
Definition: dhcp4.h:81
isc::perfdhcp::TestControl::processReceivedPacket4
void processReceivedPacket4(const TestControlSocket &socket, const dhcp::Pkt4Ptr &pkt4)
Process received DHCPv4 packet.
Definition: test_control.cc:1229
isc::perfdhcp::CommandOptions::getReleaseRate
int getReleaseRate() const
Returns a rate at which DHCPv6 Release messages are sent.
Definition: command_options.h:162
isc::perfdhcp::TestControl::instance
static TestControl & instance()
TestControl is a singleton class.
Definition: test_control.cc:136
isc::perfdhcp::CommandOptions::LeaseType::ADDRESS
@ ADDRESS
Definition: command_options.h:42
isc::dhcp::DHCPOFFER
@ DHCPOFFER
Definition: dhcp4.h:229
isc::perfdhcp::StatsMgr::XCHG_RR
@ XCHG_RR
DHCPv6 REQUEST-REPLY.
Definition: bin/perfdhcp/stats_mgr.h:120
check_valgrind.h
isc::perfdhcp::CommandOptions::getExitWaitTime
int getExitWaitTime() const
Returns the time in microseconds to delay the program by.
Definition: command_options.h:254
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition: exceptions/exceptions.h:115
isc::dhcp::SocketInfo::sockfd_
int sockfd_
IPv4 or IPv6.
Definition: socket_info.h:26
isc::perfdhcp::CommandOptions::LeaseType::PREFIX
@ PREFIX
Definition: command_options.h:43
isc::perfdhcp::TestControl::factoryIana6
static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create IA_NA option.
Definition: test_control.cc:464
isc::perfdhcp::TestControl::sendRequest6
void sendRequest6(const TestControlSocket &socket, const dhcp::Pkt6Ptr &advertise_pkt6)
Send DHCPv6 REQUEST message.
Definition: test_control.cc:2028
isc::perfdhcp::CommandOptions::getWrapped
std::string getWrapped() const
Returns wrapped command.
Definition: command_options.h:339
isc::perfdhcp::TestControl::handleChild
static void handleChild(int sig)
Handle child signal.
Definition: test_control.cc:762
D6O_ORO
@ D6O_ORO
Definition: dhcp6.h:26
isc::perfdhcp::CommandOptions::getClientsNum
uint32_t getClientsNum() const
Returns number of simulated clients.
Definition: command_options.h:172
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
isc::perfdhcp::PerfPkt4Ptr
boost::shared_ptr< PerfPkt4 > PerfPkt4Ptr
Definition: perf_pkt4.h:126
isc::dhcp::HTYPE_ETHER
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition: dhcp4.h:56
isc::dhcp::DHO_DOMAIN_NAME
@ DHO_DOMAIN_NAME
Definition: dhcp4.h:84
exceptions.h
isc::perfdhcp::TestControl::waitToExit
bool waitToExit() const
Delay the exit by a fixed given time to catch up to all exchanges that were already started.
Definition: test_control.cc:53
isc::perfdhcp::CommandOptions::getMaxDrop
std::vector< int > getMaxDrop() const
Returns maximum drops number.
Definition: command_options.h:213
isc::perfdhcp::CommandOptions::getDuidTemplate
std::vector< uint8_t > getDuidTemplate() const
Returns DUID template.
Definition: command_options.h:182
isc::perfdhcp::CommandOptions::getLocalPort
int getLocalPort() const
Returns local port number.
Definition: command_options.h:249
D6O_CLIENTID
@ D6O_CLIENTID
Definition: dhcp6.h:21
isc::perfdhcp::TestControl::factoryOptionRequestOption6
static dhcp::OptionPtr factoryOptionRequestOption6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 ORO option.
Definition: test_control.cc:502
isc::util::OutputBuffer::getData
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
isc::perfdhcp::OptionNotFound
Exception thrown when the required option is not found in a packet.
Definition: test_control.h:54
isc::perfdhcp::StatsMgr::XCHG_RL
@ XCHG_RL
DHCPv6 RELEASE-REPLY.
Definition: bin/perfdhcp/stats_mgr.h:122
isc::dhcp::DHCPACK
@ DHCPACK
Definition: dhcp4.h:232
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
isc::perfdhcp::CommandOptions::isSeeded
bool isSeeded() const
Checks if seed provided.
Definition: command_options.h:259
isc::perfdhcp::TestControl::generateClientId
dhcp::OptionPtr generateClientId(const dhcp::HWAddrPtr &hwaddr) const
Generate DHCPv4 client identifier from HW address.
Definition: test_control.cc:583
isc::perfdhcp::TestControl::renew_rate_control_
RateControl renew_rate_control_
A rate control class for Renew messages.
Definition: test_control.h:1142
isc::perfdhcp::TestControl::getRcvdPacketsNum
uint64_t getRcvdPacketsNum(ExchangeType xchg_type) const
Get number of received packets.
Definition: test_control.cc:714
isc::dhcp::DHO_DHCP_CLIENT_IDENTIFIER
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition: dhcp4.h:130
D6O_DOMAIN_SEARCH
@ D6O_DOMAIN_SEARCH
Definition: dhcp6.h:44
isc::perfdhcp::TestControl::printStats
void printStats() const
Print performance statistics.
Definition: test_control.cc:1140
isc::dhcp::DHO_TIME_OFFSET
@ DHO_TIME_OFFSET
Definition: dhcp4.h:71
isc::dhcp::DHO_DHCP_PARAMETER_REQUEST_LIST
@ DHO_DHCP_PARAMETER_REQUEST_LIST
Definition: dhcp4.h:124
isc::perfdhcp::CommandOptions::getMacTemplate
std::vector< uint8_t > getMacTemplate() const
Returns MAC address template.
Definition: command_options.h:177
isc::perfdhcp::StatsMgr::XCHG_DO
@ XCHG_DO
DHCPv4 DISCOVER-OFFER.
Definition: bin/perfdhcp/stats_mgr.h:116
isc::perfdhcp::CommandOptions::getReportDelay
int getReportDelay() const
Returns delay between two performance reports.
Definition: command_options.h:167
isc::dhcp::Option
Definition: option.h:58
isc::perfdhcp::TestControl::sendRequest4
void sendRequest4(const TestControlSocket &socket, const dhcp::Pkt4Ptr &discover_pkt4, const dhcp::Pkt4Ptr &offer_pkt4)
Send DHCPv4 REQUEST message.
Definition: test_control.cc:1848
isc::dhcp::Pkt6::RelayInfo::linkaddr_
isc::asiolink::IOAddress linkaddr_
fixed field in relay-forw/relay-reply
Definition: pkt6.h:96
command_options.h
isc::perfdhcp::CommandOptions::getLocalName
std::string getLocalName() const
Returns local address or interface name.
Definition: command_options.h:226
isc::perfdhcp::PerfPkt4
PerfPkt4 (DHCPv4 packet)
Definition: perf_pkt4.h:40
isc::perfdhcp::TestControl::factoryIapd6
static dhcp::OptionPtr factoryIapd6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create IA_PD option.
Definition: test_control.cc:480
isc::perfdhcp::RateControl::getOutboundMessageCount
uint64_t getOutboundMessageCount()
Returns number of messages to be sent "now".
Definition: rate_control.cc:36
isc::dhcp::IfacePtr
boost::shared_ptr< Iface > IfacePtr
Definition: iface_mgr.h:457
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
isc::dhcp::DHCPREQUEST
@ DHCPREQUEST
Definition: dhcp4.h:230
isc::perfdhcp::TestControl::ExchangeType
StatsMgr ::ExchangeType ExchangeType
Packet exchange type.
Definition: test_control.h:133
isc::perfdhcp::TestControl::first_packet_serverid_
dhcp::OptionBuffer first_packet_serverid_
Buffer holding server id received in first packet.
Definition: test_control.h:1158
DHCPV6_SOLICIT
@ DHCPV6_SOLICIT
Definition: dhcp6.h:213
isc::perfdhcp::TestControl::reply_storage_
PacketStorage< dhcp::Pkt6 > reply_storage_
A storage for reply messages.
Definition: test_control.h:1152
isc::perfdhcp::TestControl::interrupted_
static bool interrupted_
Is program interrupted.
Definition: test_control.h:1168
isc::dhcp::DHO_BROADCAST_ADDRESS
@ DHO_BROADCAST_ADDRESS
Definition: dhcp4.h:97
isc::perfdhcp::TestControl::getElapsedTimeOffset
int getElapsedTimeOffset() const
Return elapsed time offset in a packet.
Definition: test_control.cc:669
isc::perfdhcp::TestControl::generateTransid
uint32_t generateTransid()
generate transaction id.
Definition: test_control.h:508
isc::perfdhcp::TestControl::transid_gen_
NumberGeneratorPtr transid_gen_
Transaction id generator.
Definition: test_control.h:1154
isc::perfdhcp::TestControl::TestControlSocket::~TestControlSocket
~TestControlSocket()
Destructor of the socket wrapper class.
Definition: test_control.cc:113