25 #include <boost/date_time/posix_time/posix_time.hpp>
45 bool TestControl::interrupted_ =
false;
48 TestControl::waitToExit() {
49 uint32_t
const wait_time = options_.getExitWaitTime();
52 if (wait_time && !haveAllPacketsBeenReceived()) {
53 const ptime now = microsec_clock::universal_time();
56 if (exit_time_.is_not_a_date_time()) {
57 exit_time_ = now + time_duration(microseconds(wait_time));
61 return (now < exit_time_);
69 TestControl::haveAllPacketsBeenReceived()
const {
70 const uint8_t& ipversion = options_.getIpVersion();
71 const std::vector<int>& num_request = options_.getNumRequests();
72 const size_t& num_request_size = num_request.size();
74 if (num_request_size == 0) {
78 uint32_t responses = 0;
79 uint32_t requests = num_request[0];
80 if (num_request_size >= 2) {
81 requests += num_request[1];
85 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) +
86 stats_mgr_.getRcvdPacketsNum(ExchangeType::RA);
88 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) +
89 stats_mgr_.getRcvdPacketsNum(ExchangeType::RR);
92 return (responses == requests);
96 TestControl::cleanCachedPackets() {
99 if (options_.getRenewRate() == 0) {
103 static boost::posix_time::ptime last_clean =
104 microsec_clock::universal_time();
107 time_period time_since_clean(last_clean,
108 microsec_clock::universal_time());
110 if (time_since_clean.length().total_seconds() >= 1) {
116 if (reply_storage_.size() > 5 * options_.getRenewRate()) {
117 reply_storage_.clear(reply_storage_.size() -
118 5 * options_.getRenewRate());
122 last_clean = microsec_clock::universal_time();
128 if (!pkt_from || !pkt_to) {
130 " for the copyIaOptions function");
133 if (options_.getLeaseType()
134 .includes(CommandOptions::LeaseType::ADDRESS)) {
138 " server's response");
140 pkt_to->addOption(option);
143 if (options_.getLeaseType()
144 .includes(CommandOptions::LeaseType::PREFIX)) {
148 " server's response");
150 pkt_to->addOption(option);
155 TestControl::byte2Hex(
const uint8_t b) {
156 const int b1 = b / 16;
157 const int b0 = b % 16;
158 ostringstream stream;
159 stream << std::hex << b1 << b0 << std::dec;
160 return (stream.str());
167 " null DHCPACK message");
168 }
else if (ack->getYiaddr().isV4Zero()) {
170 " DHCPACK message containing yiaddr of 0");
173 msg->setCiaddr(ack->getYiaddr());
174 msg->setHWAddr(ack->getHWAddr());
175 msg->addOption(generateClientId(msg->getHWAddr()));
180 TestControl::createMessageFromReply(
const uint16_t msg_type,
185 <<
" to be created from Reply, expected DHCPV6_RENEW or"
190 const char* msg_type_str = (msg_type ==
DHCPV6_RENEW ?
"Renew" :
"Release");
194 <<
" message from the Reply message because the instance of"
195 " the Reply message is NULL");
198 Pkt6Ptr msg(
new Pkt6(msg_type, generateTransid()));
203 <<
" message because client id option has not been found"
204 " in the Reply message");
206 msg->addOption(opt_clientid);
211 <<
" because server id option has not been found in the"
214 msg->addOption(opt_serverid);
215 copyIaOptions(reply, msg);
222 if (buf.size() == 2) {
224 }
else if (buf.size() == 0) {
229 "elapsed time option buffer size has to be 0 or 2");
243 const uint8_t buf_array[] = {
245 0, 0, 3600 >> 8, 3600 & 0xff,
246 0, 0, 5400 >> 8, 5400 & 0xff,
248 OptionBuffer buf_ia_na(buf_array, buf_array +
sizeof(buf_array));
249 for (
size_t i = 0; i < buf.size(); ++i) {
250 buf_ia_na.push_back(buf[i]);
259 static const uint8_t buf_array[] = {
261 0, 0, 3600 >> 8, 3600 & 0xff,
262 0, 0, 5400 >> 8, 5400 & 0xff,
264 OptionBuffer buf_ia_pd(buf_array, buf_array +
sizeof(buf_array));
266 buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
281 const uint8_t buf_array[] = {
285 OptionBuffer buf_with_options(buf_array, buf_array +
sizeof(buf_array));
294 const uint8_t buf_array[] = {
304 OptionBuffer buf_with_options(buf_array, buf_array +
sizeof(buf_array));
306 opt->setData(buf_with_options.begin(), buf_with_options.end());
311 TestControl::generateMacAddress(uint8_t& randomized) {
314 if (macs.size() > 0) {
315 uint16_t r = number_generator_();
316 if (r >= macs.size()) {
323 uint32_t clients_num = options_.getClientsNum();
324 if (clients_num < 2) {
325 return (options_.getMacTemplate());
328 std::vector<uint8_t> mac_addr(options_.getMacTemplate());
329 if (mac_addr.size() != HW_ETHER_LEN) {
332 uint32_t r = macaddr_gen_->generate();
335 for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
336 it >= mac_addr.begin();
358 std::vector<uint8_t> client_id(1, static_cast<uint8_t>(hwaddr->htype_));
359 client_id.insert(client_id.end(), hwaddr->hwaddr_.begin(),
360 hwaddr->hwaddr_.end());
366 TestControl::generateDuid(uint8_t& randomized) {
367 std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
370 if (macs.size() > 0) {
371 uint16_t r = number_generator_();
372 if (r >= macs.size()) {
375 std::vector<uint8_t> mac = macs[r];
389 uint8_t duid_ll[] = {0, 3, 0, 1, 0, 0, 0, 0, 0, 0};
391 std::vector<uint8_t> duid(duid_ll,
392 duid_ll +
sizeof(duid_ll) /
sizeof(duid_ll[0]));
394 std::copy(mac.begin(), mac.end(), duid.begin() + 4);
397 uint32_t clients_num = options_.getClientsNum();
398 if ((clients_num == 0) || (clients_num == 1)) {
399 return (options_.getDuidTemplate());
402 std::vector<uint8_t> duid(options_.getDuidTemplate());
404 duid.resize(duid.size());
405 std::copy(mac_addr.begin(), mac_addr.end(),
406 duid.begin() + duid.size() - mac_addr.size());
412 TestControl::getElapsedTimeOffset()
const {
413 int elp_offset = options_.getIpVersion() == 4 ?
414 DHCPV4_ELAPSED_TIME_OFFSET : DHCPV6_ELAPSED_TIME_OFFSET;
415 if (options_.getElapsedTimeOffset() > 0) {
416 elp_offset = options_.getElapsedTimeOffset();
423 TestControl::getElapsedTime(
const T& pkt1,
const T& pkt2) {
425 ptime pkt1_time = pkt1->getTimestamp();
426 ptime pkt2_time = pkt2->getTimestamp();
427 if (pkt1_time.is_not_a_date_time() ||
428 pkt2_time.is_not_a_date_time()) {
431 time_period elapsed_period(pkt1_time, pkt2_time);
432 return (elapsed_period.is_null() ? 0 :
433 elapsed_period.length().total_milliseconds());
437 TestControl::getRandomOffset(
const int arg_idx)
const {
438 int rand_offset = options_.getIpVersion() == 4 ?
439 DHCPV4_RANDOMIZATION_OFFSET : DHCPV6_RANDOMIZATION_OFFSET;
440 if (options_.getRandomOffset().size() > arg_idx) {
441 rand_offset = options_.getRandomOffset()[arg_idx];
443 return (rand_offset);
447 TestControl::getRequestedIpOffset()
const {
448 int rip_offset = options_.getIpVersion() == 4 ?
449 DHCPV4_REQUESTED_IP_OFFSET : DHCPV6_IA_NA_OFFSET;
450 if (options_.getRequestedIpOffset() > 0) {
451 rip_offset = options_.getRequestedIpOffset();
457 TestControl::getServerIdOffset()
const {
458 int srvid_offset = options_.getIpVersion() == 4 ?
459 DHCPV4_SERVERID_OFFSET : DHCPV6_SERVERID_OFFSET;
460 if (options_.getServerIdOffset() > 0) {
461 srvid_offset = options_.getServerIdOffset();
463 return (srvid_offset);
467 TestControl::getTemplateBuffer(
const size_t idx)
const {
468 if (template_buffers_.size() > idx) {
469 return (template_buffers_[idx]);
475 TestControl::getTransactionIdOffset(
const int arg_idx)
const {
476 int xid_offset = options_.getIpVersion() == 4 ?
477 DHCPV4_TRANSID_OFFSET : DHCPV6_TRANSID_OFFSET;
478 if (options_.getTransactionIdOffset().size() > arg_idx) {
479 xid_offset = options_.getTransactionIdOffset()[arg_idx];
485 TestControl::handleChild(
int) {
487 while (wait3(&status, WNOHANG, NULL) > 0) {
493 TestControl::handleInterrupt(
int) {
498 TestControl::initPacketTemplates() {
499 template_packets_v4_.clear();
500 template_packets_v6_.clear();
501 template_buffers_.clear();
502 std::vector<std::string> template_files = options_.getTemplateFiles();
503 for (std::vector<std::string>::const_iterator it = template_files.begin();
504 it != template_files.end(); ++it) {
505 readPacketTemplate(*it);
510 TestControl::sendPackets(
const uint64_t packets_num,
511 const bool preload ) {
512 for (uint64_t i = packets_num; i > 0; --i) {
513 if (options_.getIpVersion() == 4) {
516 if (template_buffers_.empty()) {
517 sendDiscover4(preload);
521 sendDiscover4(template_buffers_[0], preload);
526 if (template_buffers_.empty()) {
527 sendSolicit6(preload);
531 sendSolicit6(template_buffers_[0], preload);
538 TestControl::sendMultipleRequests(
const uint64_t msg_num) {
539 for (uint64_t i = 0; i < msg_num; ++i) {
540 if (!sendRequestFromAck()) {
548 TestControl::sendMultipleMessages6(
const uint32_t msg_type,
549 const uint64_t msg_num) {
550 for (uint64_t i = 0; i < msg_num; ++i) {
551 if (!sendMessageFromReply(msg_type)) {
559 TestControl::printDiagnostics()
const {
560 if (options_.testDiags(
'a')) {
562 options_.printCommandLine();
564 std::cout <<
"Set MAC to " << vector2Hex(options_.getMacTemplate(),
"::")
566 if (options_.getDuidTemplate().size() > 0) {
567 std::cout <<
"Set DUID to " << vector2Hex(options_.getDuidTemplate()) << std::endl;
573 TestControl::printTemplate(
const uint8_t packet_type)
const {
576 if (options_.getIpVersion() == 4) {
580 std::map<uint8_t, dhcp::Pkt4Ptr>::const_iterator pkt_it =
581 template_packets_v4_.find(packet_type);
582 if ((pkt_it != template_packets_v4_.end()) &&
585 const char* out_buf_data =
586 static_cast<const char*
>(out_buf.getData());
587 std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
588 hex_buf = vector2Hex(buf);
590 }
else if (options_.getIpVersion() == 6) {
594 std::map<uint8_t, dhcp::Pkt6Ptr>::const_iterator pkt_it =
595 template_packets_v6_.find(packet_type);
596 if (pkt_it != template_packets_v6_.end() &&
599 const char* out_buf_data =
600 static_cast<const char*
>(out_buf.getData());
601 std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
602 hex_buf = vector2Hex(buf);
605 std::cout <<
"xid-offset=" << getTransactionIdOffset(arg_idx) << std::endl;
606 std::cout <<
"random-offset=" << getRandomOffset(arg_idx) << std::endl;
608 std::cout <<
"srvid-offset=" << getServerIdOffset() << std::endl;
609 std::cout <<
"time-offset=" << getElapsedTimeOffset() << std::endl;
610 std::cout <<
"ip-offset=" << getRequestedIpOffset() << std::endl;
613 std::cout <<
"contents: " << std::endl;
616 while (line_len == 32) {
617 if (hex_buf.length() - i < 32) {
618 line_len = hex_buf.length() - i;
621 std::cout << setfill(
'0') << setw(4) << std::hex << i << std::dec
622 <<
" " << hex_buf.substr(i, line_len) << std::endl;
626 std::cout << std::endl;
630 TestControl::printTemplates()
const {
631 if (options_.getIpVersion() == 4) {
634 }
else if (options_.getIpVersion() == 6) {
641 TestControl::printRate()
const {
643 std::string exchange_name =
"4-way exchanges";
645 if (options_.getIpVersion() == 4) {
647 options_.getExchangeMode() == CommandOptions::DO_SA ?
648 ExchangeType::DO : ExchangeType::RA;
649 if (xchg_type == ExchangeType::DO) {
650 exchange_name =
"DISCOVER-OFFER";
652 }
else if (options_.getIpVersion() == 6) {
654 options_.getExchangeMode() == CommandOptions::DO_SA ?
655 ExchangeType::SA : ExchangeType::RR;
656 if (xchg_type == ExchangeType::SA) {
657 exchange_name = options_.isRapidCommit() ?
"Solicit-Reply" :
662 stats_mgr_.getTestPeriod().length().total_nanoseconds() / 1e9;
663 rate = stats_mgr_.getRcvdPacketsNum(xchg_type) / duration;
664 std::ostringstream s;
665 s <<
"***Rate statistics***" << std::endl;
666 s <<
"Rate: " << rate <<
" " << exchange_name <<
"/second";
667 if (options_.getRate() > 0) {
668 s <<
", expected rate: " << options_.getRate() << std::endl;
671 std::cout << s.str() << std::endl;
673 std::cout <<
"***Malformed Packets***" << std::endl
674 <<
"Malformed packets: " << ExchangeStats::malformed_pkts_
679 TestControl::printIntermediateStats() {
680 int delay = options_.getReportDelay();
681 ptime now = microsec_clock::universal_time();
682 time_period time_since_report(last_report_, now);
683 if (time_since_report.length().total_seconds() >= delay) {
684 stats_mgr_.printIntermediateStats(options_.getCleanReport(),
685 options_.getCleanReportSeparator());
691 TestControl::printStats()
const {
693 stats_mgr_.printStats();
694 if (options_.testDiags(
'i')) {
695 stats_mgr_.printCustomCounters();
700 TestControl::vector2Hex(
const std::vector<uint8_t>& vec,
701 const std::string& separator ) {
702 std::ostringstream stream;
703 for (std::vector<uint8_t>::const_iterator it = vec.begin();
706 if (it == vec.begin()) {
707 stream << byte2Hex(*it);
709 stream << separator << byte2Hex(*it);
712 return (stream.str());
716 TestControl::readPacketTemplate(
const std::string& file_name) {
717 std::ifstream temp_file;
718 temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate);
719 if (!temp_file.is_open()) {
723 std::streampos temp_size = temp_file.tellg();
724 if (temp_size == std::streampos(0)) {
728 temp_file.seekg(0, ios::beg);
729 std::vector<char> file_contents(temp_size);
730 temp_file.read(&file_contents[0], temp_size);
736 std::vector<char> hex_digits;
737 for (
size_t i = 0; i < file_contents.size(); ++i) {
738 if (isxdigit(file_contents[i])) {
739 hex_digits.push_back(file_contents[i]);
740 }
else if (!isxdigit(file_contents[i]) &&
741 !isspace(file_contents[i])) {
743 " hexadecimal digit");
747 if (hex_digits.size() % 2 != 0) {
749 }
else if (hex_digits.empty()) {
752 std::vector<uint8_t> binary_stream;
753 for (
size_t i = 0; i < hex_digits.size(); i += 2) {
755 s <<
"0x" << hex_digits[i] << hex_digits[i+1];
758 binary_stream.push_back(static_cast<uint8_t>(b));
760 template_buffers_.push_back(binary_stream);
764 TestControl::processReceivedPacket4(
const Pkt4Ptr& pkt4) {
766 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::DO, pkt4);
767 address4Uniqueness(pkt4, ExchangeType::DO);
768 Pkt4Ptr discover_pkt4(boost::dynamic_pointer_cast<Pkt4>(pkt));
770 if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
771 if (template_buffers_.size() < 2) {
772 sendRequest4(discover_pkt4, pkt4);
776 sendRequest4(template_buffers_[1], discover_pkt4, pkt4);
779 }
else if (pkt4->getType() ==
DHCPACK) {
783 if (stats_mgr_.passRcvdPacket(ExchangeType::RA, pkt4)) {
784 address4Uniqueness(pkt4, ExchangeType::RA);
789 if (stats_mgr_.hasExchangeStats(ExchangeType::RNA)) {
793 ack_storage_.append(pkt4);
800 }
else if (stats_mgr_.hasExchangeStats(ExchangeType::RNA)) {
801 stats_mgr_.passRcvdPacket(ExchangeType::RNA, pkt4);
809 if (options_.getAddrUnique()) {
810 std::set<std::string> current;
813 for (OptionCollection::iterator opt = pkt6->options_.begin();
814 opt != pkt6->options_.end(); ++opt) {
815 switch (opt->second->getType()) {
819 auto ret = current.emplace(boost::dynamic_pointer_cast<
822 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
829 auto ret = current.emplace(boost::dynamic_pointer_cast<
832 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
841 addUniqeAddr(current, xchg_type);
848 if (options_.getAddrUnique()) {
851 std::set<std::string> current;
852 current.insert(pkt4->getYiaddr().toText());
854 addUniqeAddr(current, xchg_type);
859 TestControl::validateIA(
const Pkt6Ptr& pkt6) {
869 iapref = boost::dynamic_pointer_cast<
873 iaaddr = boost::dynamic_pointer_cast<
877 bool address_and_prefix = options_.getLeaseType().includes(
878 CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
879 bool prefix_only = options_.getLeaseType().includes(
880 CommandOptions::LeaseType::PREFIX);
881 bool address_only = options_.getLeaseType().includes(
882 CommandOptions::LeaseType::ADDRESS);
883 if ((address_and_prefix && iapref && iaaddr) ||
884 (prefix_only && iapref && !address_and_prefix) ||
885 (address_only && iaaddr && !address_and_prefix)) {
893 TestControl::processReceivedPacket6(
const Pkt6Ptr& pkt6) {
894 uint8_t packet_type = pkt6->
getType();
896 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::SA, pkt6);
897 Pkt6Ptr solicit_pkt6(boost::dynamic_pointer_cast<Pkt6>(pkt));
899 if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
900 if (validateIA(pkt6)) {
902 address6Uniqueness(pkt6, ExchangeType::SA);
903 if (template_buffers_.size() < 2) {
908 sendRequest6(template_buffers_[1], pkt6);
911 stats_mgr_.updateRejLeases(ExchangeType::SA);
919 if (stats_mgr_.passRcvdPacket(ExchangeType::RR, pkt6)) {
925 if (validateIA(pkt6)) {
927 address6Uniqueness(pkt6, ExchangeType::RR);
929 if (stats_mgr_.hasExchangeStats(ExchangeType::RN) ||
930 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
934 reply_storage_.append(pkt6);
937 stats_mgr_.updateRejLeases(ExchangeType::RR);
946 }
else if (!(stats_mgr_.hasExchangeStats(ExchangeType::RN) &&
947 stats_mgr_.passRcvdPacket(ExchangeType::RN, pkt6)) &&
948 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
951 stats_mgr_.passRcvdPacket(ExchangeType::RL, pkt6);
957 TestControl::consumeReceivedPackets() {
958 unsigned int pkt_count = 0;
960 while ((pkt = receiver_.getPkt())) {
962 if (options_.getIpVersion() == 4) {
963 Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<
Pkt4>(pkt);
964 processReceivedPacket4(pkt4);
966 Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<
Pkt6>(pkt);
967 processReceivedPacket6(pkt6);
973 TestControl::registerOptionFactories4()
const {
974 static bool factories_registered =
false;
975 if (!factories_registered) {
977 LibDHCP::OptionFactoryRegister(Option::V4,
979 &TestControl::factoryGeneric);
981 LibDHCP::OptionFactoryRegister(Option::V4,
983 &TestControl::factoryGeneric);
985 LibDHCP::OptionFactoryRegister(Option::V4,
987 &TestControl::factoryRequestList4);
989 factories_registered =
true;
993 TestControl::registerOptionFactories6()
const {
994 static bool factories_registered =
false;
995 if (!factories_registered) {
997 LibDHCP::OptionFactoryRegister(Option::V6,
999 &TestControl::factoryElapsedTime6);
1001 LibDHCP::OptionFactoryRegister(Option::V6,
1003 &TestControl::factoryRapidCommit6);
1005 LibDHCP::OptionFactoryRegister(Option::V6,
1007 &TestControl::factoryOptionRequestOption6);
1009 LibDHCP::OptionFactoryRegister(Option::V6,
1011 &TestControl::factoryGeneric);
1013 LibDHCP::OptionFactoryRegister(Option::V6,
1015 &TestControl::factoryGeneric);
1017 LibDHCP::OptionFactoryRegister(Option::V6,
1019 &TestControl::factoryIana6);
1022 LibDHCP::OptionFactoryRegister(Option::V6,
1024 &TestControl::factoryIapd6);
1028 factories_registered =
true;
1032 TestControl::registerOptionFactories()
const {
1033 switch(options_.getIpVersion()) {
1035 registerOptionFactories4();
1038 registerOptionFactories6();
1042 "before DHCP option factories can be registered");
1047 TestControl::reset() {
1048 transid_gen_.reset();
1049 last_report_ = microsec_clock::universal_time();
1054 first_packet_serverid_.clear();
1055 interrupted_ =
false;
1059 exit_time_(not_a_date_time),
1060 number_generator_(0, options.getMacsFromFile().size()),
1062 receiver_(socket, options.isSingleThreaded(), options.getIpVersion()),
1063 stats_mgr_(options),
1075 "command options must be parsed before running a test");
1078 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET,
data::ElementPtr());
1082 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6,
data::ElementPtr());
1101 time_period duration(from_iso_string(
"20111231T235959"),
1102 microsec_clock::universal_time());
1103 srandom(duration.length().total_seconds()
1104 + duration.length().fractional_seconds());
1118 }
else if (pid == 0) {
1145 uint8_t randomized = 0;
1162 pkt4->addOption(Option::factory(Option::V4,
1171 pkt4->setHWAddr(
HTYPE_ETHER, mac_address.size(), mac_address);
1188 pkt4->setSecs(static_cast<uint16_t>(val));
1205 const bool preload ) {
1208 const uint8_t arg_idx = 0;
1210 uint8_t randomized = 0;
1223 std::vector<uint8_t> in_buf(template_buf.begin(),
1224 template_buf.end());
1234 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1240 socket_.
send(boost::static_pointer_cast<Pkt4>(pkt4));
1244 boost::static_pointer_cast<Pkt4>(pkt4));
1262 msg->setGiaddr(ack->getGiaddr());
1280 <<
" to be sent, expected DHCPV6_RENEW or DHCPV6_RELEASE");
1306 const uint32_t transid = discover_pkt4->getTransid();
1318 if (!opt_serverid) {
1320 <<
"in OFFER message");
1325 pkt4->addOption(opt_serverid);
1330 if (!yiaddr.
isV4()) {
1337 opt_requested_address->setUint32(yiaddr.
toUint32());
1338 pkt4->addOption(opt_requested_address);
1341 pkt4->addOption(opt_parameter_list);
1345 pkt4->setGiaddr(offer_pkt4->getGiaddr());
1350 pkt4->setHWAddr(offer_pkt4->getHWAddr());
1354 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1355 pkt4->setSecs(static_cast<uint16_t>(elapsed_time / 1000));
1369 const uint8_t arg_idx = 1;
1371 const uint32_t transid = discover_pkt4->getTransid();
1379 std::vector<uint8_t> in_buf(template_buf.begin(),
1380 template_buf.end());
1392 HWAddrPtr hwaddr = offer_pkt4->getHWAddr();
1394 uint8_t hw_len = hwaddr->hwaddr_.size();
1396 memcpy(&mac_address[0], &hwaddr->hwaddr_[0],
1399 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1403 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1404 pkt4->writeValueAt<uint16_t>(elp_offset,
1405 static_cast<uint16_t
>(elapsed_time / 1000));
1413 boost::shared_ptr<LocalizedOption>
1418 pkt4->addOption(opt_serverid);
1424 if (!opt_serverid_offer) {
1426 <<
"in OFFER message");
1428 boost::shared_ptr<LocalizedOption>
1431 opt_serverid_offer->getData(),
1433 pkt4->addOption(opt_serverid);
1441 if (!yiaddr.
isV4()) {
1449 boost::shared_ptr<LocalizedOption>
1455 opt_requested_ip->setUint32(yiaddr.
toUint32());
1456 pkt4->addOption(opt_requested_ip);
1465 socket_.
send(boost::static_pointer_cast<Pkt4>(pkt4));
1468 boost::static_pointer_cast<Pkt4>(pkt4));
1479 pkt6->addOption(opt_elapsed_time);
1482 if (!opt_clientid) {
1485 pkt6->addOption(opt_clientid);
1491 pkt6->addOption(Option::factory(Option::V6,
D6O_SERVERID,
1495 if (!opt_serverid) {
1501 pkt6->addOption(opt_serverid);
1526 const Pkt6Ptr& advertise_pkt6) {
1529 const uint8_t arg_idx = 1;
1535 transid_offset, transid));
1538 boost::shared_ptr<LocalizedOption>
1541 pkt6->addOption(opt_elapsed_time);
1549 boost::shared_ptr<LocalizedOption>
1554 pkt6->addOption(opt_serverid);
1561 if (!opt_serverid_advertise) {
1563 <<
"in ADVERTISE message");
1565 boost::shared_ptr<LocalizedOption>
1568 opt_serverid_advertise->getData(),
1570 pkt6->addOption(opt_serverid);
1576 boost::shared_ptr<Option6IA> opt_ia_na_advertise =
1578 if (!opt_ia_na_advertise) {
1583 boost::shared_ptr<LocalizedOption>
1585 if (!opt_ia_na->valid()) {
1588 pkt6->addOption(opt_ia_na);
1591 if (!opt_serverid_advertise) {
1596 boost::shared_ptr<LocalizedOption>
1598 opt_serverid_advertise->getData(),
1600 pkt6->addOption(opt_serverid);
1604 if (!opt_clientid_advertise) {
1607 rand_offset -= (opt_clientid_advertise->len() - 1);
1609 boost::shared_ptr<LocalizedOption>
1611 opt_clientid_advertise->getData(),
1613 pkt6->addOption(opt_clientid);
1641 uint8_t randomized = 0;
1664 pkt6->addOption(elapsed);
1672 pkt6->addOption(Option::factory(Option::V6,
D6O_CLIENTID, duid));
1673 pkt6->addOption(Option::factory(Option::V6,
D6O_ORO));
1681 pkt6->addOption(Option::factory(Option::V6,
D6O_IA_NA));
1685 pkt6->addOption(Option::factory(Option::V6,
D6O_IA_PD));
1704 const bool preload ) {
1705 const int arg_idx = 0;
1712 transid_offset, transid));
1720 uint8_t randomized = 0;
1722 if (rand_offset > template_buf.size()) {
1726 pkt6->writeAt(rand_offset - randomized + 1,
1727 duid.end() - randomized, duid.end());
1750 if (iface == NULL) {
1753 pkt->setIface(iface->getName());
1757 pkt->setLocalPort(DHCP4_CLIENT_PORT);
1762 pkt->setRemotePort(DHCP4_SERVER_PORT);
1783 if (iface == NULL) {
1786 pkt->setIface(iface->getName());
1790 pkt->setLocalPort(DHCP6_CLIENT_PORT);
1795 pkt->setRemotePort(DHCP6_SERVER_PORT);
1815 pkt->addRelayInfo(relay_info);
1824 result.insert(result.end(), a.begin(), a.end());
1825 result.insert(result.end(), b.begin(), b.end());
1829 static void mergeOptionIntoPacket(
Pkt4Ptr const& packet,
1831 uint16_t
const code(extra_option->getType());
1833 OptionPtr const& option(packet->getOption(code));
1838 packet->delOption(code);
1839 packet->addOption(boost::make_shared<Option>(
1841 concatenateBuffers(option->getData(),
1842 extra_option->getData())));
1850 packet->addOption(extra_option);
1859 for (
auto entry : extra_opts) {
1860 mergeOptionIntoPacket(pkt, entry.second);
1868 for (
auto entry : extra_opts) {
1869 pkt->addOption(entry.second);
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
boost::shared_ptr< NumberGenerator > NumberGeneratorPtr
The default generator pointer.
void address6Uniqueness(const dhcp::Pkt6Ptr &pkt6, ExchangeType xchg_type)
Process received v6 addresses uniqueness.
uint32_t generateTransid()
generate transaction id.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
boost::shared_ptr< PerfPkt6 > PerfPkt6Ptr
void sendSolicit6(const bool preload=false)
Send DHCPv6 SOLICIT message.
virtual std::string toText(int indent=0) const
Returns string representation of the option.
DHCP option at specific offset.
bool isUseFirst() const
Check if server-ID to be taken from first package.
LeaseType getLeaseType() const
\ brief Returns the type of lease being requested.
DHCPv6 SOLICIT-ADVERTISE.
ExchangeType
DHCP packet exchange types.
boost::shared_ptr< PerfPkt4 > PerfPkt4Ptr
void registerOptionFactories() const
Register option factory functions for DHCPv4 or DHCPv6.
void printDiagnostics() const
Print main diagnostics data.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
PacketStorage< dhcp::Pkt4 > ack_storage_
Storage for DHCPACK messages.
int getRemotePort() const
Returns remote port number.
std::vector< uint8_t > generateDuid(uint8_t &randomized)
Generate DUID.
void runWrapped(bool do_stop=false) const
Run wrapped command.
uint32_t getClientsNum() const
Returns number of simulated clients.
std::vector< std::vector< uint8_t > > MacAddrsVector
A vector holding MAC addresses.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
boost::shared_ptr< Option > OptionPtr
void setTransidGenerator(const NumberGeneratorPtr &generator)
Set new transaction id generator.
void setDefaults6(const dhcp::Pkt6Ptr &pkt)
Set default DHCPv6 packet parameters.
virtual std::string toText(int indent=0) const
Returns string representation of the option.
StatsMgr stats_mgr_
Statistics Manager.
int getRequestedIpOffset() const
Return requested ip offset in a packet.
bool sendMessageFromReply(const uint16_t msg_type)
Send DHCPv6 Renew or Release message.
int getIncreaseElapsedTime() const
Returns increased elapsed time.
Universe
defines option universe DHCPv4 or DHCPv6
Represents a DHCPv6 packet.
bool checkMultiSubnet()
Check if multi subnet mode is enabled.
boost::shared_ptr< Element > ElementPtr
Forward declaration to OptionInt.
const isc::dhcp::OptionCollection & getExtraOpts() const
Returns extra options to be inserted.
virtual dhcp::IfacePtr getIface()=0
See description of this method in PerfSocket class below.
void initPacketTemplates()
Reads packet templates from files.
bool isV4() const
Convenience function to check for an IPv4 address.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
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...
dhcp::Pkt4Ptr createRequestFromAck(const dhcp::Pkt4Ptr &ack)
Creates DHCPREQUEST from a DHCPACK message.
void setDefaults4(const dhcp::Pkt4Ptr &pkt)
Set default DHCPv4 packet parameters.
std::vector< uint8_t > TemplateBuffer
Packet template buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
structure that describes a single relay information
PacketPtr getRandom()
Returns random packet from the storage.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
bool isRapidCommit() const
Check if rapid commit option used.
boost::shared_ptr< Option6IAPrefix > Option6IAPrefixPtr
Pointer to the Option6IAPrefix object.
DHCPv4 REQUEST-ACK (renewal)
bool isUseRelayedV6() const
Check if generated DHCPv6 messages should appear as relayed.
A generic exception that is thrown when an unexpected error condition occurs.
std::map< uint8_t, dhcp::Pkt6Ptr > template_packets_v6_
Template for v6.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
isc::asiolink::IOAddress addr_
std::string getRandRelayAddr()
Returns random relay address.
uint8_t getIpVersion() const
Returns IP version.
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
void sendDiscover4(const bool preload=false)
Send DHCPv4 DISCOVER message.
uint16_t ifindex_
Interface index.
int getServerIdOffset() const
Return server id offset in a packet.
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
uint32_t getSeed() const
Returns random seed.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
std::vector< uint8_t > generateMacAddress(uint8_t &randomized)
Generate MAC address.
void sendRequest6(const dhcp::Pkt6Ptr &advertise_pkt6)
Send DHCPv6 REQUEST message.
Defines the logger used by the top-level component of kea-dhcp-ddns.
void sendRequest4(const dhcp::Pkt4Ptr &discover_pkt4, const dhcp::Pkt4Ptr &offer_pkt4)
Send DHCPv4 REQUEST message.
int getRandomOffset(const int arg_idx) const
Return randomization offset in a packet.
void copyIaOptions(const dhcp::Pkt6Ptr &pkt_from, dhcp::Pkt6Ptr &pkt_to)
Copies IA_NA or IA_PD option from one packet to another.
Represents DHCPv4 packet.
static void handleChild(int sig)
Handle child signal.
uint8_t hop_count_
number of traversed relays (up to 32)
PacketStorage< dhcp::Pkt6 > reply_storage_
Storage for reply messages.
dhcp::OptionPtr generateClientId(const dhcp::HWAddrPtr &hwaddr) const
Generate DHCPv4 client identifier from HW address.
std::string getServerName() const
Returns server name.
void saveFirstPacket(const dhcp::Pkt4Ptr &pkt)
Save the first DHCPv4 sent packet of the specified type.
bool isSeeded() const
Checks if seed provided.
bool sendRequestFromAck()
Send DHCPv4 renew (DHCPREQUEST).
uint16_t getType() const
Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
CommandOptions & options_
Command options.
A generic exception that is thrown if a function is called in a prohibited way.
bool testDiags(const char diag)
Find if diagnostic flag has been set.
static const uint8_t HW_ETHER_LEN
Length of the Ethernet HW address (MAC) in bytes.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an object can not be found.
isc::asiolink::IOAddress linkaddr_
fixed field in relay-forw/relay-reply
dhcp::OptionBuffer first_packet_serverid_
Buffer holding server id received in first packet.
isc::asiolink::IOAddress peeraddr_
fixed field in relay-forw/relay-reply
Socket wrapper structure.
int getTransactionIdOffset(const int arg_idx) const
Return transaction id offset in a packet.
dhcp::Pkt6Ptr createMessageFromReply(const uint16_t msg_type, const dhcp::Pkt6Ptr &reply)
Creates DHCPv6 message from the Reply packet.
The IOAddress class represents an IP addresses (version agnostic)
Class that represents IAPREFIX option in DHCPv6.
boost::posix_time::time_period getTestPeriod() const
Get time period since the start of test.
ExchangeMode
2-way (cmd line param -i) or 4-way exchanges
std::string getWrapped() const
Returns wrapped command.
int getWaitForElapsedTime() const
Returns time to wait for elapsed time increase.
void setMacAddrGenerator(const NumberGeneratorPtr &generator)
Set new MAC address generator.
int getElapsedTimeOffset() const
Return elapsed time offset in a packet.
std::map< uint8_t, dhcp::Pkt4Ptr > template_packets_v4_
First packets send.
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
BasePerfSocket & socket_
Socket used for DHCP traffic.
void reset()
Resets internal state of the object.
static void handleInterrupt(int sig)
Handle interrupt signal.
Sequential numbers generator class.
void addExtraOpts(const dhcp::Pkt4Ptr &pkt4)
Inserts extra options specified by user.
uint8_t msg_type_
message type (RELAY-FORW oro RELAY-REPL)
void passSentPacket(const ExchangeType xchg_type, const dhcp::PktPtr &packet)
Adds new packet to the sent packets list.
virtual bool send(const dhcp::Pkt4Ptr &pkt)=0
See description of this method in PerfSocket class below.