Kea  1.5.0
command_options.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 
9 #include "command_options.h"
10 #include <exceptions/exceptions.h>
11 #include <dhcp/iface_mgr.h>
12 #include <dhcp/duid.h>
13 #include <dhcp/option.h>
14 #include <cfgrpt/config_report.h>
15 #include <util/encode/hex.h>
16 
17 #include <boost/lexical_cast.hpp>
18 #include <boost/date_time/posix_time/posix_time.hpp>
19 
20 #include <sstream>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <unistd.h>
25 #include <fstream>
26 
27 #ifdef HAVE_OPTRESET
28 extern int optreset;
29 #endif
30 
31 using namespace std;
32 using namespace isc;
33 using namespace isc::dhcp;
34 
35 namespace isc {
36 namespace perfdhcp {
37 
38 // Refer to config_report so it will be embedded in the binary
40 
41 CommandOptions::LeaseType::LeaseType()
42  : type_(ADDRESS) {
43 }
44 
46  : type_(lease_type) {
47 }
48 
49 bool
50 CommandOptions::LeaseType::is(const Type lease_type) const {
51  return (lease_type == type_);
52 }
53 
54 bool
55 CommandOptions::LeaseType::includes(const Type lease_type) const {
56  return (is(ADDRESS_AND_PREFIX) || (lease_type == type_));
57 }
58 
59 void
61  type_ = lease_type;
62 }
63 
64 void
65 CommandOptions::LeaseType::fromCommandLine(const std::string& cmd_line_arg) {
66  if (cmd_line_arg == "address-only") {
67  type_ = ADDRESS;
68 
69  } else if (cmd_line_arg == "prefix-only") {
70  type_ = PREFIX;
71 
72  } else if (cmd_line_arg == "address-and-prefix") {
73  type_ = ADDRESS_AND_PREFIX;
74 
75  } else {
76  isc_throw(isc::InvalidParameter, "value of lease-type: -e<lease-type>,"
77  " must be one of the following: 'address-only' or"
78  " 'prefix-only'");
79  }
80 }
81 
82 std::string
84  switch (type_) {
85  case ADDRESS:
86  return ("address-only (IA_NA option added to the client's request)");
87  case PREFIX:
88  return ("prefix-only (IA_PD option added to the client's request)");
89  case ADDRESS_AND_PREFIX:
90  return ("address-and-prefix (Both IA_NA and IA_PD options added to the"
91  " client's request)");
92  default:
93  isc_throw(Unexpected, "internal error: undefined lease type code when"
94  " returning textual representation of the lease type");
95  }
96 }
97 
100  static CommandOptions options;
101  return (options);
102 }
103 
104 void
106  // Default mac address used in DHCP messages
107  // if -b mac=<mac-address> was not specified
108  uint8_t mac[6] = { 0x0, 0xC, 0x1, 0x2, 0x3, 0x4 };
109 
110  // Default packet drop time if -D<drop-time> parameter
111  // was not specified
112  double dt[2] = { 1., 1. };
113 
114  // We don't use constructor initialization list because we
115  // will need to reset all members many times to perform unit tests
116  ipversion_ = 0;
117  exchange_mode_ = DORA_SARR;
118  lease_type_.set(LeaseType::ADDRESS);
119  rate_ = 0;
120  renew_rate_ = 0;
121  release_rate_ = 0;
122  report_delay_ = 0;
123  clients_num_ = 0;
124  mac_template_.assign(mac, mac + 6);
125  duid_template_.clear();
126  base_.clear();
127  mac_list_file_.clear();
128  mac_list_.clear();
129  num_request_.clear();
130  exit_wait_time_ = 0;
131  period_ = 0;
132  drop_time_set_ = 0;
133  drop_time_.assign(dt, dt + 2);
134  max_drop_.clear();
135  max_pdrop_.clear();
136  localname_.clear();
137  is_interface_ = false;
138  preload_ = 0;
139  aggressivity_ = 1;
140  local_port_ = 0;
141  seeded_ = false;
142  seed_ = 0;
143  broadcast_ = false;
144  rapid_commit_ = false;
145  use_first_ = false;
146  template_file_.clear();
147  rnd_offset_.clear();
148  xid_offset_.clear();
149  elp_offset_ = -1;
150  sid_offset_ = -1;
151  rip_offset_ = -1;
152  diags_.clear();
153  wrapped_.clear();
154  server_name_.clear();
155  v6_relay_encapsulation_level_ = 0;
156  generateDuidTemplate();
157  extra_opts_.clear();
158 }
159 
160 bool
161 CommandOptions::parse(int argc, char** const argv, bool print_cmd_line) {
162  // Reset internal variables used by getopt
163  // to eliminate undefined behavior when
164  // parsing different command lines multiple times
165 
166 #ifdef __GLIBC__
167  // Warning: non-portable code. This is due to a bug in glibc's
168  // getopt() which keeps internal state about an old argument vector
169  // (argc, argv) from last call and tries to scan them when a new
170  // argument vector (argc, argv) is passed. As the old vector may not
171  // be main()'s arguments, but heap allocated and may have been freed
172  // since, this becomes a use after free and results in random
173  // behavior. According to the NOTES section in glibc getopt()'s
174  // manpage, setting optind=0 resets getopt()'s state. Though this is
175  // not required in our usage of getopt(), the bug still happens
176  // unless we set optind=0.
177  //
178  // Setting optind=0 is non-portable code.
179  optind = 0;
180 #else
181  optind = 1;
182 #endif
183 
184  // optreset is declared on BSD systems and is used to reset internal
185  // state of getopt(). When parsing command line arguments multiple
186  // times with getopt() the optreset must be set to 1 every time before
187  // parsing starts. Failing to do so will result in random behavior of
188  // getopt().
189 #ifdef HAVE_OPTRESET
190  optreset = 1;
191 #endif
192 
193  opterr = 0;
194 
195  // Reset values of class members
196  reset();
197 
198  // Informs if program has been run with 'h' or 'v' option.
199  bool help_or_version_mode = initialize(argc, argv, print_cmd_line);
200  if (!help_or_version_mode) {
201  validate();
202  }
203  return (help_or_version_mode);
204 }
205 
206 bool
207 CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
208  int opt = 0; // Subsequent options returned by getopt()
209  std::string drop_arg; // Value of -D<value>argument
210  size_t percent_loc = 0; // Location of % sign in -D<value>
211  double drop_percent = 0; // % value (1..100) in -D<value%>
212  int num_drops = 0; // Max number of drops specified in -D<value>
213  int num_req = 0; // Max number of dropped
214  // requests in -n<max-drops>
215  int offset_arg = 0; // Temporary variable holding offset arguments
216  std::string sarg; // Temporary variable for string args
217 
218  std::ostringstream stream;
219  stream << "perfdhcp";
220  int num_mac_list_files = 0;
221 
222  // In this section we collect argument values from command line
223  // they will be tuned and validated elsewhere
224  while((opt = getopt(argc, argv, "hv46A:r:t:R:b:n:p:d:D:l:P:a:L:M:"
225  "s:iBc1T:X:O:o:E:S:I:x:W:w:e:f:F:")) != -1) {
226  stream << " -" << static_cast<char>(opt);
227  if (optarg) {
228  stream << " " << optarg;
229  }
230  switch (opt) {
231  case '1':
232  use_first_ = true;
233  break;
234 
235  // Simulate DHCPv6 relayed traffic.
236  case 'A':
237  // @todo: At the moment we only support simulating a single relay
238  // agent. In the future we should extend it to up to 32.
239  // See comment in https://github.com/isc-projects/kea/pull/22#issuecomment-243405600
240  v6_relay_encapsulation_level_ =
241  static_cast<uint8_t>(positiveInteger("-A<encapsulation-level> must"
242  " be a positive integer"));
243  if (v6_relay_encapsulation_level_ != 1) {
244  isc_throw(isc::InvalidParameter, "-A only supports 1 at the moment.");
245  }
246  break;
247 
248  case '4':
249  check(ipversion_ == 6, "IP version already set to 6");
250  ipversion_ = 4;
251  break;
252 
253  case '6':
254  check(ipversion_ == 4, "IP version already set to 4");
255  ipversion_ = 6;
256  break;
257 
258  case 'a':
259  aggressivity_ = positiveInteger("value of aggressivity: -a<value>"
260  " must be a positive integer");
261  break;
262 
263  case 'b':
264  check(base_.size() > 3, "-b<value> already specified,"
265  " unexpected occurrence of 5th -b<value>");
266  base_.push_back(optarg);
267  decodeBase(base_.back());
268  break;
269 
270  case 'B':
271  broadcast_ = true;
272  break;
273 
274  case 'c':
275  rapid_commit_ = true;
276  break;
277 
278  case 'd':
279  check(drop_time_set_ > 1,
280  "maximum number of drops already specified, "
281  "unexpected 3rd occurrence of -d<value>");
282  try {
283  drop_time_[drop_time_set_] =
284  boost::lexical_cast<double>(optarg);
285  } catch (boost::bad_lexical_cast&) {
287  "value of drop time: -d<value>"
288  " must be positive number");
289  }
290  check(drop_time_[drop_time_set_] <= 0.,
291  "drop-time must be a positive number");
292  drop_time_set_ = true;
293  break;
294 
295  case 'D':
296  drop_arg = std::string(optarg);
297  percent_loc = drop_arg.find('%');
298  check(max_pdrop_.size() > 1 || max_drop_.size() > 1,
299  "values of maximum drops: -D<value> already "
300  "specified, unexpected 3rd occurrence of -D<value>");
301  if ((percent_loc) != std::string::npos) {
302  try {
303  drop_percent =
304  boost::lexical_cast<double>(drop_arg.substr(0, percent_loc));
305  } catch (boost::bad_lexical_cast&) {
307  "value of drop percentage: -D<value%>"
308  " must be 0..100");
309  }
310  check((drop_percent <= 0) || (drop_percent >= 100),
311  "value of drop percentage: -D<value%> must be 0..100");
312  max_pdrop_.push_back(drop_percent);
313  } else {
314  num_drops = positiveInteger("value of max drops number:"
315  " -D<value> must be a positive integer");
316  max_drop_.push_back(num_drops);
317  }
318  break;
319 
320  case 'e':
321  initLeaseType();
322  break;
323 
324  case 'E':
325  elp_offset_ = nonNegativeInteger("value of time-offset: -E<value>"
326  " must not be a negative integer");
327  break;
328 
329  case 'f':
330  renew_rate_ = positiveInteger("value of the renew rate: -f<renew-rate>"
331  " must be a positive integer");
332  break;
333 
334  case 'F':
335  release_rate_ = positiveInteger("value of the release rate:"
336  " -F<release-rate> must be a"
337  " positive integer");
338  break;
339 
340  case 'h':
341  usage();
342  return (true);
343 
344  case 'i':
345  exchange_mode_ = DO_SA;
346  break;
347 
348  case 'I':
349  rip_offset_ = positiveInteger("value of ip address offset:"
350  " -I<value> must be a"
351  " positive integer");
352  break;
353 
354  case 'l':
355  localname_ = std::string(optarg);
356  initIsInterface();
357  break;
358 
359  case 'L':
360  local_port_ = nonNegativeInteger("value of local port:"
361  " -L<value> must not be a"
362  " negative integer");
363  check(local_port_ >
364  static_cast<int>(std::numeric_limits<uint16_t>::max()),
365  "local-port must be lower than " +
366  boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
367  break;
368 
369  case 'M':
370  check(num_mac_list_files >= 1, "only -M option can be specified");
371  num_mac_list_files++;
372  mac_list_file_ = std::string(optarg);
373  loadMacs();
374  break;
375 
376  case 'W':
377  exit_wait_time_ = nonNegativeInteger("value of exist wait time: "
378  "-W<value> must not be a "
379  "negative integer");
380  break;
381 
382  case 'n':
383  num_req = positiveInteger("value of num-request:"
384  " -n<value> must be a positive integer");
385  if (num_request_.size() >= 2) {
387  "value of maximum number of requests: -n<value> "
388  "already specified, unexpected 3rd occurrence"
389  " of -n<value>");
390  }
391  num_request_.push_back(num_req);
392  break;
393 
394  case 'O':
395  if (rnd_offset_.size() < 2) {
396  offset_arg = positiveInteger("value of random offset: "
397  "-O<value> must be greater than 3");
398  } else {
400  "random offsets already specified,"
401  " unexpected 3rd occurrence of -O<value>");
402  }
403  check(offset_arg < 3, "value of random random-offset:"
404  " -O<value> must be greater than 3 ");
405  rnd_offset_.push_back(offset_arg);
406  break;
407  case 'o': {
408 
409  // we must know how to contruct the option: whether it's v4 or v6.
410  check( (ipversion_ != 4) && (ipversion_ != 6),
411  "-4 or -6 must be explicitly specified before -o is used.");
412 
413  // custom option (expected format: code,hexstring)
414  std::string opt_text = std::string(optarg);
415  size_t coma_loc = opt_text.find(',');
416  check(coma_loc == std::string::npos,
417  "-o option must provide option code, a coma and hexstring for"
418  " the option content, e.g. -o60,646f63736973 for sending option"
419  " 60 (class-id) with the value 'docsis'");
420  int code = 0;
421 
422  // Try to parse the option code
423  try {
424  code = boost::lexical_cast<int>(opt_text.substr(0,coma_loc));
425  check(code <= 0, "Option code can't be negative");
426  } catch (boost::bad_lexical_cast&) {
427  isc_throw(InvalidParameter, "Invalid option code specified for "
428  "-o option, expected format: -o<integer>,<hexstring>");
429  }
430 
431  // Now try to interpret the hexstring
432  opt_text = opt_text.substr(coma_loc + 1);
433  std::vector<uint8_t> bin;
434  try {
435  isc::util::encode::decodeHex(opt_text, bin);
436  } catch (BadValue& e) {
437  isc_throw(InvalidParameter, "Error during encoding option -o:"
438  << e.what());
439  }
440 
441  // Create and remember the option.
442  OptionPtr opt(new Option(ipversion_ == 4 ? Option::V4 : Option::V6,
443  code, bin));
444  extra_opts_.insert(make_pair(code, opt));
445  break;
446  }
447  case 'p':
448  period_ = positiveInteger("value of test period:"
449  " -p<value> must be a positive integer");
450  break;
451 
452  case 'P':
453  preload_ = nonNegativeInteger("number of preload packets:"
454  " -P<value> must not be "
455  "a negative integer");
456  break;
457 
458  case 'r':
459  rate_ = positiveInteger("value of rate:"
460  " -r<value> must be a positive integer");
461  break;
462 
463  case 'R':
464  initClientsNum();
465  break;
466 
467  case 's':
468  seed_ = static_cast<unsigned int>
469  (nonNegativeInteger("value of seed:"
470  " -s <seed> must be non-negative integer"));
471  seeded_ = seed_ > 0 ? true : false;
472  break;
473 
474  case 'S':
475  sid_offset_ = positiveInteger("value of server id offset:"
476  " -S<value> must be a"
477  " positive integer");
478  break;
479 
480  case 't':
481  report_delay_ = positiveInteger("value of report delay:"
482  " -t<value> must be a"
483  " positive integer");
484  break;
485 
486  case 'T':
487  if (template_file_.size() < 2) {
488  sarg = nonEmptyString("template file name not specified,"
489  " expected -T<filename>");
490  template_file_.push_back(sarg);
491  } else {
493  "template files are already specified,"
494  " unexpected 3rd -T<filename> occurrence");
495  }
496  break;
497 
498  case 'v':
499  version();
500  return (true);
501 
502  case 'w':
503  wrapped_ = nonEmptyString("command for wrapped mode:"
504  " -w<command> must be specified");
505  break;
506 
507  case 'x':
508  diags_ = nonEmptyString("value of diagnostics selectors:"
509  " -x<value> must be specified");
510  break;
511 
512  case 'X':
513  if (xid_offset_.size() < 2) {
514  offset_arg = positiveInteger("value of transaction id:"
515  " -X<value> must be a"
516  " positive integer");
517  } else {
519  "transaction ids already specified,"
520  " unexpected 3rd -X<value> occurrence");
521  }
522  xid_offset_.push_back(offset_arg);
523  break;
524 
525  default:
526  isc_throw(isc::InvalidParameter, "unknown command line option");
527  }
528  }
529 
530  // If the IP version was not specified in the
531  // command line, assume IPv4.
532  if (ipversion_ == 0) {
533  ipversion_ = 4;
534  }
535 
536  // If template packet files specified for both DISCOVER/SOLICIT
537  // and REQUEST/REPLY exchanges make sure we have transaction id
538  // and random duid offsets for both exchanges. We will duplicate
539  // value specified as -X<value> and -R<value> for second
540  // exchange if user did not specified otherwise.
541  if (template_file_.size() > 1) {
542  if (xid_offset_.size() == 1) {
543  xid_offset_.push_back(xid_offset_[0]);
544  }
545  if (rnd_offset_.size() == 1) {
546  rnd_offset_.push_back(rnd_offset_[0]);
547  }
548  }
549 
550  // Get server argument
551  // NoteFF02::1:2 and FF02::1:3 are defined in RFC 8415 as
552  // All_DHCP_Relay_Agents_and_Servers and All_DHCP_Servers
553  // addresses
554  check(optind < argc -1, "extra arguments?");
555  if (optind == argc - 1) {
556  server_name_ = argv[optind];
557  stream << " " << server_name_;
558  // Decode special cases
559  if ((ipversion_ == 4) && (server_name_.compare("all") == 0)) {
560  broadcast_ = true;
561  // Use broadcast address as server name.
562  server_name_ = DHCP_IPV4_BROADCAST_ADDRESS;
563  } else if ((ipversion_ == 6) && (server_name_.compare("all") == 0)) {
564  server_name_ = ALL_DHCP_RELAY_AGENTS_AND_SERVERS;
565  } else if ((ipversion_ == 6) &&
566  (server_name_.compare("servers") == 0)) {
567  server_name_ = ALL_DHCP_SERVERS;
568  }
569  }
570 
571  if (print_cmd_line) {
572  std::cout << "Running: " << stream.str() << std::endl;
573  }
574 
575  // Handle the local '-l' address/interface
576  if (!localname_.empty()) {
577  if (server_name_.empty()) {
578  if (is_interface_ && (ipversion_ == 4)) {
579  broadcast_ = true;
580  server_name_ = DHCP_IPV4_BROADCAST_ADDRESS;
581  } else if (is_interface_ && (ipversion_ == 6)) {
582  server_name_ = ALL_DHCP_RELAY_AGENTS_AND_SERVERS;
583  }
584  }
585  }
586  if (server_name_.empty()) {
588  "without an interface, server is required");
589  }
590 
591  // If DUID is not specified from command line we need to
592  // generate one.
593  if (duid_template_.empty()) {
594  generateDuidTemplate();
595  }
596  return (false);
597 }
598 
599 void
600 CommandOptions::initClientsNum() {
601  const std::string errmsg =
602  "value of -R <value> must be non-negative integer";
603 
604  try {
605  // Declare clients_num as as 64-bit signed value to
606  // be able to detect negative values provided
607  // by user. We would not detect negative values
608  // if we casted directly to unsigned value.
609  long long clients_num = boost::lexical_cast<long long>(optarg);
610  check(clients_num < 0, errmsg);
611  clients_num_ = boost::lexical_cast<uint32_t>(optarg);
612  } catch (boost::bad_lexical_cast&) {
614  }
615 }
616 
617 void
618 CommandOptions::initIsInterface() {
619  is_interface_ = false;
620  if (!localname_.empty()) {
622  if (iface_mgr.getIface(localname_) != NULL) {
623  is_interface_ = true;
624  }
625  }
626 }
627 
628 void
629 CommandOptions::decodeBase(const std::string& base) {
630  std::string b(base);
631  boost::algorithm::to_lower(b);
632 
633  // Currently we only support mac and duid
634  if ((b.substr(0, 4) == "mac=") || (b.substr(0, 6) == "ether=")) {
635  decodeMacBase(b);
636  } else if (b.substr(0, 5) == "duid=") {
637  decodeDuid(b);
638  } else {
640  "base value not provided as -b<value>,"
641  " expected -b mac=<mac> or -b duid=<duid>");
642  }
643 }
644 
645 void
646 CommandOptions::decodeMacBase(const std::string& base) {
647  // Strip string from mac=
648  size_t found = base.find('=');
649  static const char* errmsg = "expected -b<base> format for"
650  " mac address is -b mac=00::0C::01::02::03::04 or"
651  " -b mac=00:0C:01:02:03:04";
652  check(found == std::string::npos, errmsg);
653 
654  // Decode mac address to vector of uint8_t
655  std::istringstream s1(base.substr(found + 1));
656  std::string token;
657  mac_template_.clear();
658  // Get pieces of MAC address separated with : (or even ::)
659  while (std::getline(s1, token, ':')) {
660  // Convert token to byte value using std::istringstream
661  if (token.length() > 0) {
662  unsigned int ui = 0;
663  try {
664  // Do actual conversion
665  ui = convertHexString(token);
666  } catch (isc::InvalidParameter&) {
668  "invalid characters in MAC provided");
669 
670  }
671  // If conversion succeeded store byte value
672  mac_template_.push_back(ui);
673  }
674  }
675  // MAC address must consist of 6 octets, otherwise it is invalid
676  check(mac_template_.size() != 6, errmsg);
677 }
678 
679 void
680 CommandOptions::decodeDuid(const std::string& base) {
681  // Strip argument from duid=
682  std::vector<uint8_t> duid_template;
683  size_t found = base.find('=');
684  check(found == std::string::npos, "expected -b<base>"
685  " format for duid is -b duid=<duid>");
686  std::string b = base.substr(found + 1);
687 
688  // DUID must have even number of digits and must not be longer than 64 bytes
689  check(b.length() & 1, "odd number of hexadecimal digits in duid");
690  check(b.length() > 128, "duid too large");
691  check(b.length() == 0, "no duid specified");
692 
693  // Turn pairs of hexadecimal digits into vector of octets
694  for (size_t i = 0; i < b.length(); i += 2) {
695  unsigned int ui = 0;
696  try {
697  // Do actual conversion
698  ui = convertHexString(b.substr(i, 2));
699  } catch (isc::InvalidParameter&) {
701  "invalid characters in DUID provided,"
702  " expected hex digits");
703  }
704  duid_template.push_back(static_cast<uint8_t>(ui));
705  }
706  // @todo Get rid of this limitation when we manage add support
707  // for DUIDs other than LLT. Shorter DUIDs may be useful for
708  // server testing purposes.
709  check(duid_template.size() < 6, "DUID must be at least 6 octets long");
710  // Assign the new duid only if successfully generated.
711  std::swap(duid_template, duid_template_);
712 }
713 
714 void
715 CommandOptions::generateDuidTemplate() {
716  using namespace boost::posix_time;
717  // Duid template will be most likely generated only once but
718  // it is ok if it is called more then once so we simply
719  // regenerate it and discard previous value.
720  duid_template_.clear();
721  const uint8_t duid_template_len = 14;
722  duid_template_.resize(duid_template_len);
723  // The first four octets consist of DUID LLT and hardware type.
724  duid_template_[0] = static_cast<uint8_t>(static_cast<uint16_t>(isc::dhcp::DUID::DUID_LLT) >> 8);
725  duid_template_[1] = static_cast<uint8_t>(static_cast<uint16_t>(isc::dhcp::DUID::DUID_LLT) & 0xff);
726  duid_template_[2] = HWTYPE_ETHERNET >> 8;
727  duid_template_[3] = HWTYPE_ETHERNET & 0xff;
728 
729  // As described in RFC 8415: 'the time value is the time
730  // that the DUID is generated represented in seconds
731  // since midnight (UTC), January 1, 2000, modulo 2^32.'
732  ptime now = microsec_clock::universal_time();
733  ptime duid_epoch(from_iso_string("20000101T000000"));
734  time_period period(duid_epoch, now);
735  uint32_t duration_sec = htonl(period.length().total_seconds());
736  memcpy(&duid_template_[4], &duration_sec, 4);
737 
738  // Set link layer address (6 octets). This value may be
739  // randomized before sending a packet to simulate different
740  // clients.
741  memcpy(&duid_template_[8], &mac_template_[0], 6);
742 }
743 
744 uint8_t
745 CommandOptions::convertHexString(const std::string& text) const {
746  unsigned int ui = 0;
747  // First, check if we are dealing with hexadecimal digits only
748  for (size_t i = 0; i < text.length(); ++i) {
749  if (!std::isxdigit(text[i])) {
751  "The following digit: " << text[i] << " in "
752  << text << "is not hexadecimal");
753  }
754  }
755  // If we are here, we have valid string to convert to octet
756  std::istringstream text_stream(text);
757  text_stream >> std::hex >> ui >> std::dec;
758  // Check if for some reason we have overflow - this should never happen!
759  if (ui > 0xFF) {
760  isc_throw(isc::InvalidParameter, "Can't convert more than"
761  " two hex digits to byte");
762  }
763  return ui;
764 }
765 
766 void CommandOptions::loadMacs() {
767  std::string line;
768  std::ifstream infile(mac_list_file_.c_str());
769  size_t cnt = 0;
770  while (std::getline(infile, line)) {
771  cnt++;
772  stringstream tmp;
773  tmp << "invalid mac in input line " << cnt;
774  // Let's print more meaningful error that contains line with error.
775  check(decodeMacString(line), tmp.str());
776  }
777 }
778 
779 bool CommandOptions::decodeMacString(const std::string& line) {
780  // decode mac string into a vector of uint8_t returns true in case of error.
781  std::istringstream s(line);
782  std::string token;
783  std::vector<uint8_t> mac;
784  while(std::getline(s, token, ':')) {
785  // Convert token to byte value using std::istringstream
786  if (token.length() > 0) {
787  unsigned int ui = 0;
788  try {
789  // Do actual conversion
790  ui = convertHexString(token);
791  } catch (isc::InvalidParameter&) {
792  return (true);
793  }
794  // If conversion succeeded store byte value
795  mac.push_back(ui);
796  }
797  }
798  mac_list_.push_back(mac);
799  return (false);
800 }
801 
802 void
803 CommandOptions::validate() const {
804  check((getIpVersion() != 4) && (isBroadcast() != 0),
805  "-B is not compatible with IPv6 (-6)");
806  check((getIpVersion() != 6) && (isRapidCommit() != 0),
807  "-6 (IPv6) must be set to use -c");
808  check(getIpVersion() == 4 && isUseRelayedV6(),
809  "Can't use -4 with -A, it's a V6 only option.");
810  check((getIpVersion() != 6) && (getReleaseRate() != 0),
811  "-F<release-rate> may be used with -6 (IPv6) only");
812  check((getExchangeMode() == DO_SA) && (getNumRequests().size() > 1),
813  "second -n<num-request> is not compatible with -i");
814  check((getIpVersion() == 4) && !getLeaseType().is(LeaseType::ADDRESS),
815  "-6 option must be used if lease type other than '-e address-only'"
816  " is specified");
817  check(!getTemplateFiles().empty() &&
819  "template files may be only used with '-e address-only'");
820  check((getExchangeMode() == DO_SA) && (getDropTime()[1] != 1.),
821  "second -d<drop-time> is not compatible with -i");
822  check((getExchangeMode() == DO_SA) &&
823  ((getMaxDrop().size() > 1) || (getMaxDropPercentage().size() > 1)),
824  "second -D<max-drop> is not compatible with -i");
825  check((getExchangeMode() == DO_SA) && (isUseFirst()),
826  "-1 is not compatible with -i");
827  check((getExchangeMode() == DO_SA) && (getTemplateFiles().size() > 1),
828  "second -T<template-file> is not compatible with -i");
829  check((getExchangeMode() == DO_SA) && (getTransactionIdOffset().size() > 1),
830  "second -X<xid-offset> is not compatible with -i");
831  check((getExchangeMode() == DO_SA) && (getRandomOffset().size() > 1),
832  "second -O<random-offset is not compatible with -i");
833  check((getExchangeMode() == DO_SA) && (getElapsedTimeOffset() >= 0),
834  "-E<time-offset> is not compatible with -i");
835  check((getExchangeMode() == DO_SA) && (getServerIdOffset() >= 0),
836  "-S<srvid-offset> is not compatible with -i");
837  check((getExchangeMode() == DO_SA) && (getRequestedIpOffset() >= 0),
838  "-I<ip-offset> is not compatible with -i");
839  check((getExchangeMode() == DO_SA) && (getRenewRate() != 0),
840  "-f<renew-rate> is not compatible with -i");
841  check((getExchangeMode() == DO_SA) && (getReleaseRate() != 0),
842  "-F<release-rate> is not compatible with -i");
843  check((getExchangeMode() != DO_SA) && (isRapidCommit() != 0),
844  "-i must be set to use -c");
845  check((getRate() != 0) && (getRenewRate() + getReleaseRate() > getRate()),
846  "The sum of Renew rate (-f<renew-rate>) and Release rate"
847  " (-F<release-rate>) must not be greater than the exchange"
848  " rate specified as -r<rate>");
849  check((getRate() == 0) && (getRenewRate() != 0),
850  "Renew rate specified as -f<renew-rate> must not be specified"
851  " when -r<rate> parameter is not specified");
852  check((getRate() == 0) && (getReleaseRate() != 0),
853  "Release rate specified as -F<release-rate> must not be specified"
854  " when -r<rate> parameter is not specified");
855  check((getTemplateFiles().size() < getTransactionIdOffset().size()),
856  "-T<template-file> must be set to use -X<xid-offset>");
857  check((getTemplateFiles().size() < getRandomOffset().size()),
858  "-T<template-file> must be set to use -O<random-offset>");
859  check((getTemplateFiles().size() < 2) && (getElapsedTimeOffset() >= 0),
860  "second/request -T<template-file> must be set to use -E<time-offset>");
861  check((getTemplateFiles().size() < 2) && (getServerIdOffset() >= 0),
862  "second/request -T<template-file> must be set to "
863  "use -S<srvid-offset>");
864  check((getTemplateFiles().size() < 2) && (getRequestedIpOffset() >= 0),
865  "second/request -T<template-file> must be set to "
866  "use -I<ip-offset>");
867  check((!getMacListFile().empty() && base_.size() > 0),
868  "Can't use -b with -M option");
869 }
870 
871 void
872 CommandOptions::check(bool condition, const std::string& errmsg) const {
873  // The same could have been done with macro or just if statement but
874  // we prefer functions to macros here
875  std::ostringstream stream;
876  stream << errmsg << "\n";
877  if (condition) {
879  }
880 }
881 
882 int
883 CommandOptions::positiveInteger(const std::string& errmsg) const {
884  try {
885  int value = boost::lexical_cast<int>(optarg);
886  check(value <= 0, errmsg);
887  return (value);
888  } catch (boost::bad_lexical_cast&) {
889  isc_throw(InvalidParameter, errmsg);
890  }
891 }
892 
893 int
894 CommandOptions::nonNegativeInteger(const std::string& errmsg) const {
895  try {
896  int value = boost::lexical_cast<int>(optarg);
897  check(value < 0, errmsg);
898  return (value);
899  } catch (boost::bad_lexical_cast&) {
900  isc_throw(InvalidParameter, errmsg);
901  }
902 }
903 
904 std::string
905 CommandOptions::nonEmptyString(const std::string& errmsg) const {
906  std::string sarg = optarg;
907  if (sarg.length() == 0) {
909  }
910  return sarg;
911 }
912 
913 void
914 CommandOptions::initLeaseType() {
915  std::string lease_type_arg = optarg;
916  lease_type_.fromCommandLine(lease_type_arg);
917 }
918 
919 void
921  std::cout << "IPv" << static_cast<int>(ipversion_) << std::endl;
922  if (exchange_mode_ == DO_SA) {
923  if (ipversion_ == 4) {
924  std::cout << "DISCOVER-OFFER only" << std::endl;
925  } else {
926  std::cout << "SOLICIT-ADVERTISE only" << std::endl;
927  }
928  }
929  std::cout << "lease-type=" << getLeaseType().toText() << std::endl;
930  if (rate_ != 0) {
931  std::cout << "rate[1/s]=" << rate_ << std::endl;
932  }
933  if (getRenewRate() != 0) {
934  std::cout << "renew-rate[1/s]=" << getRenewRate() << std::endl;
935  }
936  if (getReleaseRate() != 0) {
937  std::cout << "release-rate[1/s]=" << getReleaseRate() << std::endl;
938  }
939  if (report_delay_ != 0) {
940  std::cout << "report[s]=" << report_delay_ << std::endl;
941  }
942  if (clients_num_ != 0) {
943  std::cout << "clients=" << clients_num_ << std::endl;
944  }
945  for (size_t i = 0; i < base_.size(); ++i) {
946  std::cout << "base[" << i << "]=" << base_[i] << std::endl;
947  }
948  for (size_t i = 0; i < num_request_.size(); ++i) {
949  std::cout << "num-request[" << i << "]=" << num_request_[i] << std::endl;
950  }
951  if (period_ != 0) {
952  std::cout << "test-period=" << period_ << std::endl;
953  }
954  for (size_t i = 0; i < drop_time_.size(); ++i) {
955  std::cout << "drop-time[" << i << "]=" << drop_time_[i] << std::endl;
956  }
957  for (size_t i = 0; i < max_drop_.size(); ++i) {
958  std::cout << "max-drop{" << i << "]=" << max_drop_[i] << std::endl;
959  }
960  for (size_t i = 0; i < max_pdrop_.size(); ++i) {
961  std::cout << "max-pdrop{" << i << "]=" << max_pdrop_[i] << std::endl;
962  }
963  if (preload_ != 0) {
964  std::cout << "preload=" << preload_ << std::endl;
965  }
966  std::cout << "aggressivity=" << aggressivity_ << std::endl;
967  if (getLocalPort() != 0) {
968  std::cout << "local-port=" << local_port_ << std::endl;
969  }
970  if (seeded_) {
971  std::cout << "seed=" << seed_ << std::endl;
972  }
973  if (broadcast_) {
974  std::cout << "broadcast" << std::endl;
975  }
976  if (rapid_commit_) {
977  std::cout << "rapid-commit" << std::endl;
978  }
979  if (use_first_) {
980  std::cout << "use-first" << std::endl;
981  }
982  if (!mac_list_file_.empty()) {
983  std::cout << "mac-list-file=" << mac_list_file_ << std::endl;
984  }
985  for (size_t i = 0; i < template_file_.size(); ++i) {
986  std::cout << "template-file[" << i << "]=" << template_file_[i] << std::endl;
987  }
988  for (size_t i = 0; i < xid_offset_.size(); ++i) {
989  std::cout << "xid-offset[" << i << "]=" << xid_offset_[i] << std::endl;
990  }
991  if (elp_offset_ != 0) {
992  std::cout << "elp-offset=" << elp_offset_ << std::endl;
993  }
994  for (size_t i = 0; i < rnd_offset_.size(); ++i) {
995  std::cout << "rnd-offset[" << i << "]=" << rnd_offset_[i] << std::endl;
996  }
997  if (sid_offset_ != 0) {
998  std::cout << "sid-offset=" << sid_offset_ << std::endl;
999  }
1000  if (rip_offset_ != 0) {
1001  std::cout << "rip-offset=" << rip_offset_ << std::endl;
1002  }
1003  if (!diags_.empty()) {
1004  std::cout << "diagnostic-selectors=" << diags_ << std::endl;
1005  }
1006  if (!wrapped_.empty()) {
1007  std::cout << "wrapped=" << wrapped_ << std::endl;
1008  }
1009  if (!localname_.empty()) {
1010  if (is_interface_) {
1011  std::cout << "interface=" << localname_ << std::endl;
1012  } else {
1013  std::cout << "local-addr=" << localname_ << std::endl;
1014  }
1015  }
1016  if (!server_name_.empty()) {
1017  std::cout << "server=" << server_name_ << std::endl;
1018  }
1019 }
1020 
1021 void
1023  std::cout <<
1024  "perfdhcp [-hv] [-4|-6] [-A<encapsulation-level>] [-e<lease-type>]"
1025  " [-r<rate>] [-f<renew-rate>]\n"
1026  " [-F<release-rate>] [-t<report>] [-R<range>] [-b<base>]\n"
1027  " [-n<num-request>] [-p<test-period>] [-d<drop-time>]\n"
1028  " [-D<max-drop>] [-l<local-addr|interface>] [-P<preload>]\n"
1029  " [-a<aggressivity>] [-L<local-port>] [-s<seed>] [-i] [-B]\n"
1030  " [-W<late-exit-delay>]\n"
1031  " [-c] [-1] [-M<mac-list-file>] [-T<template-file>]\n"
1032  " [-X<xid-offset>] [-O<random-offset] [-E<time-offset>]\n"
1033  " [-S<srvid-offset>] [-I<ip-offset>] [-x<diagnostic-selector>]\n"
1034  " [-w<wrapped>] [server]\n"
1035  "\n"
1036  "The [server] argument is the name/address of the DHCP server to\n"
1037  "contact. For DHCPv4 operation, exchanges are initiated by\n"
1038  "transmitting a DHCP DISCOVER to this address.\n"
1039  "\n"
1040  "For DHCPv6 operation, exchanges are initiated by transmitting a DHCP\n"
1041  "SOLICIT to this address. In the DHCPv6 case, the special name 'all'\n"
1042  "can be used to refer to All_DHCP_Relay_Agents_and_Servers (the\n"
1043  "multicast address FF02::1:2), or the special name 'servers' to refer\n"
1044  "to All_DHCP_Servers (the multicast address FF05::1:3). The [server]\n"
1045  "argument is optional only in the case that -l is used to specify an\n"
1046  "interface, in which case [server] defaults to 'all'.\n"
1047  "\n"
1048  "The default is to perform a single 4-way exchange, effectively pinging\n"
1049  "the server.\n"
1050  "The -r option is used to set up a performance test, without\n"
1051  "it exchanges are initiated as fast as possible.\n"
1052  "\n"
1053  "Options:\n"
1054  "-1: Take the server-ID option from the first received message.\n"
1055  "-4: DHCPv4 operation (default). This is incompatible with the -6 option.\n"
1056  "-6: DHCPv6 operation. This is incompatible with the -4 option.\n"
1057  "-a<aggressivity>: When the target sending rate is not yet reached,\n"
1058  " control how many exchanges are initiated before the next pause.\n"
1059  "-b<base>: The base mac, duid, IP, etc, used to simulate different\n"
1060  " clients. This can be specified multiple times, each instance is\n"
1061  " in the <type>=<value> form, for instance:\n"
1062  " (and default) mac=00:0c:01:02:03:04.\n"
1063  "-d<drop-time>: Specify the time after which a request is treated as\n"
1064  " having been lost. The value is given in seconds and may contain a\n"
1065  " fractional component. The default is 1 second.\n"
1066  "-e<lease-type>: A type of lease being requested from the server. It\n"
1067  " may be one of the following: address-only, prefix-only or\n"
1068  " address-and-prefix. The address-only indicates that the regular\n"
1069  " address (v4 or v6) will be requested. The prefix-only indicates\n"
1070  " that the IPv6 prefix will be requested. The address-and-prefix\n"
1071  " indicates that both IPv6 address and prefix will be requested.\n"
1072  " The '-e prefix-only' and -'e address-and-prefix' must not be\n"
1073  " used with -4.\n"
1074  "-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)\n"
1075  " elapsed-time option in the (second/request) template.\n"
1076  " The value 0 disables it.\n"
1077  "-f<renew-rate>: Rate at which DHCPv4 or DHCPv6 renew requests are sent\n"
1078  " to a server. This value is only valid when used in conjunction\n"
1079  " with the exchange rate (given by -r<rate>). Furthermore the sum of\n"
1080  " this value and the release-rate (given by -F<rate) must be equal\n"
1081  " to or less than the exchange rate.\n"
1082  "-h: Print this help.\n"
1083  "-i: Do only the initial part of an exchange: DO or SA, depending on\n"
1084  " whether -6 is given.\n"
1085  "-I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP\n"
1086  " option / (DHCPv6) IA_NA option in the (second/request) template.\n"
1087  "-l<local-addr|interface>: For DHCPv4 operation, specify the local\n"
1088  " hostname/address to use when communicating with the server. By\n"
1089  " default, the interface address through which traffic would\n"
1090  " normally be routed to the server is used.\n"
1091  " For DHCPv6 operation, specify the name of the network interface\n"
1092  " via which exchanges are initiated.\n"
1093  "-L<local-port>: Specify the local port to use\n"
1094  " (the value 0 means to use the default).\n"
1095  "-M<mac-list-file>: A text file containing a list of MAC addresses,\n"
1096  " one per line. If provided, a MAC address will be chosen randomly\n"
1097  " from this list for every new exchange. In the DHCPv6 case, MAC\n"
1098  " addresses are used to generate DUID-LLs. This parameter must not be\n"
1099  " used in conjunction with the -b parameter.\n"
1100  "-O<random-offset>: Offset of the last octet to randomize in the template.\n"
1101  "-P<preload>: Initiate first <preload> exchanges back to back at startup.\n"
1102  "-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)\n"
1103  " exchanges per second. A periodic report is generated showing the\n"
1104  " number of exchanges which were not completed, as well as the\n"
1105  " average response latency. The program continues until\n"
1106  " interrupted, at which point a final report is generated.\n"
1107  "-R<range>: Specify how many different clients are used. With 1\n"
1108  " (the default), all requests seem to come from the same client.\n"
1109  "-s<seed>: Specify the seed for randomization, making it repeatable.\n"
1110  "-S<srvid-offset>: Offset of the server-ID option in the\n"
1111  " (second/request) template.\n"
1112  "-T<template-file>: The name of a file containing the template to use\n"
1113  " as a stream of hexadecimal digits.\n"
1114  "-v: Report the version number of this program.\n"
1115  "-W<time>: Specifies exit-wait-time parameter, that makes perfdhcp wait\n"
1116  " for <time> us after an exit condition has been met to receive all\n"
1117  " packets without sending any new packets. Expressed in microseconds.\n"
1118  "-w<wrapped>: Command to call with start/stop at the beginning/end of\n"
1119  " the program.\n"
1120  "-x<diagnostic-selector>: Include extended diagnostics in the output.\n"
1121  " <diagnostic-selector> is a string of single-keywords specifying\n"
1122  " the operations for which verbose output is desired. The selector\n"
1123  " keyletters are:\n"
1124  " * 'a': print the decoded command line arguments\n"
1125  " * 'e': print the exit reason\n"
1126  " * 'i': print rate processing details\n"
1127  " * 's': print first server-id\n"
1128  " * 't': when finished, print timers of all successful exchanges\n"
1129  " * 'T': when finished, print templates\n"
1130  "-X<xid-offset>: Transaction ID (aka. xid) offset in the template.\n"
1131  "\n"
1132  "DHCPv4 only options:\n"
1133  "-B: Force broadcast handling.\n"
1134  "\n"
1135  "DHCPv6 only options:\n"
1136  "-c: Add a rapid commit option (exchanges will be SA).\n"
1137  "-F<release-rate>: Rate at which IPv6 Release requests are sent to\n"
1138  " a server. This value is only valid when used in conjunction with\n"
1139  " the exchange rate (given by -r<rate>). Furthermore the sum of\n"
1140  " this value and the renew-rate (given by -f<rate) must be equal\n"
1141  " to or less than the exchange rate.\n"
1142  "-A<encapsulation-level>: Specifies that relayed traffic must be\n"
1143  " generated. The argument specifies the level of encapsulation, i.e.\n"
1144  " how many relay agents are simulated. Currently the only supported\n"
1145  " <encapsulation-level> value is 1, which means that the generated\n"
1146  " traffic is an equivalent of the traffic passing through a single\n"
1147  " relay agent.\n"
1148  "\n"
1149  "The remaining options are typically used in conjunction with -r:\n"
1150  "\n"
1151  "-D<max-drop>: Abort the test immediately if max-drop requests have\n"
1152  " been dropped. max-drop must be a positive integer. If max-drop\n"
1153  " includes the suffix '%', it specifies a maximum percentage of\n"
1154  " requests that may be dropped before abort. In this case, testing\n"
1155  " of the threshold begins after 10 requests have been expected to\n"
1156  " be received.\n"
1157  "-n<num-request>: Initiate <num-request> transactions. No report is\n"
1158  " generated until all transactions have been initiated/waited-for,\n"
1159  " after which a report is generated and the program terminates.\n"
1160  "-p<test-period>: Send requests for the given test period, which is\n"
1161  " specified in the same manner as -d. This can be used as an\n"
1162  " alternative to -n, or both options can be given, in which case the\n"
1163  " testing is completed when either limit is reached.\n"
1164  "-t<report>: Delay in seconds between two periodic reports.\n"
1165  "\n"
1166  "Errors:\n"
1167  "- tooshort: received a too short message\n"
1168  "- orphans: received a message which doesn't match an exchange\n"
1169  " (duplicate, late or not related)\n"
1170  "- locallimit: reached to local system limits when sending a message.\n"
1171  "\n"
1172  "Exit status:\n"
1173  "The exit status is:\n"
1174  "0 on complete success.\n"
1175  "1 for a general error.\n"
1176  "2 if an error is found in the command line arguments.\n"
1177  "3 if there are no general failures in operation, but one or more\n"
1178  " exchanges are not successfully completed.\n";
1179 }
1180 
1181 void
1183  std::cout << "VERSION: " << VERSION << std::endl;
1184 }
1185 
1186 } // namespace perfdhcp
1187 } // namespace isc
isc::perfdhcp::CommandOptions::LeaseType::is
bool is(const Type lease_type) const
Checks if lease type has the specified code.
Definition: command_options.cc:50
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::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
iface_mgr.h
isc::perfdhcp::CommandOptions::LeaseType::set
void set(const Type lease_type)
Sets the lease type code.
Definition: command_options.cc:60
isc::perfdhcp::CommandOptions::getExchangeMode
ExchangeMode getExchangeMode() const
Returns packet exchange mode.
Definition: command_options.h:142
duid.h
config_report.h
isc::perfdhcp::CommandOptions::reset
void reset()
Reset to defaults.
Definition: command_options.cc:105
isc::perfdhcp::CommandOptions::getRandomOffset
std::vector< int > getRandomOffset() const
Returns template offsets for rnd.
Definition: command_options.h:314
isc::perfdhcp::CommandOptions::isUseRelayedV6
bool isUseRelayedV6() const
Check if generated DHCPv6 messages should appear as relayed.
Definition: command_options.h:284
isc::perfdhcp::CommandOptions::getTemplateFiles
std::vector< std::string > getTemplateFiles() const
Returns template file names.
Definition: command_options.h:289
isc::dhcp::IfaceMgr::getIface
IfacePtr getIface(int ifindex)
Returns interface specified interface index.
Definition: iface_mgr.cc:752
DHCP_IPV4_BROADCAST_ADDRESS
#define DHCP_IPV4_BROADCAST_ADDRESS
Definition: dhcp4.h:42
isc::perfdhcp::CommandOptions::LeaseType::Type
Type
The lease type code.
Definition: command_options.h:41
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::LeaseType::fromCommandLine
void fromCommandLine(const std::string &cmd_line_arg)
Sets the lease type from the command line argument.
Definition: command_options.cc:65
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
ALL_DHCP_SERVERS
#define ALL_DHCP_SERVERS
Definition: dhcp6.h:303
isc::perfdhcp::CommandOptions
Command Options.
Definition: command_options.h:25
isc::perfdhcp::CommandOptions::version
void version() const
Print program version.
Definition: command_options.cc:1182
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
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::perfdhcp::CommandOptions::parse
bool parse(int argc, char **const argv, bool print_cmd_line=false)
Parse command line.
Definition: command_options.cc:161
isc::perfdhcp::CommandOptions::getIpVersion
uint8_t getIpVersion() const
Returns IP version.
Definition: command_options.h:137
perfdhcp
hex.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
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::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::CommandOptions::LeaseType::toText
std::string toText() const
Return textual representation of the lease type.
Definition: command_options.cc:83
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
isc::perfdhcp::CommandOptions::getTransactionIdOffset
std::vector< int > getTransactionIdOffset() const
brief Returns template offsets for xid.
Definition: command_options.h:309
isc::dhcp::DUID::DUID_LLT
@ DUID_LLT
link-layer + time, see RFC3315, section 11.2
Definition: duid.h:40
isc::perfdhcp::CommandOptions::getDropTime
std::vector< double > getDropTime() const
Returns drop time.
Definition: command_options.h:205
isc::dhcp::IfaceMgr::instance
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
isc::dhcp
Definition: ctrl_dhcp4_srv.cc:75
isc::perfdhcp::CommandOptions::LeaseType::includes
bool includes(const Type lease_type) const
Checks if lease type implies request for the address, prefix (or both) as specified by the function a...
Definition: command_options.cc:55
isc::perfdhcp::CommandOptions::getLeaseType
LeaseType getLeaseType() const
\ brief Returns the type of lease being requested.
Definition: command_options.h:147
isc::perfdhcp::CommandOptions::getRate
int getRate() const
Returns exchange rate.
Definition: command_options.h:152
isc::perfdhcp::CommandOptions::isRapidCommit
bool isRapidCommit() const
Check if rapid commit option used.
Definition: command_options.h:274
isc::dhcp::IfaceMgr
Handles network interfaces, transmission and reception.
Definition: iface_mgr.h:478
isc::perfdhcp::CommandOptions::LeaseType::LeaseType
LeaseType()
Definition: command_options.cc:41
isc::perfdhcp::CommandOptions::isUseFirst
bool isUseFirst() const
Check if server-ID to be taken from first package.
Definition: command_options.h:279
isc::perfdhcp::CommandOptions::getNumRequests
std::vector< int > getNumRequests() const
Returns maximum number of exchanges.
Definition: command_options.h:192
isc::perfdhcp::CommandOptions::getReleaseRate
int getReleaseRate() const
Returns a rate at which DHCPv6 Release messages are sent.
Definition: command_options.h:162
isc::detail::config_report
const char *const config_report[]
isc::perfdhcp::CommandOptions::LeaseType::ADDRESS
@ ADDRESS
Definition: command_options.h:42
isc::perfdhcp::perfdhcp_config_report
const char *const * perfdhcp_config_report
Definition: command_options.cc:39
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
exceptions.h
isc::perfdhcp::CommandOptions::getMaxDrop
std::vector< int > getMaxDrop() const
Returns maximum drops number.
Definition: command_options.h:213
isc::perfdhcp::CommandOptions::getLocalPort
int getLocalPort() const
Returns local port number.
Definition: command_options.h:249
ALL_DHCP_RELAY_AGENTS_AND_SERVERS
#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS
Definition: dhcp6.h:302
option.h
isc::perfdhcp::CommandOptions::usage
void usage() const
Print usage.
Definition: command_options.cc:1022
isc::dhcp::Option
Definition: option.h:58
command_options.h
isc::perfdhcp::CommandOptions::getMacListFile
std::string getMacListFile() const
Returns location of the file containing list of MAC addresses.
Definition: command_options.h:297
isc::util::encode::decodeHex
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 ('hex') format into the original data.
Definition: base_n.cc:466