17 #include <boost/lexical_cast.hpp>
18 #include <boost/date_time/posix_time/posix_time.hpp>
41 CommandOptions::LeaseType::LeaseType()
51 return (lease_type == type_);
56 return (is(ADDRESS_AND_PREFIX) || (lease_type == type_));
66 if (cmd_line_arg ==
"address-only") {
69 }
else if (cmd_line_arg ==
"prefix-only") {
72 }
else if (cmd_line_arg ==
"address-and-prefix") {
73 type_ = ADDRESS_AND_PREFIX;
77 " must be one of the following: 'address-only' or"
86 return (
"address-only (IA_NA option added to the client's request)");
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)");
94 " returning textual representation of the lease type");
108 uint8_t mac[6] = { 0x0, 0xC, 0x1, 0x2, 0x3, 0x4 };
112 double dt[2] = { 1., 1. };
124 mac_template_.assign(mac, mac + 6);
125 duid_template_.clear();
127 mac_list_file_.clear();
129 num_request_.clear();
133 drop_time_.assign(dt, dt + 2);
137 is_interface_ =
false;
144 rapid_commit_ =
false;
146 template_file_.clear();
154 server_name_.clear();
155 v6_relay_encapsulation_level_ = 0;
156 generateDuidTemplate();
199 bool help_or_version_mode = initialize(argc, argv, print_cmd_line);
200 if (!help_or_version_mode) {
203 return (help_or_version_mode);
207 CommandOptions::initialize(
int argc,
char** argv,
bool print_cmd_line) {
209 std::string drop_arg;
210 size_t percent_loc = 0;
211 double drop_percent = 0;
218 std::ostringstream stream;
219 stream <<
"perfdhcp";
220 int num_mac_list_files = 0;
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);
228 stream <<
" " << optarg;
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) {
249 check(ipversion_ == 6,
"IP version already set to 6");
254 check(ipversion_ == 4,
"IP version already set to 4");
259 aggressivity_ = positiveInteger(
"value of aggressivity: -a<value>"
260 " must be a positive integer");
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());
275 rapid_commit_ =
true;
279 check(drop_time_set_ > 1,
280 "maximum number of drops already specified, "
281 "unexpected 3rd occurrence of -d<value>");
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");
290 check(drop_time_[drop_time_set_] <= 0.,
291 "drop-time must be a positive number");
292 drop_time_set_ =
true;
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) {
304 boost::lexical_cast<double>(drop_arg.substr(0, percent_loc));
305 }
catch (boost::bad_lexical_cast&) {
307 "value of drop percentage: -D<value%>"
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);
314 num_drops = positiveInteger(
"value of max drops number:"
315 " -D<value> must be a positive integer");
316 max_drop_.push_back(num_drops);
325 elp_offset_ = nonNegativeInteger(
"value of time-offset: -E<value>"
326 " must not be a negative integer");
330 renew_rate_ = positiveInteger(
"value of the renew rate: -f<renew-rate>"
331 " must be a positive integer");
335 release_rate_ = positiveInteger(
"value of the release rate:"
336 " -F<release-rate> must be a"
337 " positive integer");
345 exchange_mode_ =
DO_SA;
349 rip_offset_ = positiveInteger(
"value of ip address offset:"
350 " -I<value> must be a"
351 " positive integer");
355 localname_ = std::string(optarg);
360 local_port_ = nonNegativeInteger(
"value of local port:"
361 " -L<value> must not be a"
362 " negative integer");
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()));
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);
377 exit_wait_time_ = nonNegativeInteger(
"value of exist wait time: "
378 "-W<value> must not be a "
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"
391 num_request_.push_back(num_req);
395 if (rnd_offset_.size() < 2) {
396 offset_arg = positiveInteger(
"value of random offset: "
397 "-O<value> must be greater than 3");
400 "random offsets already specified,"
401 " unexpected 3rd occurrence of -O<value>");
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);
410 check( (ipversion_ != 4) && (ipversion_ != 6),
411 "-4 or -6 must be explicitly specified before -o is used.");
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'");
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&) {
428 "-o option, expected format: -o<integer>,<hexstring>");
432 opt_text = opt_text.substr(coma_loc + 1);
433 std::vector<uint8_t> bin;
444 extra_opts_.insert(make_pair(code, opt));
448 period_ = positiveInteger(
"value of test period:"
449 " -p<value> must be a positive integer");
453 preload_ = nonNegativeInteger(
"number of preload packets:"
454 " -P<value> must not be "
455 "a negative integer");
459 rate_ = positiveInteger(
"value of rate:"
460 " -r<value> must be a positive integer");
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;
475 sid_offset_ = positiveInteger(
"value of server id offset:"
476 " -S<value> must be a"
477 " positive integer");
481 report_delay_ = positiveInteger(
"value of report delay:"
482 " -t<value> must be a"
483 " positive integer");
487 if (template_file_.size() < 2) {
488 sarg = nonEmptyString(
"template file name not specified,"
489 " expected -T<filename>");
490 template_file_.push_back(sarg);
493 "template files are already specified,"
494 " unexpected 3rd -T<filename> occurrence");
503 wrapped_ = nonEmptyString(
"command for wrapped mode:"
504 " -w<command> must be specified");
508 diags_ = nonEmptyString(
"value of diagnostics selectors:"
509 " -x<value> must be specified");
513 if (xid_offset_.size() < 2) {
514 offset_arg = positiveInteger(
"value of transaction id:"
515 " -X<value> must be a"
516 " positive integer");
519 "transaction ids already specified,"
520 " unexpected 3rd -X<value> occurrence");
522 xid_offset_.push_back(offset_arg);
532 if (ipversion_ == 0) {
541 if (template_file_.size() > 1) {
542 if (xid_offset_.size() == 1) {
543 xid_offset_.push_back(xid_offset_[0]);
545 if (rnd_offset_.size() == 1) {
546 rnd_offset_.push_back(rnd_offset_[0]);
554 check(optind < argc -1,
"extra arguments?");
555 if (optind == argc - 1) {
556 server_name_ = argv[optind];
557 stream <<
" " << server_name_;
559 if ((ipversion_ == 4) && (server_name_.compare(
"all") == 0)) {
563 }
else if ((ipversion_ == 6) && (server_name_.compare(
"all") == 0)) {
565 }
else if ((ipversion_ == 6) &&
566 (server_name_.compare(
"servers") == 0)) {
571 if (print_cmd_line) {
572 std::cout <<
"Running: " << stream.str() << std::endl;
576 if (!localname_.empty()) {
577 if (server_name_.empty()) {
578 if (is_interface_ && (ipversion_ == 4)) {
581 }
else if (is_interface_ && (ipversion_ == 6)) {
586 if (server_name_.empty()) {
588 "without an interface, server is required");
593 if (duid_template_.empty()) {
594 generateDuidTemplate();
600 CommandOptions::initClientsNum() {
601 const std::string errmsg =
602 "value of -R <value> must be non-negative integer";
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&) {
618 CommandOptions::initIsInterface() {
619 is_interface_ =
false;
620 if (!localname_.empty()) {
622 if (iface_mgr.
getIface(localname_) != NULL) {
623 is_interface_ =
true;
629 CommandOptions::decodeBase(
const std::string& base) {
631 boost::algorithm::to_lower(b);
634 if ((b.substr(0, 4) ==
"mac=") || (b.substr(0, 6) ==
"ether=")) {
636 }
else if (b.substr(0, 5) ==
"duid=") {
640 "base value not provided as -b<value>,"
641 " expected -b mac=<mac> or -b duid=<duid>");
646 CommandOptions::decodeMacBase(
const std::string& base) {
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);
655 std::istringstream s1(base.substr(found + 1));
657 mac_template_.clear();
659 while (std::getline(s1, token,
':')) {
661 if (token.length() > 0) {
665 ui = convertHexString(token);
668 "invalid characters in MAC provided");
672 mac_template_.push_back(ui);
676 check(mac_template_.size() != 6, errmsg);
680 CommandOptions::decodeDuid(
const std::string& base) {
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);
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");
694 for (
size_t i = 0; i < b.length(); i += 2) {
698 ui = convertHexString(b.substr(i, 2));
701 "invalid characters in DUID provided,"
702 " expected hex digits");
704 duid_template.push_back(
static_cast<uint8_t
>(ui));
709 check(duid_template.size() < 6,
"DUID must be at least 6 octets long");
711 std::swap(duid_template, duid_template_);
715 CommandOptions::generateDuidTemplate() {
716 using namespace boost::posix_time;
720 duid_template_.clear();
721 const uint8_t duid_template_len = 14;
722 duid_template_.resize(duid_template_len);
726 duid_template_[2] = HWTYPE_ETHERNET >> 8;
727 duid_template_[3] = HWTYPE_ETHERNET & 0xff;
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);
741 memcpy(&duid_template_[8], &mac_template_[0], 6);
745 CommandOptions::convertHexString(
const std::string& text)
const {
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");
756 std::istringstream text_stream(text);
757 text_stream >> std::hex >> ui >> std::dec;
761 " two hex digits to byte");
766 void CommandOptions::loadMacs() {
768 std::ifstream infile(mac_list_file_.c_str());
770 while (std::getline(infile, line)) {
773 tmp <<
"invalid mac in input line " << cnt;
775 check(decodeMacString(line), tmp.str());
779 bool CommandOptions::decodeMacString(
const std::string& line) {
781 std::istringstream s(line);
783 std::vector<uint8_t> mac;
784 while(std::getline(s, token,
':')) {
786 if (token.length() > 0) {
790 ui = convertHexString(token);
798 mac_list_.push_back(mac);
803 CommandOptions::validate()
const {
805 "-B is not compatible with IPv6 (-6)");
807 "-6 (IPv6) must be set to use -c");
809 "Can't use -4 with -A, it's a V6 only option.");
811 "-F<release-rate> may be used with -6 (IPv6) only");
813 "second -n<num-request> is not compatible with -i");
815 "-6 option must be used if lease type other than '-e address-only'"
819 "template files may be only used with '-e address-only'");
821 "second -d<drop-time> is not compatible with -i");
824 "second -D<max-drop> is not compatible with -i");
826 "-1 is not compatible with -i");
828 "second -T<template-file> is not compatible with -i");
830 "second -X<xid-offset> is not compatible with -i");
832 "second -O<random-offset is not compatible with -i");
834 "-E<time-offset> is not compatible with -i");
836 "-S<srvid-offset> is not compatible with -i");
838 "-I<ip-offset> is not compatible with -i");
840 "-f<renew-rate> is not compatible with -i");
842 "-F<release-rate> is not compatible with -i");
844 "-i must be set to use -c");
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>");
850 "Renew rate specified as -f<renew-rate> must not be specified"
851 " when -r<rate> parameter is not specified");
853 "Release rate specified as -F<release-rate> must not be specified"
854 " when -r<rate> parameter is not specified");
856 "-T<template-file> must be set to use -X<xid-offset>");
858 "-T<template-file> must be set to use -O<random-offset>");
860 "second/request -T<template-file> must be set to use -E<time-offset>");
862 "second/request -T<template-file> must be set to "
863 "use -S<srvid-offset>");
865 "second/request -T<template-file> must be set to "
866 "use -I<ip-offset>");
868 "Can't use -b with -M option");
872 CommandOptions::check(
bool condition,
const std::string& errmsg)
const {
875 std::ostringstream stream;
876 stream << errmsg <<
"\n";
883 CommandOptions::positiveInteger(
const std::string& errmsg)
const {
885 int value = boost::lexical_cast<int>(optarg);
886 check(value <= 0, errmsg);
888 }
catch (boost::bad_lexical_cast&) {
894 CommandOptions::nonNegativeInteger(
const std::string& errmsg)
const {
896 int value = boost::lexical_cast<int>(optarg);
897 check(value < 0, errmsg);
899 }
catch (boost::bad_lexical_cast&) {
905 CommandOptions::nonEmptyString(
const std::string& errmsg)
const {
906 std::string sarg = optarg;
907 if (sarg.length() == 0) {
914 CommandOptions::initLeaseType() {
915 std::string lease_type_arg = optarg;
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;
926 std::cout <<
"SOLICIT-ADVERTISE only" << std::endl;
931 std::cout <<
"rate[1/s]=" << rate_ << std::endl;
934 std::cout <<
"renew-rate[1/s]=" <<
getRenewRate() << std::endl;
937 std::cout <<
"release-rate[1/s]=" <<
getReleaseRate() << std::endl;
939 if (report_delay_ != 0) {
940 std::cout <<
"report[s]=" << report_delay_ << std::endl;
942 if (clients_num_ != 0) {
943 std::cout <<
"clients=" << clients_num_ << std::endl;
945 for (
size_t i = 0; i < base_.size(); ++i) {
946 std::cout <<
"base[" << i <<
"]=" << base_[i] << std::endl;
948 for (
size_t i = 0; i < num_request_.size(); ++i) {
949 std::cout <<
"num-request[" << i <<
"]=" << num_request_[i] << std::endl;
952 std::cout <<
"test-period=" << period_ << std::endl;
954 for (
size_t i = 0; i < drop_time_.size(); ++i) {
955 std::cout <<
"drop-time[" << i <<
"]=" << drop_time_[i] << std::endl;
957 for (
size_t i = 0; i < max_drop_.size(); ++i) {
958 std::cout <<
"max-drop{" << i <<
"]=" << max_drop_[i] << std::endl;
960 for (
size_t i = 0; i < max_pdrop_.size(); ++i) {
961 std::cout <<
"max-pdrop{" << i <<
"]=" << max_pdrop_[i] << std::endl;
964 std::cout <<
"preload=" << preload_ << std::endl;
966 std::cout <<
"aggressivity=" << aggressivity_ << std::endl;
968 std::cout <<
"local-port=" << local_port_ << std::endl;
971 std::cout <<
"seed=" << seed_ << std::endl;
974 std::cout <<
"broadcast" << std::endl;
977 std::cout <<
"rapid-commit" << std::endl;
980 std::cout <<
"use-first" << std::endl;
982 if (!mac_list_file_.empty()) {
983 std::cout <<
"mac-list-file=" << mac_list_file_ << std::endl;
985 for (
size_t i = 0; i < template_file_.size(); ++i) {
986 std::cout <<
"template-file[" << i <<
"]=" << template_file_[i] << std::endl;
988 for (
size_t i = 0; i < xid_offset_.size(); ++i) {
989 std::cout <<
"xid-offset[" << i <<
"]=" << xid_offset_[i] << std::endl;
991 if (elp_offset_ != 0) {
992 std::cout <<
"elp-offset=" << elp_offset_ << std::endl;
994 for (
size_t i = 0; i < rnd_offset_.size(); ++i) {
995 std::cout <<
"rnd-offset[" << i <<
"]=" << rnd_offset_[i] << std::endl;
997 if (sid_offset_ != 0) {
998 std::cout <<
"sid-offset=" << sid_offset_ << std::endl;
1000 if (rip_offset_ != 0) {
1001 std::cout <<
"rip-offset=" << rip_offset_ << std::endl;
1003 if (!diags_.empty()) {
1004 std::cout <<
"diagnostic-selectors=" << diags_ << std::endl;
1006 if (!wrapped_.empty()) {
1007 std::cout <<
"wrapped=" << wrapped_ << std::endl;
1009 if (!localname_.empty()) {
1010 if (is_interface_) {
1011 std::cout <<
"interface=" << localname_ << std::endl;
1013 std::cout <<
"local-addr=" << localname_ << std::endl;
1016 if (!server_name_.empty()) {
1017 std::cout <<
"server=" << server_name_ << std::endl;
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"
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"
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"
1048 "The default is to perform a single 4-way exchange, effectively pinging\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"
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"
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"
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"
1132 "DHCPv4 only options:\n"
1133 "-B: Force broadcast handling.\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"
1149 "The remaining options are typically used in conjunction with -r:\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"
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"
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"
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";
1183 std::cout <<
"VERSION: " << VERSION << std::endl;