Kea: test_control.cc Source File

| Kea 2.2.0

test_control.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2022 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 <perfdhcp/test_control.h>
10#include <perfdhcp/receiver.h>
11#include <perfdhcp/command_options.h>
12#include <perfdhcp/perf_pkt4.h>
13#include <perfdhcp/perf_pkt6.h>
14
15#include <exceptions/exceptions.h>
16#include <dhcp/libdhcp++.h>
17#include <dhcp/iface_mgr.h>
18#include <dhcp/dhcp4.h>
19#include <dhcp/option6_ia.h>
20#include <dhcp/option6_iaaddr.h>
21#include <dhcp/option6_iaprefix.h>
22#include <dhcp/option_int.h>
23#include <util/unittests/check_valgrind.h>
24
25#include <boost/date_time/posix_time/posix_time.hpp>
26#include <algorithm>
27#include <fstream>
28#include <stdio.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <unistd.h>
32#include <signal.h>
33#include <sstream>
34#include <sys/wait.h>
35
36using namespace std;
37using namespace boost::posix_time;
38using namespace isc;
39using namespace isc::dhcp;
40using namespace isc::asiolink;
41
42namespace isc {
43namespace perfdhcp {
44
45bool TestControl::interrupted_ = false;
46
47bool
48TestControl::waitToExit() {
49 uint32_t const wait_time = options_.getExitWaitTime();
50
51 // If we care and not all packets are in yet
52 if (wait_time && !haveAllPacketsBeenReceived()) {
53 const ptime now = microsec_clock::universal_time();
54
55 // Init the end time if it hasn't started yet
56 if (exit_time_.is_not_a_date_time()) {
57 exit_time_ = now + time_duration(microseconds(wait_time));
58 }
59
60 // If we're not at end time yet, return true
61 return (now < exit_time_);
62 }
63
64 // No need to wait, return false;
65 return (false);
66}
67
68bool
69TestControl::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();
73
74 if (num_request_size == 0) {
75 return false;
76 }
77
78 uint32_t responses = 0;
79 uint32_t requests = num_request[0];
80 if (num_request_size >= 2) {
81 requests += num_request[1];
82 }
83
84 if (ipversion == 4) {
85 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) +
86 stats_mgr_.getRcvdPacketsNum(ExchangeType::RA);
87 } else {
88 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) +
89 stats_mgr_.getRcvdPacketsNum(ExchangeType::RR);
90 }
91
92 return (responses == requests);
93}
94
95void
96TestControl::cleanCachedPackets() {
97 // When Renews are not sent, Reply packets are not cached so there
98 // is nothing to do.
99 if (options_.getRenewRate() == 0) {
100 return;
101 }
102
103 static boost::posix_time::ptime last_clean =
104 microsec_clock::universal_time();
105
106 // Check how much time has passed since last cleanup.
107 time_period time_since_clean(last_clean,
108 microsec_clock::universal_time());
109 // Cleanup every 1 second.
110 if (time_since_clean.length().total_seconds() >= 1) {
111 // Calculate how many cached packets to remove. Actually we could
112 // just leave enough packets to handle Renews for 1 second but
113 // since we want to randomize leases to be renewed so leave 5
114 // times more packets to randomize from.
116 if (reply_storage_.size() > 5 * options_.getRenewRate()) {
117 reply_storage_.clear(reply_storage_.size() -
118 5 * options_.getRenewRate());
119 }
120 // Remember when we performed a cleanup for the last time.
121 // We want to do the next cleanup not earlier than in one second.
122 last_clean = microsec_clock::universal_time();
123 }
124}
125
126void
127TestControl::copyIaOptions(const Pkt6Ptr& pkt_from, Pkt6Ptr& pkt_to) {
128 if (!pkt_from || !pkt_to) {
129 isc_throw(BadValue, "NULL pointers must not be specified as arguments"
130 " for the copyIaOptions function");
131 }
132 // IA_NA
133 if (options_.getLeaseType()
134 .includes(CommandOptions::LeaseType::ADDRESS)) {
135 OptionPtr option = pkt_from->getOption(D6O_IA_NA);
136 if (!option) {
137 isc_throw(NotFound, "IA_NA option not found in the"
138 " server's response");
139 }
140 pkt_to->addOption(option);
141 }
142 // IA_PD
143 if (options_.getLeaseType()
144 .includes(CommandOptions::LeaseType::PREFIX)) {
145 OptionPtr option = pkt_from->getOption(D6O_IA_PD);
146 if (!option) {
147 isc_throw(NotFound, "IA_PD option not found in the"
148 " server's response");
149 }
150 pkt_to->addOption(option);
151 }
152}
153
154std::string
155TestControl::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());
161}
162
163 Pkt4Ptr
164TestControl::createMessageFromAck(const uint16_t msg_type,
165 const dhcp::Pkt4Ptr& ack) {
166 // Restrict messages to Release and Renew.
167 if (msg_type != DHCPREQUEST && msg_type != DHCPRELEASE) {
168 isc_throw(isc::BadValue, "invalid message type " << msg_type
169 << " to be created from Reply, expected DHCPREQUEST or"
170 " DHCPRELEASE");
171 }
172
173 // Get the string representation of the message - to be used for error
174 // logging purposes.
175 auto msg_type_str = [=]() -> const char* {
176 return (msg_type == DHCPREQUEST ? "Request" : "Release");
177 };
178
179 if (!ack) {
180 isc_throw(isc::BadValue, "Unable to create "
181 << msg_type_str()
182 << " from a null DHCPACK message");
183 } else if (ack->getYiaddr().isV4Zero()) {
184 isc_throw(isc::BadValue,
185 "Unable to create "
186 << msg_type_str()
187 << " from a DHCPACK message containing yiaddr of 0");
188 }
189 Pkt4Ptr msg(new Pkt4(msg_type, generateTransid()));
190 msg->setCiaddr(ack->getYiaddr());
191 msg->setHWAddr(ack->getHWAddr());
192 msg->addOption(generateClientId(msg->getHWAddr()));
193 if (msg_type == DHCPRELEASE) {
194 // RFC 2132: DHCPRELEASE MUST include server ID.
195 if (options_.isUseFirst()) {
196 // Honor the '-1' flag if it exists.
197 if (first_packet_serverid_.empty()) {
198 isc_throw(isc::BadValue,
199 "Unable to create "
200 << msg_type_str()
201 << "from the first packet which lacks the server "
202 "identifier option");
203 }
204 msg->addOption(Option::factory(Option::V4,
205 DHO_DHCP_SERVER_IDENTIFIER,
206 first_packet_serverid_));
207 } else {
208 // Otherwise take it from the DHCPACK message.
209 OptionPtr server_identifier(
210 ack->getOption(DHO_DHCP_SERVER_IDENTIFIER));
211 if (!server_identifier) {
212 isc_throw(isc::BadValue,
213 "Unable to create "
214 << msg_type_str()
215 << "from a DHCPACK message without the server "
216 "identifier option");
217 }
218 msg->addOption(server_identifier);
219 }
220 }
221 return (msg);
222}
223
224 Pkt6Ptr
225TestControl::createMessageFromReply(const uint16_t msg_type,
226 const dhcp::Pkt6Ptr& reply) {
227 // Restrict messages to Release and Renew.
228 if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
229 isc_throw(isc::BadValue, "invalid message type " << msg_type
230 << " to be created from Reply, expected DHCPV6_RENEW or"
231 " DHCPV6_RELEASE");
232 }
233
234 // Get the string representation of the message - to be used for error
235 // logging purposes.
236 auto msg_type_str = [=]() -> const char* {
237 return (msg_type == DHCPV6_RENEW ? "Renew" : "Release");
238 };
239
240 // Reply message must be specified.
241 if (!reply) {
242 isc_throw(isc::BadValue, "Unable to create " << msg_type_str()
243 << " message from the Reply message because the instance of"
244 " the Reply message is NULL");
245 }
246
247 Pkt6Ptr msg(new Pkt6(msg_type, generateTransid()));
248 // Client id.
249 OptionPtr opt_clientid = reply->getOption(D6O_CLIENTID);
250 if (!opt_clientid) {
251 isc_throw(isc::Unexpected, "failed to create " << msg_type_str()
252 << " message because client id option has not been found"
253 " in the Reply message");
254 }
255 msg->addOption(opt_clientid);
256 // Server id.
257 OptionPtr opt_serverid = reply->getOption(D6O_SERVERID);
258 if (!opt_serverid) {
259 isc_throw(isc::Unexpected, "failed to create " << msg_type_str()
260 << " because server id option has not been found in the"
261 " Reply message");
262 }
263 msg->addOption(opt_serverid);
264 copyIaOptions(reply, msg);
265 return (msg);
266}
267
268 OptionPtr
269TestControl::factoryElapsedTime6(Option::Universe, uint16_t,
270 const OptionBuffer& buf) {
271 if (buf.size() == 2) {
272 return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf)));
273 } else if (buf.size() == 0) {
274 return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
275 OptionBuffer(2, 0))));
276 }
277 isc_throw(isc::BadValue,
278 "elapsed time option buffer size has to be 0 or 2");
279}
280
281 OptionPtr
282TestControl::factoryGeneric(Option::Universe u, uint16_t type,
283 const OptionBuffer& buf) {
284 OptionPtr opt(new Option(u, type, buf));
285 return (opt);
286}
287
288 OptionPtr
289TestControl::factoryIana6(Option::Universe, uint16_t,
290 const OptionBuffer& buf) {
292 const uint8_t buf_array[] = {
293 0, 0, 0, 1, // IAID = 1
294 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
295 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
296 };
297 OptionBuffer buf_ia_na(buf_array, buf_array + sizeof(buf_array));
298 for (size_t i = 0; i < buf.size(); ++i) {
299 buf_ia_na.push_back(buf[i]);
300 }
301 return (OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)));
302}
303
304 OptionPtr
305TestControl::factoryIapd6(Option::Universe, uint16_t,
306 const OptionBuffer& buf) {
308 static const uint8_t buf_array[] = {
309 0, 0, 0, 1, // IAID = 1
310 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
311 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
312 };
313 OptionBuffer buf_ia_pd(buf_array, buf_array + sizeof(buf_array));
314 // Append sub-options to IA_PD.
315 buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
316 return (OptionPtr(new Option(Option::V6, D6O_IA_PD, buf_ia_pd)));
317}
318
319
320 OptionPtr
321TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
322 const OptionBuffer&) {
323 return (OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())));
324}
325
326 OptionPtr
327TestControl::factoryOptionRequestOption6(Option::Universe,
328 uint16_t,
329 const OptionBuffer&) {
330 const uint8_t buf_array[] = {
331 0, D6O_NAME_SERVERS,
332 0, D6O_DOMAIN_SEARCH,
333 };
334 OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
335 return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)));
336}
337
338
339 OptionPtr
340TestControl::factoryRequestList4(Option::Universe u,
341 uint16_t type,
342 const OptionBuffer& buf) {
343 const uint8_t buf_array[] = {
344 DHO_SUBNET_MASK,
345 DHO_BROADCAST_ADDRESS,
346 DHO_TIME_OFFSET,
347 DHO_ROUTERS,
348 DHO_DOMAIN_NAME,
349 DHO_DOMAIN_NAME_SERVERS,
350 DHO_HOST_NAME
351 };
352
353 OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
354 OptionPtr opt(new Option(u, type, buf));
355 opt->setData(buf_with_options.begin(), buf_with_options.end());
356 return (opt);
357}
358
359std::vector<uint8_t>
360TestControl::generateMacAddress(uint8_t& randomized) {
361 const CommandOptions::MacAddrsVector& macs = options_.getMacsFromFile();
362 // if we are using the -M option return a random one from the list...
363 if (macs.size() > 0) {
364 uint16_t r = number_generator_();
365 if (r >= macs.size()) {
366 r = 0;
367 }
368 return macs[r];
369
370 } else {
371 // ... otherwise use the standard behavior
372 uint32_t clients_num = options_.getClientsNum();
373 if (clients_num < 2) {
374 return (options_.getMacTemplate());
375 }
376 // Get the base MAC address. We are going to randomize part of it.
377 std::vector<uint8_t> mac_addr(options_.getMacTemplate());
378 if (mac_addr.size() != HW_ETHER_LEN) {
379 isc_throw(BadValue, "invalid MAC address template specified");
380 }
381 uint32_t r = macaddr_gen_->generate();
382 randomized = 0;
383 // Randomize MAC address octets.
384 for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
385 it >= mac_addr.begin();
386 --it) {
387 // Add the random value to the current octet.
388 (*it) += r;
389 ++randomized;
390 if (r < 256) {
391 // If we are here it means that there is no sense
392 // to randomize the remaining octets of MAC address
393 // because the following bytes of random value
394 // are zero and it will have no effect.
395 break;
396 }
397 // Randomize the next octet with the following
398 // byte of random value.
399 r >>= 8;
400 }
401 return (mac_addr);
402 }
403}
404
405 OptionPtr
406TestControl::generateClientId(const dhcp::HWAddrPtr& hwaddr) const {
407 std::vector<uint8_t> client_id(1, static_cast<uint8_t>(hwaddr->htype_));
408 client_id.insert(client_id.end(), hwaddr->hwaddr_.begin(),
409 hwaddr->hwaddr_.end());
410 return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
411 client_id)));
412}
413
414std::vector<uint8_t>
415TestControl::generateDuid(uint8_t& randomized) {
416 std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
417 const CommandOptions::MacAddrsVector& macs = options_.getMacsFromFile();
418 // pick a random mac address if we are using option -M..
419 if (macs.size() > 0) {
420 uint16_t r = number_generator_();
421 if (r >= macs.size()) {
422 r = 0;
423 }
424 std::vector<uint8_t> mac = macs[r];
425 // DUID_LL is in this format
426 // 0 1 2 3
427 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
428 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
429 // | 3 | hardware type (16 bits) |
430 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
431 // . .
432 // . link-layer address (variable length) .
433 // . .
434 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435
436 // No C++11 so initializer list support, building a vector<uint8_t> is a
437 // pain...
438 uint8_t duid_ll[] = {0, 3, 0, 1, 0, 0, 0, 0, 0, 0};
439 // copy duid_ll array into the vector
440 std::vector<uint8_t> duid(duid_ll,
441 duid_ll + sizeof(duid_ll) / sizeof(duid_ll[0]));
442 // put the mac address bytes at the end
443 std::copy(mac.begin(), mac.end(), duid.begin() + 4);
444 return (duid);
445 } else {
446 uint32_t clients_num = options_.getClientsNum();
447 if ((clients_num == 0) || (clients_num == 1)) {
448 return (options_.getDuidTemplate());
449 }
450 // Get the base DUID. We are going to randomize part of it.
451 std::vector<uint8_t> duid(options_.getDuidTemplate());
453 duid.resize(duid.size());
454 std::copy(mac_addr.begin(), mac_addr.end(),
455 duid.begin() + duid.size() - mac_addr.size());
456 return (duid);
457 }
458}
459
460int
461TestControl::getElapsedTimeOffset() const {
462 int elp_offset = options_.getIpVersion() == 4 ?
463 DHCPV4_ELAPSED_TIME_OFFSET : DHCPV6_ELAPSED_TIME_OFFSET;
464 if (options_.getElapsedTimeOffset() > 0) {
465 elp_offset = options_.getElapsedTimeOffset();
466 }
467 return (elp_offset);
468}
469
470template<class T>
471uint32_t
472TestControl::getElapsedTime(const T& pkt1, const T& pkt2) {
473 using namespace boost::posix_time;
474 ptime pkt1_time = pkt1->getTimestamp();
475 ptime pkt2_time = pkt2->getTimestamp();
476 if (pkt1_time.is_not_a_date_time() ||
477 pkt2_time.is_not_a_date_time()) {
478 isc_throw(InvalidOperation, "packet timestamp not set");;
479 }
480 time_period elapsed_period(pkt1_time, pkt2_time);
481 return (elapsed_period.is_null() ? 0 :
482 elapsed_period.length().total_milliseconds());
483}
484
485int
486TestControl::getRandomOffset(const int arg_idx) const {
487 int rand_offset = options_.getIpVersion() == 4 ?
488 DHCPV4_RANDOMIZATION_OFFSET : DHCPV6_RANDOMIZATION_OFFSET;
489 if (options_.getRandomOffset().size() > arg_idx) {
490 rand_offset = options_.getRandomOffset()[arg_idx];
491 }
492 return (rand_offset);
493}
494
495int
496TestControl::getRequestedIpOffset() const {
497 int rip_offset = options_.getIpVersion() == 4 ?
498 DHCPV4_REQUESTED_IP_OFFSET : DHCPV6_IA_NA_OFFSET;
499 if (options_.getRequestedIpOffset() > 0) {
500 rip_offset = options_.getRequestedIpOffset();
501 }
502 return (rip_offset);
503}
504
505int
506TestControl::getServerIdOffset() const {
507 int srvid_offset = options_.getIpVersion() == 4 ?
508 DHCPV4_SERVERID_OFFSET : DHCPV6_SERVERID_OFFSET;
509 if (options_.getServerIdOffset() > 0) {
510 srvid_offset = options_.getServerIdOffset();
511 }
512 return (srvid_offset);
513}
514
515 TestControl::TemplateBuffer
516TestControl::getTemplateBuffer(const size_t idx) const {
517 if (template_buffers_.size() > idx) {
518 return (template_buffers_[idx]);
519 }
520 isc_throw(OutOfRange, "invalid buffer index");
521}
522
523int
524TestControl::getTransactionIdOffset(const int arg_idx) const {
525 int xid_offset = options_.getIpVersion() == 4 ?
526 DHCPV4_TRANSID_OFFSET : DHCPV6_TRANSID_OFFSET;
527 if (options_.getTransactionIdOffset().size() > arg_idx) {
528 xid_offset = options_.getTransactionIdOffset()[arg_idx];
529 }
530 return (xid_offset);
531}
532
533void
534TestControl::handleChild(int) {
535 int status = 0;
536 while (wait3(&status, WNOHANG, NULL) > 0) {
537 // continue
538 }
539}
540
541void
542TestControl::handleInterrupt(int) {
543 interrupted_ = true;
544}
545
546void
547TestControl::initPacketTemplates() {
548 template_packets_v4_.clear();
549 template_packets_v6_.clear();
550 template_buffers_.clear();
551 std::vector<std::string> template_files = options_.getTemplateFiles();
552 for (std::vector<std::string>::const_iterator it = template_files.begin();
553 it != template_files.end(); ++it) {
554 readPacketTemplate(*it);
555 }
556}
557
558void
559TestControl::sendPackets(const uint64_t packets_num,
560 const bool preload /* = false */) {
561 for (uint64_t i = packets_num; i > 0; --i) {
562 if (options_.getIpVersion() == 4) {
563 // No template packets means that no -T option was specified.
564 // We have to build packets ourselves.
565 if (template_buffers_.empty()) {
566 sendDiscover4(preload);
567 } else {
570 sendDiscover4(template_buffers_[0], preload);
571 }
572 } else {
573 // No template packets means that no -T option was specified.
574 // We have to build packets ourselves.
575 if (template_buffers_.empty()) {
576 sendSolicit6(preload);
577 } else {
580 sendSolicit6(template_buffers_[0], preload);
581 }
582 }
583 }
584}
585
586uint64_t
587TestControl::sendMultipleMessages4(const uint32_t msg_type,
588 const uint64_t msg_num) {
589 for (uint64_t i = 0; i < msg_num; ++i) {
590 if (!sendMessageFromAck(msg_type)) {
591 return (i);
592 }
593 }
594 return (msg_num);
595}
596
597uint64_t
598TestControl::sendMultipleMessages6(const uint32_t msg_type,
599 const uint64_t msg_num) {
600 for (uint64_t i = 0; i < msg_num; ++i) {
601 if (!sendMessageFromReply(msg_type)) {
602 return (i);
603 }
604 }
605 return (msg_num);
606}
607
608void
609TestControl::printDiagnostics() const {
610 if (options_.testDiags('a')) {
611 // Print all command line parameters.
612 options_.printCommandLine();
613 // Print MAC and DUID.
614 std::cout << "Set MAC to " << vector2Hex(options_.getMacTemplate(), "::")
615 << std::endl;
616 if (options_.getDuidTemplate().size() > 0) {
617 std::cout << "Set DUID to " << vector2Hex(options_.getDuidTemplate()) << std::endl;
618 }
619 }
620}
621
622void
623TestControl::printTemplate(const uint8_t packet_type) const {
624 std::string hex_buf;
625 int arg_idx = 0;
626 if (options_.getIpVersion() == 4) {
627 if (packet_type == DHCPREQUEST) {
628 arg_idx = 1;
629 }
630 std::map<uint8_t, dhcp::Pkt4Ptr>::const_iterator pkt_it =
631 template_packets_v4_.find(packet_type);
632 if ((pkt_it != template_packets_v4_.end()) &&
633 pkt_it->second) {
634 const util::OutputBuffer& out_buf(pkt_it->second->getBuffer());
635 const char* out_buf_data =
636 static_cast<const char*>(out_buf.getData());
637 std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
638 hex_buf = vector2Hex(buf);
639 }
640 } else if (options_.getIpVersion() == 6) {
641 if (packet_type == DHCPV6_REQUEST) {
642 arg_idx = 1;
643 }
644 std::map<uint8_t, dhcp::Pkt6Ptr>::const_iterator pkt_it =
645 template_packets_v6_.find(packet_type);
646 if (pkt_it != template_packets_v6_.end() &&
647 pkt_it->second) {
648 const util::OutputBuffer& out_buf(pkt_it->second->getBuffer());
649 const char* out_buf_data =
650 static_cast<const char*>(out_buf.getData());
651 std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
652 hex_buf = vector2Hex(buf);
653 }
654 }
655 std::cout << "xid-offset=" << getTransactionIdOffset(arg_idx) << std::endl;
656 std::cout << "random-offset=" << getRandomOffset(arg_idx) << std::endl;
657 if (arg_idx > 0) {
658 std::cout << "srvid-offset=" << getServerIdOffset() << std::endl;
659 std::cout << "time-offset=" << getElapsedTimeOffset() << std::endl;
660 std::cout << "ip-offset=" << getRequestedIpOffset() << std::endl;
661 }
662
663 std::cout << "contents: " << std::endl;
664 int line_len = 32;
665 int i = 0;
666 while (line_len == 32) {
667 if (hex_buf.length() - i < 32) {
668 line_len = hex_buf.length() - i;
669 };
670 if (line_len > 0) {
671 std::cout << setfill('0') << setw(4) << std::hex << i << std::dec
672 << " " << hex_buf.substr(i, line_len) << std::endl;
673 }
674 i += 32;
675 }
676 std::cout << std::endl;
677}
678
679void
680TestControl::printTemplates() const {
681 if (options_.getIpVersion() == 4) {
682 printTemplate(DHCPDISCOVER);
683 printTemplate(DHCPREQUEST);
684 } else if (options_.getIpVersion() == 6) {
685 printTemplate(DHCPV6_SOLICIT);
686 printTemplate(DHCPV6_REQUEST);
687 }
688}
689
690void
691TestControl::printRate() const {
692 double rate = 0;
693 std::string exchange_name = "4-way exchanges";
694 ExchangeType xchg_type = ExchangeType::DO;
695 if (options_.getIpVersion() == 4) {
696 xchg_type =
697 options_.getExchangeMode() == CommandOptions::DO_SA ?
698 ExchangeType::DO : ExchangeType::RA;
699 if (xchg_type == ExchangeType::DO) {
700 exchange_name = "DISCOVER-OFFER";
701 }
702 } else if (options_.getIpVersion() == 6) {
703 xchg_type =
704 options_.getExchangeMode() == CommandOptions::DO_SA ?
705 ExchangeType::SA : ExchangeType::RR;
706 if (xchg_type == ExchangeType::SA) {
707 exchange_name = options_.isRapidCommit() ? "Solicit-Reply" :
708 "Solicit-Advertise";
709 }
710 }
711 double duration =
712 stats_mgr_.getTestPeriod().length().total_nanoseconds() / 1e9;
713 rate = stats_mgr_.getRcvdPacketsNum(xchg_type) / duration;
714 std::ostringstream s;
715 s << "***Rate statistics***" << std::endl;
716 s << "Rate: " << rate << " " << exchange_name << "/second";
717 if (options_.getRate() > 0) {
718 s << ", expected rate: " << options_.getRate() << std::endl;
719 }
720
721 std::cout << s.str() << std::endl;
722
723 std::cout <<"***Malformed Packets***" << std::endl
724 << "Malformed packets: " << ExchangeStats::malformed_pkts_
725 << std::endl;
726}
727
728void
729TestControl::printIntermediateStats() {
730 int delay = options_.getReportDelay();
731 ptime now = microsec_clock::universal_time();
732 time_period time_since_report(last_report_, now);
733 if (time_since_report.length().total_seconds() >= delay) {
734 stats_mgr_.printIntermediateStats(options_.getCleanReport(),
735 options_.getCleanReportSeparator());
736 last_report_ = now;
737 }
738}
739
740void
741TestControl::printStats() const {
742 printRate();
743 stats_mgr_.printStats();
744 if (options_.testDiags('i')) {
745 stats_mgr_.printCustomCounters();
746 }
747}
748
749std::string
750TestControl::vector2Hex(const std::vector<uint8_t>& vec,
751 const std::string& separator /* = "" */) {
752 std::ostringstream stream;
753 for (std::vector<uint8_t>::const_iterator it = vec.begin();
754 it != vec.end();
755 ++it) {
756 if (it == vec.begin()) {
757 stream << byte2Hex(*it);
758 } else {
759 stream << separator << byte2Hex(*it);
760 }
761 }
762 return (stream.str());
763}
764
765void
766TestControl::readPacketTemplate(const std::string& file_name) {
767 std::ifstream temp_file;
768 temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate);
769 if (!temp_file.is_open()) {
770 isc_throw(BadValue, "unable to open template file " << file_name);
771 }
772 // Read template file contents.
773 std::streampos temp_size = temp_file.tellg();
774 if (temp_size == std::streampos(0)) {
775 temp_file.close();
776 isc_throw(OutOfRange, "the template file " << file_name << " is empty");
777 }
778 temp_file.seekg(0, ios::beg);
779 std::vector<char> file_contents(temp_size);
780 temp_file.read(&file_contents[0], temp_size);
781 temp_file.close();
782 // Spaces are allowed so we have to strip the contents
783 // from them. In the same time we want to make sure that
784 // apart from spaces the file contains hexadecimal digits
785 // only.
786 std::vector<char> hex_digits;
787 for (size_t i = 0; i < file_contents.size(); ++i) {
788 if (isxdigit(file_contents[i])) {
789 hex_digits.push_back(file_contents[i]);
790 } else if (!isxdigit(file_contents[i]) &&
791 !isspace(file_contents[i])) {
792 isc_throw(BadValue, "'" << file_contents[i] << "' is not a"
793 " hexadecimal digit");
794 }
795 }
796 // Expect even number of digits.
797 if (hex_digits.size() % 2 != 0) {
798 isc_throw(OutOfRange, "odd number of digits in template file");
799 } else if (hex_digits.empty()) {
800 isc_throw(OutOfRange, "template file " << file_name << " is empty");
801 }
802 std::vector<uint8_t> binary_stream;
803 for (size_t i = 0; i < hex_digits.size(); i += 2) {
804 stringstream s;
805 s << "0x" << hex_digits[i] << hex_digits[i+1];
806 int b;
807 s >> std::hex >> b;
808 binary_stream.push_back(static_cast<uint8_t>(b));
809 }
810 template_buffers_.push_back(binary_stream);
811}
812
813void
814TestControl::processReceivedPacket4(const Pkt4Ptr& pkt4) {
815 if (pkt4->getType() == DHCPOFFER) {
816 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::DO, pkt4);
817 address4Uniqueness(pkt4, ExchangeType::DO);
818 Pkt4Ptr discover_pkt4(boost::dynamic_pointer_cast<Pkt4>(pkt));
819 CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
820 if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
821 if (template_buffers_.size() < 2) {
822 sendRequest4(discover_pkt4, pkt4);
823 } else {
826 sendRequest4(template_buffers_[1], discover_pkt4, pkt4);
827 }
828 }
829 } else if (pkt4->getType() == DHCPACK) {
830 // If received message is DHCPACK, we have to check if this is
831 // a response to 4-way exchange. We'll match this packet with
832 // a DHCPREQUEST sent as part of the 4-way exchanges.
833 if (stats_mgr_.passRcvdPacket(ExchangeType::RA, pkt4)) {
834 address4Uniqueness(pkt4, ExchangeType::RA);
835 // The DHCPACK belongs to DHCPREQUEST-DHCPACK exchange type.
836 // So, we may need to keep this DHCPACK in the storage if renews.
837 // Note that, DHCPACK messages hold the information about
838 // leases assigned. We use this information to renew.
839 if (stats_mgr_.hasExchangeStats(ExchangeType::RNA) ||
840 stats_mgr_.hasExchangeStats(ExchangeType::RLA)) {
841 // Renew or release messages are sent, because StatsMgr has the
842 // specific exchange type specified. Let's append the DHCPACK
843 // message to a storage.
844 ack_storage_.append(pkt4);
845 }
846 // The DHCPACK message is not a server's response to the DHCPREQUEST
847 // message sent within the 4-way exchange. It may be a response to a
848 // renewal. In this case we first check if StatsMgr has exchange type
849 // for renew specified, and if it has, if there is a corresponding
850 // renew message for the received DHCPACK.
851 } else if (stats_mgr_.hasExchangeStats(ExchangeType::RNA)) {
852 stats_mgr_.passRcvdPacket(ExchangeType::RNA, pkt4);
853 }
854 }
855}
856
857void
858TestControl::address6Uniqueness(const Pkt6Ptr& pkt6, ExchangeType xchg_type) {
859 // check if received address is unique
860 if (options_.getAddrUnique()) {
861 std::set<std::string> current;
862 // addresses were already checked in validateIA
863 // we can safely assume that those are correct
864 for (const auto& opt : pkt6->options_) {
865 switch (opt.second->getType()) {
866 case D6O_IA_PD: {
867 // add address and check if it has not been already assigned
868 // addresses should be unique cross options of the packet
869 auto ret = current.emplace(boost::dynamic_pointer_cast<
870 Option6IAPrefix>(opt.second->getOption(D6O_IAPREFIX))->getAddress().toText());
871 if (!ret.second) {
872 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
873 }
874 break;
875 }
876 case D6O_IA_NA: {
877 // add address and check if it has not been already assigned
878 // addresses should be unique cross options of the packet
879 auto ret = current.emplace(boost::dynamic_pointer_cast<
880 Option6IAAddr>(opt.second->getOption(D6O_IAADDR))->getAddress().toText());
881 if (!ret.second) {
882 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
883 }
884 break;
885 }
886 default:
887 break;
888 }
889 }
890 // addresses should be unique cross packets
891 addUniqeAddr(current, xchg_type);
892 }
893}
894
895void
896TestControl::address4Uniqueness(const Pkt4Ptr& pkt4, ExchangeType xchg_type) {
897 // check if received address is unique
898 if (options_.getAddrUnique()) {
899 // addresses were already checked in validateIA
900 // we can safely assume that those are correct
901 std::set<std::string> current;
902 current.insert(pkt4->getYiaddr().toText());
903 // addresses should be unique cross packets
904 addUniqeAddr(current, xchg_type);
905 }
906}
907
908bool
909TestControl::validateIA(const Pkt6Ptr& pkt6) {
910 // check if iaaddr exists - if it does, we can continue sending request
911 // if not we will update statistics about rejected leases
912 // @todo it's checking just one iaaddress option for now it's ok
913 // but when perfdhcp will be extended to create message with multiple IA
914 // this will have to be iterate on:
915 // OptionCollection ias = pkt6->getOptions(D6O_IA_NA);
916 Option6IAPrefixPtr iapref;
917 Option6IAAddrPtr iaaddr;
918 if (pkt6->getOption(D6O_IA_PD)) {
919 iapref = boost::dynamic_pointer_cast<
920 Option6IAPrefix>(pkt6->getOption(D6O_IA_PD)->getOption(D6O_IAPREFIX));
921 }
922 if (pkt6->getOption(D6O_IA_NA)) {
923 iaaddr = boost::dynamic_pointer_cast<
924 Option6IAAddr>(pkt6->getOption(D6O_IA_NA)->getOption(D6O_IAADDR));
925 }
926
927 bool address_and_prefix = options_.getLeaseType().includes(
928 CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
929 bool prefix_only = options_.getLeaseType().includes(
930 CommandOptions::LeaseType::PREFIX);
931 bool address_only = options_.getLeaseType().includes(
932 CommandOptions::LeaseType::ADDRESS);
933 if ((address_and_prefix && iapref && iaaddr) ||
934 (prefix_only && iapref && !address_and_prefix) ||
935 (address_only && iaaddr && !address_and_prefix)) {
936 return true;
937 } else {
938 return false;
939 }
940}
941
942void
943TestControl::processReceivedPacket6(const Pkt6Ptr& pkt6) {
944 uint8_t packet_type = pkt6->getType();
945 if (packet_type == DHCPV6_ADVERTISE) {
946 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::SA, pkt6);
947 Pkt6Ptr solicit_pkt6(boost::dynamic_pointer_cast<Pkt6>(pkt));
948 CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
949 if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
950 if (validateIA(pkt6)) {
951 // if address is correct - check uniqueness
952 address6Uniqueness(pkt6, ExchangeType::SA);
953 if (template_buffers_.size() < 2) {
954 sendRequest6(pkt6);
955 } else {
958 sendRequest6(template_buffers_[1], pkt6);
959 }
960 } else {
961 stats_mgr_.updateRejLeases(ExchangeType::SA);
962 }
963 }
964 } else if (packet_type == DHCPV6_REPLY) {
965 // If the received message is Reply, we have to find out which exchange
966 // type the Reply message belongs to. It is doable by matching the Reply
967 // transaction id with the transaction id of the sent Request, Renew
968 // or Release. First we start with the Request.
969 if (stats_mgr_.passRcvdPacket(ExchangeType::RR, pkt6)) {
970 // The Reply belongs to Request-Reply exchange type. So, we may need
971 // to keep this Reply in the storage if Renews or/and Releases are
972 // being sent. Note that, Reply messages hold the information about
973 // leases assigned. We use this information to construct Renew and
974 // Release messages.
975 if (validateIA(pkt6)) {
976 // if address is correct - check uniqueness
977 address6Uniqueness(pkt6, ExchangeType::RR);
978 // check if there is correct IA to continue with Renew/Release
979 if (stats_mgr_.hasExchangeStats(ExchangeType::RN) ||
980 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
981 // Renew or Release messages are sent, because StatsMgr has the
982 // specific exchange type specified. Let's append the Reply
983 // message to a storage.
984 reply_storage_.append(pkt6);
985 }
986 } else {
987 stats_mgr_.updateRejLeases(ExchangeType::RR);
988 }
989 // The Reply message is not a server's response to the Request message
990 // sent within the 4-way exchange. It may be a response to the Renew
991 // or Release message. In the if clause we first check if StatsMgr
992 // has exchange type for Renew specified, and if it has, if there is
993 // a corresponding Renew message for the received Reply. If not,
994 // we check that StatsMgr has exchange type for Release specified,
995 // as possibly the Reply has been sent in response to Release.
996 } else if (!(stats_mgr_.hasExchangeStats(ExchangeType::RN) &&
997 stats_mgr_.passRcvdPacket(ExchangeType::RN, pkt6)) &&
998 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
999 // At this point, it is only possible that the Reply has been sent
1000 // in response to a Release. Try to match the Reply with Release.
1001 stats_mgr_.passRcvdPacket(ExchangeType::RL, pkt6);
1002 }
1003 }
1004}
1005
1006unsigned int
1007TestControl::consumeReceivedPackets() {
1008 unsigned int pkt_count = 0;
1009 PktPtr pkt;
1010 while ((pkt = receiver_.getPkt())) {
1011 pkt_count += 1;
1012 if (options_.getIpVersion() == 4) {
1013 Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
1014 processReceivedPacket4(pkt4);
1015 } else {
1016 Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<Pkt6>(pkt);
1017 processReceivedPacket6(pkt6);
1018 }
1019 }
1020 return pkt_count;
1021}
1022void
1023TestControl::registerOptionFactories4() const {
1024 static bool factories_registered = false;
1025 if (!factories_registered) {
1026 // DHCP_MESSAGE_TYPE option factory.
1027 LibDHCP::OptionFactoryRegister(Option::V4,
1028 DHO_DHCP_MESSAGE_TYPE,
1029 &TestControl::factoryGeneric);
1030 // DHCP_SERVER_IDENTIFIER option factory.
1031 LibDHCP::OptionFactoryRegister(Option::V4,
1032 DHO_DHCP_SERVER_IDENTIFIER,
1033 &TestControl::factoryGeneric);
1034 // DHCP_PARAMETER_REQUEST_LIST option factory.
1035 LibDHCP::OptionFactoryRegister(Option::V4,
1036 DHO_DHCP_PARAMETER_REQUEST_LIST,
1037 &TestControl::factoryRequestList4);
1038 }
1039 factories_registered = true;
1040}
1041
1042void
1043TestControl::registerOptionFactories6() const {
1044 static bool factories_registered = false;
1045 if (!factories_registered) {
1046 // D6O_ELAPSED_TIME
1047 LibDHCP::OptionFactoryRegister(Option::V6,
1048 D6O_ELAPSED_TIME,
1049 &TestControl::factoryElapsedTime6);
1050 // D6O_RAPID_COMMIT
1051 LibDHCP::OptionFactoryRegister(Option::V6,
1052 D6O_RAPID_COMMIT,
1053 &TestControl::factoryRapidCommit6);
1054 // D6O_ORO (option request option) factory.
1055 LibDHCP::OptionFactoryRegister(Option::V6,
1056 D6O_ORO,
1057 &TestControl::factoryOptionRequestOption6);
1058 // D6O_CLIENTID option factory.
1059 LibDHCP::OptionFactoryRegister(Option::V6,
1060 D6O_CLIENTID,
1061 &TestControl::factoryGeneric);
1062 // D6O_SERVERID option factory.
1063 LibDHCP::OptionFactoryRegister(Option::V6,
1064 D6O_SERVERID,
1065 &TestControl::factoryGeneric);
1066 // D6O_IA_NA option factory.
1067 LibDHCP::OptionFactoryRegister(Option::V6,
1068 D6O_IA_NA,
1069 &TestControl::factoryIana6);
1070
1071 // D6O_IA_PD option factory.
1072 LibDHCP::OptionFactoryRegister(Option::V6,
1073 D6O_IA_PD,
1074 &TestControl::factoryIapd6);
1075
1076
1077 }
1078 factories_registered = true;
1079}
1080
1081void
1082TestControl::registerOptionFactories() const {
1083 switch(options_.getIpVersion()) {
1084 case 4:
1085 registerOptionFactories4();
1086 break;
1087 case 6:
1088 registerOptionFactories6();
1089 break;
1090 default:
1091 isc_throw(InvalidOperation, "command line options have to be parsed "
1092 "before DHCP option factories can be registered");
1093 }
1094}
1095
1096void
1097TestControl::reset() {
1098 transid_gen_.reset();
1099 last_report_ = microsec_clock::universal_time();
1100 // Actual generators will have to be set later on because we need to
1101 // get command line parameters first.
1102 setTransidGenerator(NumberGeneratorPtr());
1103 setMacAddrGenerator(NumberGeneratorPtr());
1104 first_packet_serverid_.clear();
1105 interrupted_ = false;
1106}
1107
1108TestControl::TestControl(CommandOptions& options, BasePerfSocket &socket) :
1109 exit_time_(not_a_date_time),
1110 number_generator_(0, options.getMacsFromFile().size()),
1111 socket_(socket),
1112 receiver_(socket, options.isSingleThreaded(), options.getIpVersion()),
1113 stats_mgr_(options),
1114 options_(options)
1115{
1116 // Reset singleton state before test starts.
1117 reset();
1118
1119 // Ip version is not set ONLY in case the command options
1120 // were not parsed. This surely means that parse() function
1121 // was not called prior to starting the test. This is fatal
1122 // error.
1123 if (options_.getIpVersion() == 0) {
1124 isc_throw(InvalidOperation,
1125 "command options must be parsed before running a test");
1126 } else if (options_.getIpVersion() == 4) {
1127 // Turn off packet queueing.
1128 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, data::ElementPtr());
1129 setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator()));
1130 } else {
1131 // Turn off packet queueing.
1132 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, data::ElementPtr());
1133 setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator(0x00FFFFFF)));
1134 }
1135
1136 uint32_t clients_num = options_.getClientsNum() == 0 ?
1137 1 : options_.getClientsNum();
1138 setMacAddrGenerator(NumberGeneratorPtr(new SequentialGenerator(clients_num)));
1139
1140 // Diagnostics are command line options mainly.
1141 printDiagnostics();
1142 // Option factories have to be registered.
1143 registerOptionFactories();
1144 // Initialize packet templates.
1145 initPacketTemplates();
1146 // Initialize randomization seed.
1147 if (options_.isSeeded()) {
1148 srandom(options_.getSeed());
1149 } else {
1150 // Seed with current time.
1151 time_period duration(from_iso_string("20111231T235959"),
1152 microsec_clock::universal_time());
1153 srandom(duration.length().total_seconds()
1154 + duration.length().fractional_seconds());
1155 }
1156 // If user interrupts the program we will exit gracefully.
1157 signal(SIGINT, TestControl::handleInterrupt);
1158}
1159
1160void
1161TestControl::runWrapped(bool do_stop /*= false */) const {
1162 if (!options_.getWrapped().empty()) {
1163 pid_t pid = 0;
1164 signal(SIGCHLD, handleChild);
1165 pid = fork();
1166 if (pid < 0) {
1167 isc_throw(Unexpected, "unable to fork");
1168 } else if (pid == 0) {
1169 execlp(options_.getWrapped().c_str(), do_stop ? "stop" : "start", (void*)0);
1170 }
1171 }
1172}
1173
1174void
1175TestControl::saveFirstPacket(const Pkt4Ptr& pkt) {
1176 if (options_.testDiags('T')) {
1177 if (template_packets_v4_.find(pkt->getType()) == template_packets_v4_.end()) {
1178 template_packets_v4_[pkt->getType()] = pkt;
1179 }
1180 }
1181}
1182
1183void
1184 TestControl::saveFirstPacket(const Pkt6Ptr& pkt) {
1185 if (options_.testDiags('T')) {
1186 if (template_packets_v6_.find(pkt->getType()) == template_packets_v6_.end()) {
1187 template_packets_v6_[pkt->getType()] = pkt;
1188 }
1189 }
1190}
1191
1192void
1193TestControl::sendDiscover4(const bool preload /*= false*/) {
1194 // Generate the MAC address to be passed in the packet.
1195 uint8_t randomized = 0;
1196 std::vector<uint8_t> mac_address = generateMacAddress(randomized);
1197 // Generate transaction id to be set for the new exchange.
1198 const uint32_t transid = generateTransid();
1199 Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, transid));
1200 if (!pkt4) {
1201 isc_throw(Unexpected, "failed to create DISCOVER packet");
1202 }
1203
1204 // Delete the default Message Type option set by Pkt4
1205 pkt4->delOption(DHO_DHCP_MESSAGE_TYPE);
1206
1207 // Set options: DHCP_MESSAGE_TYPE and DHCP_PARAMETER_REQUEST_LIST
1208 OptionBuffer buf_msg_type;
1209 buf_msg_type.push_back(DHCPDISCOVER);
1210 pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
1211 buf_msg_type));
1212 pkt4->addOption(Option::factory(Option::V4,
1213 DHO_DHCP_PARAMETER_REQUEST_LIST));
1214
1215
1216 // Set client's and server's ports as well as server's address,
1217 // and local (relay) address.
1218 setDefaults4(pkt4);
1219
1220 // Set hardware address
1221 pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address);
1222
1223 // Set client identifier
1224 pkt4->addOption(generateClientId(pkt4->getHWAddr()));
1225
1226 // Check if we need to simulate HA failures by pretending no responses were received.
1227 // The DHCP protocol signals that by increasing secs field (seconds since the configuration attempt started).
1228 if (options_.getIncreaseElapsedTime() &&
1229 stats_mgr_.getTestPeriod().length().total_seconds() >= options_.getWaitForElapsedTime() &&
1230 stats_mgr_.getTestPeriod().length().total_seconds() < options_.getWaitForElapsedTime() +
1231 options_.getIncreaseElapsedTime()) {
1232
1233 // Keep increasing elapsed time. The value should start increasing steadily.
1234 uint32_t val = stats_mgr_.getTestPeriod().length().total_seconds() - options_.getWaitForElapsedTime() + 1;
1235 if (val > 65535) {
1236 val = 65535;
1237 }
1238 pkt4->setSecs(static_cast<uint16_t>(val));
1239 }
1240
1241 // Add any extra options that user may have specified.
1242 addExtraOpts(pkt4);
1243
1244 pkt4->pack();
1245 socket_.send(pkt4);
1246 if (!preload) {
1247 stats_mgr_.passSentPacket(ExchangeType::DO, pkt4);
1248 }
1249
1250 saveFirstPacket(pkt4);
1251}
1252
1253void
1254 TestControl::sendDiscover4(const std::vector<uint8_t>& template_buf,
1255 const bool preload /* = false */) {
1256 // Get the first argument if multiple the same arguments specified
1257 // in the command line. First one refers to DISCOVER packets.
1258 const uint8_t arg_idx = 0;
1259 // Generate the MAC address to be passed in the packet.
1260 uint8_t randomized = 0;
1261 std::vector<uint8_t> mac_address = generateMacAddress(randomized);
1262 // Generate transaction id to be set for the new exchange.
1263 const uint32_t transid = generateTransid();
1264 // Get transaction id offset.
1265 size_t transid_offset = getTransactionIdOffset(arg_idx);
1266 // Get randomization offset.
1267 // We need to go back by HW_ETHER_LEN (MAC address length)
1268 // because this offset points to last octet of MAC address.
1269 size_t rand_offset = getRandomOffset(arg_idx) - HW_ETHER_LEN + 1;
1270 // Create temporary buffer with template contents. We will
1271 // modify this temporary buffer but we don't want to modify
1272 // the original template.
1273 std::vector<uint8_t> in_buf(template_buf.begin(),
1274 template_buf.end());
1275 // Check if we are not going out of bounds.
1276 if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
1277 isc_throw(OutOfRange, "randomization offset is out of bounds");
1278 }
1279 PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
1280 transid_offset,
1281 transid));
1282
1283 // Replace MAC address in the template with actual MAC address.
1284 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1285 // Create a packet from the temporary buffer.
1286 setDefaults4(boost::static_pointer_cast<Pkt4>(pkt4));
1287 // Pack the input packet buffer to output buffer so as it can
1288 // be sent to server.
1289 pkt4->rawPack();
1290 socket_.send(boost::static_pointer_cast<Pkt4>(pkt4));
1291 if (!preload) {
1292 // Update packet stats.
1293 stats_mgr_.passSentPacket(ExchangeType::DO,
1294 boost::static_pointer_cast<Pkt4>(pkt4));
1295 }
1296 saveFirstPacket(pkt4);
1297}
1298
1299bool
1300TestControl::sendMessageFromAck(const uint16_t msg_type) {
1301 // We only permit Request or Release messages to be sent using this
1302 // function.
1303 if (msg_type != DHCPREQUEST && msg_type != DHCPRELEASE) {
1304 isc_throw(isc::BadValue,
1305 "invalid message type "
1306 << msg_type
1307 << " to be sent, expected DHCPREQUEST or DHCPRELEASE");
1308 }
1309
1310 // Get one of the recorded DHCPACK messages.
1311 Pkt4Ptr ack = ack_storage_.getRandom();
1312 if (!ack) {
1313 return (false);
1314 }
1315
1316 // Create message of the specified type.
1317 Pkt4Ptr msg = createMessageFromAck(msg_type, ack);
1318 setDefaults4(msg);
1319
1320 // Override relay address
1321 msg->setGiaddr(ack->getGiaddr());
1322
1323 // Add any extra options that user may have specified.
1324 addExtraOpts(msg);
1325
1326 // Pack it.
1327 msg->pack();
1328
1329 // And send it.
1330 socket_.send(msg);
1331 address4Uniqueness(msg, ExchangeType::RLA);
1332 stats_mgr_.passSentPacket((msg_type == DHCPREQUEST ? ExchangeType::RNA :
1333 ExchangeType::RLA),
1334 msg);
1335 return (true);
1336}
1337
1338
1339bool
1340TestControl::sendMessageFromReply(const uint16_t msg_type) {
1341 // We only permit Release or Renew messages to be sent using this function.
1342 if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
1343 isc_throw(isc::BadValue, "invalid message type " << msg_type
1344 << " to be sent, expected DHCPV6_RENEW or DHCPV6_RELEASE");
1345 }
1346
1347 // Get one of the recorded DHCPV6_OFFER messages.
1348 Pkt6Ptr reply = reply_storage_.getRandom();
1349 if (!reply) {
1350 return (false);
1351 }
1352 // Prepare the message of the specified type.
1353 Pkt6Ptr msg = createMessageFromReply(msg_type, reply);
1354 setDefaults6(msg);
1355
1356 // Add any extra options that user may have specified.
1357 addExtraOpts(msg);
1358
1359 // Pack it.
1360 msg->pack();
1361
1362 // And send it.
1363 socket_.send(msg);
1364 address6Uniqueness(msg, ExchangeType::RL);
1365 stats_mgr_.passSentPacket((msg_type == DHCPV6_RENEW ? ExchangeType::RN
1366 : ExchangeType::RL), msg);
1367 return (true);
1368}
1369
1370void
1371TestControl::sendRequest4(const dhcp::Pkt4Ptr& discover_pkt4,
1372 const dhcp::Pkt4Ptr& offer_pkt4) {
1373 // Use the same transaction id as the one used in the discovery packet.
1374 const uint32_t transid = discover_pkt4->getTransid();
1375 Pkt4Ptr pkt4(new Pkt4(DHCPREQUEST, transid));
1376
1377 // Use first flags indicates that we want to use the server
1378 // id captured in first packet.
1379 if (options_.isUseFirst() &&
1380 (first_packet_serverid_.size() > 0)) {
1381 pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_SERVER_IDENTIFIER,
1382 first_packet_serverid_));
1383 } else {
1384 OptionPtr opt_serverid =
1385 offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
1386 if (!opt_serverid) {
1387 isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
1388 << "in OFFER message");
1389 }
1390 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) == 1) {
1391 first_packet_serverid_ = opt_serverid->getData();
1392 }
1393 pkt4->addOption(opt_serverid);
1394 }
1395
1397 asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
1398 if (!yiaddr.isV4()) {
1399 isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
1400 " IPv4 address");
1401 }
1402 OptionPtr opt_requested_address =
1403 OptionPtr(new Option(Option::V4, DHO_DHCP_REQUESTED_ADDRESS,
1404 OptionBuffer()));
1405 opt_requested_address->setUint32(yiaddr.toUint32());
1406 pkt4->addOption(opt_requested_address);
1407 OptionPtr opt_parameter_list =
1408 Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST);
1409 pkt4->addOption(opt_parameter_list);
1410 // Set client's and server's ports as well as server's address
1411 setDefaults4(pkt4);
1412 // Override relay address
1413 pkt4->setGiaddr(offer_pkt4->getGiaddr());
1414 // Add any extra options that user may have specified.
1415 addExtraOpts(pkt4);
1416
1417 // Set hardware address
1418 pkt4->setHWAddr(offer_pkt4->getHWAddr());
1419 // Set client id.
1420 pkt4->addOption(generateClientId(pkt4->getHWAddr()));
1421 // Set elapsed time.
1422 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1423 pkt4->setSecs(static_cast<uint16_t>(elapsed_time / 1000));
1424 // Prepare on wire data to send.
1425 pkt4->pack();
1426 socket_.send(pkt4);
1427 stats_mgr_.passSentPacket(ExchangeType::RA, pkt4);
1428 saveFirstPacket(pkt4);
1429}
1430
1431void
1432 TestControl::sendRequest4(const std::vector<uint8_t>& template_buf,
1433 const dhcp::Pkt4Ptr& discover_pkt4,
1434 const dhcp::Pkt4Ptr& offer_pkt4) {
1435 // Get the second argument if multiple the same arguments specified
1436 // in the command line. Second one refers to REQUEST packets.
1437 const uint8_t arg_idx = 1;
1438 // Use the same transaction id as the one used in the discovery packet.
1439 const uint32_t transid = discover_pkt4->getTransid();
1440 // Get transaction id offset.
1441 size_t transid_offset = getTransactionIdOffset(arg_idx);
1442 // Get the offset of MAC's last octet.
1443 // We need to go back by HW_ETHER_LEN (MAC address length)
1444 // because this offset points to last octet of MAC address.
1445 size_t rand_offset = getRandomOffset(arg_idx) - HW_ETHER_LEN + 1;
1446 // Create temporary buffer from the template.
1447 std::vector<uint8_t> in_buf(template_buf.begin(),
1448 template_buf.end());
1449 // Check if given randomization offset is not out of bounds.
1450 if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
1451 isc_throw(OutOfRange, "randomization offset is out of bounds");
1452 }
1453
1454 // Create packet from the temporary buffer.
1455 PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
1456 transid_offset,
1457 transid));
1458
1459 // Set hardware address from OFFER packet received.
1460 HWAddrPtr hwaddr = offer_pkt4->getHWAddr();
1461 std::vector<uint8_t> mac_address(HW_ETHER_LEN, 0);
1462 uint8_t hw_len = hwaddr->hwaddr_.size();
1463 if (hw_len != 0) {
1464 memcpy(&mac_address[0], &hwaddr->hwaddr_[0],
1465 hw_len > HW_ETHER_LEN ? HW_ETHER_LEN : hw_len);
1466 }
1467 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1468
1469 // Set elapsed time.
1470 size_t elp_offset = getElapsedTimeOffset();
1471 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1472 pkt4->writeValueAt<uint16_t>(elp_offset,
1473 static_cast<uint16_t>(elapsed_time / 1000));
1474
1475 // Get the actual server id offset.
1476 size_t sid_offset = getServerIdOffset();
1477 // Use first flags indicates that we want to use the server
1478 // id captured in first packet.
1479 if (options_.isUseFirst() &&
1480 (first_packet_serverid_.size() > 0)) {
1481 boost::shared_ptr<LocalizedOption>
1482 opt_serverid(new LocalizedOption(Option::V4,
1483 DHO_DHCP_SERVER_IDENTIFIER,
1484 first_packet_serverid_,
1485 sid_offset));
1486 pkt4->addOption(opt_serverid);
1487 } else {
1488 // Copy the contents of server identifier received in
1489 // OFFER packet to put this into REQUEST.
1490 OptionPtr opt_serverid_offer =
1491 offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
1492 if (!opt_serverid_offer) {
1493 isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
1494 << "in OFFER message");
1495 }
1496 boost::shared_ptr<LocalizedOption>
1497 opt_serverid(new LocalizedOption(Option::V4,
1498 DHO_DHCP_SERVER_IDENTIFIER,
1499 opt_serverid_offer->getData(),
1500 sid_offset));
1501 pkt4->addOption(opt_serverid);
1502 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) == 1) {
1503 first_packet_serverid_ = opt_serverid_offer->getData();
1504 }
1505 }
1506
1508 asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
1509 if (!yiaddr.isV4()) {
1510 isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
1511 " IPv4 address");
1512 }
1513
1514 // Get the actual offset of requested ip.
1515 size_t rip_offset = getRequestedIpOffset();
1516 // Place requested IP option at specified position (rip_offset).
1517 boost::shared_ptr<LocalizedOption>
1518 opt_requested_ip(new LocalizedOption(Option::V4,
1519 DHO_DHCP_REQUESTED_ADDRESS,
1520 OptionBuffer(),
1521 rip_offset));
1522 // The IOAddress is convertible to uint32_t and returns exactly what we need.
1523 opt_requested_ip->setUint32(yiaddr.toUint32());
1524 pkt4->addOption(opt_requested_ip);
1525
1526 setDefaults4(boost::static_pointer_cast<Pkt4>(pkt4));
1527
1528 // Add any extra options that user may have specified.
1529 addExtraOpts(pkt4);
1530
1531 // Prepare on-wire data.
1532 pkt4->rawPack();
1533 socket_.send(boost::static_pointer_cast<Pkt4>(pkt4));
1534 // Update packet stats.
1535 stats_mgr_.passSentPacket(ExchangeType::RA,
1536 boost::static_pointer_cast<Pkt4>(pkt4));
1537 saveFirstPacket(pkt4);
1538}
1539
1540void
1541TestControl::sendRequest6(const Pkt6Ptr& advertise_pkt6) {
1542 const uint32_t transid = generateTransid();
1543 Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid));
1544 // Set elapsed time.
1545 OptionPtr opt_elapsed_time =
1546 Option::factory(Option::V6, D6O_ELAPSED_TIME);
1547 pkt6->addOption(opt_elapsed_time);
1548 // Set client id.
1549 OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID);
1550 if (!opt_clientid) {
1551 isc_throw(Unexpected, "client id not found in received packet");
1552 }
1553 pkt6->addOption(opt_clientid);
1554
1555 // Use first flags indicates that we want to use the server
1556 // id captured in first packet.
1557 if (options_.isUseFirst() &&
1558 (first_packet_serverid_.size() > 0)) {
1559 pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID,
1560 first_packet_serverid_));
1561 } else {
1562 OptionPtr opt_serverid = advertise_pkt6->getOption(D6O_SERVERID);
1563 if (!opt_serverid) {
1564 isc_throw(Unexpected, "server id not found in received packet");
1565 }
1566 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) == 1) {
1567 first_packet_serverid_ = opt_serverid->getData();
1568 }
1569 pkt6->addOption(opt_serverid);
1570 }
1571
1572 // Copy IA_NA or IA_PD option from the Advertise message to the Request
1573 // message being sent to the server. This will throw exception if the
1574 // option to be copied is not found. Note that this function will copy
1575 // one of IA_NA or IA_PD options, depending on the lease-type value
1576 // specified in the command line.
1577 copyIaOptions(advertise_pkt6, pkt6);
1578
1579 // Set default packet data.
1580 setDefaults6(pkt6);
1581
1582 // Add any extra options that user may have specified.
1583 addExtraOpts(pkt6);
1584
1585 // Prepare on-wire data.
1586 pkt6->pack();
1587 socket_.send(pkt6);
1588 stats_mgr_.passSentPacket(ExchangeType::RR, pkt6);
1589 saveFirstPacket(pkt6);
1590}
1591
1592void
1593 TestControl::sendRequest6(const std::vector<uint8_t>& template_buf,
1594 const Pkt6Ptr& advertise_pkt6) {
1595 // Get the second argument if multiple the same arguments specified
1596 // in the command line. Second one refers to REQUEST packets.
1597 const uint8_t arg_idx = 1;
1598 // Generate transaction id.
1599 const uint32_t transid = generateTransid();
1600 // Get transaction id offset.
1601 size_t transid_offset = getTransactionIdOffset(arg_idx);
1602 PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
1603 transid_offset, transid));
1604 // Set elapsed time.
1605 size_t elp_offset = getElapsedTimeOffset();
1606 boost::shared_ptr<LocalizedOption>
1607 opt_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME,
1608 OptionBuffer(), elp_offset));
1609 pkt6->addOption(opt_elapsed_time);
1610
1611 // Get the actual server id offset.
1612 size_t sid_offset = getServerIdOffset();
1613 // Use first flags indicates that we want to use the server
1614 // id captured in first packet.
1615 if (options_.isUseFirst() &&
1616 (first_packet_serverid_.size() > 0)) {
1617 boost::shared_ptr<LocalizedOption>
1618 opt_serverid(new LocalizedOption(Option::V6,
1619 D6O_SERVERID,
1620 first_packet_serverid_,
1621 sid_offset));
1622 pkt6->addOption(opt_serverid);
1623
1624 } else {
1625 // Copy the contents of server identifier received in
1626 // ADVERTISE packet to put this into REQUEST.
1627 OptionPtr opt_serverid_advertise =
1628 advertise_pkt6->getOption(D6O_SERVERID);
1629 if (!opt_serverid_advertise) {
1630 isc_throw(BadValue, "there is no SERVERID option "
1631 << "in ADVERTISE message");
1632 }
1633 boost::shared_ptr<LocalizedOption>
1634 opt_serverid(new LocalizedOption(Option::V6,
1635 D6O_SERVERID,
1636 opt_serverid_advertise->getData(),
1637 sid_offset));
1638 pkt6->addOption(opt_serverid);
1639 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) == 1) {
1640 first_packet_serverid_ = opt_serverid_advertise->getData();
1641 }
1642 }
1643 // Set IA_NA
1644 boost::shared_ptr<Option6IA> opt_ia_na_advertise =
1645 boost::static_pointer_cast<Option6IA>(advertise_pkt6->getOption(D6O_IA_NA));
1646 if (!opt_ia_na_advertise) {
1647 isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
1648 "packet");
1649 }
1650 size_t addr_offset = getRequestedIpOffset();
1651 boost::shared_ptr<LocalizedOption>
1652 opt_ia_na(new LocalizedOption(opt_ia_na_advertise, addr_offset));
1653 if (!opt_ia_na->valid()) {
1654 isc_throw(BadValue, "Option IA_NA in advertise packet is invalid");
1655 }
1656 pkt6->addOption(opt_ia_na);
1657 // Set server id.
1658 OptionPtr opt_serverid_advertise = advertise_pkt6->getOption(D6O_SERVERID);
1659 if (!opt_serverid_advertise) {
1660 isc_throw(Unexpected, "DHCPV6 SERVERID option not found in received "
1661 "packet");
1662 }
1663 size_t srvid_offset = getServerIdOffset();
1664 boost::shared_ptr<LocalizedOption>
1665 opt_serverid(new LocalizedOption(Option::V6, D6O_SERVERID,
1666 opt_serverid_advertise->getData(),
1667 srvid_offset));
1668 pkt6->addOption(opt_serverid);
1669 // Get randomization offset.
1670 size_t rand_offset = getRandomOffset(arg_idx);
1671 OptionPtr opt_clientid_advertise = advertise_pkt6->getOption(D6O_CLIENTID);
1672 if (!opt_clientid_advertise) {
1673 isc_throw(Unexpected, "DHCPV6 CLIENTID option not found in received packet");
1674 }
1675 rand_offset -= (opt_clientid_advertise->len() - 1);
1676 // Set client id.
1677 boost::shared_ptr<LocalizedOption>
1678 opt_clientid(new LocalizedOption(Option::V6, D6O_CLIENTID,
1679 opt_clientid_advertise->getData(),
1680 rand_offset));
1681 pkt6->addOption(opt_clientid);
1682 // Set default packet data.
1683 setDefaults6(pkt6);
1684
1685 // Add any extra options that user may have specified.
1686 addExtraOpts(pkt6);
1687
1688 // Prepare on wire data.
1689 pkt6->rawPack();
1690 // Send packet.
1691 socket_.send(pkt6);
1692 // Update packet stats.
1693 stats_mgr_.passSentPacket(ExchangeType::RR, pkt6);
1694
1695 // When 'T' diagnostics flag is specified it means that user requested
1696 // printing packet contents. It will be just one (first) packet which
1697 // contents will be printed. Here we check if this packet has been already
1698 // collected. If it hasn't we save this packet so as we can print its
1699 // contents when test is finished.
1700 if (options_.testDiags('T') &&
1701 (template_packets_v6_.find(DHCPV6_REQUEST) == template_packets_v6_.end())) {
1702 template_packets_v6_[DHCPV6_REQUEST] = pkt6;
1703 }
1704}
1705
1706void
1707TestControl::sendSolicit6(const bool preload /*= false*/) {
1708 // Generate DUID to be passed to the packet
1709 uint8_t randomized = 0;
1710 std::vector<uint8_t> duid = generateDuid(randomized);
1711 // Generate transaction id to be set for the new exchange.
1712 const uint32_t transid = generateTransid();
1713 Pkt6Ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
1714 if (!pkt6) {
1715 isc_throw(Unexpected, "failed to create SOLICIT packet");
1716 }
1717
1718 // Check if we need to simulate HA failures by pretending no responses were received.
1719 // The DHCPv6 protocol signals that by increasing the elapsed option field. Note it is in 1/100 of a second.
1720 if (options_.getIncreaseElapsedTime() &&
1721 stats_mgr_.getTestPeriod().length().total_seconds() >= options_.getWaitForElapsedTime() &&
1722 stats_mgr_.getTestPeriod().length().total_seconds() < options_.getWaitForElapsedTime() +
1723 options_.getIncreaseElapsedTime()) {
1724
1725
1726 // Keep increasing elapsed time. The value should start increasing steadily.
1727 uint32_t val = (stats_mgr_.getTestPeriod().length().total_seconds() - options_.getWaitForElapsedTime() + 1)*100;
1728 if (val > 65535) {
1729 val = 65535;
1730 }
1731 OptionPtr elapsed(new OptionInt<uint16_t>(Option::V6, D6O_ELAPSED_TIME, val));
1732 pkt6->addOption(elapsed);
1733 } else {
1734 pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
1735 }
1736
1737 if (options_.isRapidCommit()) {
1738 pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT));
1739 }
1740 pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
1741 pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
1742
1743
1744 // Depending on the lease-type option specified, we should request
1745 // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD) or both.
1746
1747 // IA_NA
1748 if (options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
1749 pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
1750 }
1751 // IA_PD
1752 if (options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
1753 pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
1754 }
1755
1756 setDefaults6(pkt6);
1757
1758 // Add any extra options that user may have specified.
1759 addExtraOpts(pkt6);
1760
1761 pkt6->pack();
1762 socket_.send(pkt6);
1763 if (!preload) {
1764 stats_mgr_.passSentPacket(ExchangeType::SA, pkt6);
1765 }
1766
1767 saveFirstPacket(pkt6);
1768}
1769
1770void
1771 TestControl::sendSolicit6(const std::vector<uint8_t>& template_buf,
1772 const bool preload /*= false*/) {
1773 const int arg_idx = 0;
1774 // Get transaction id offset.
1775 size_t transid_offset = getTransactionIdOffset(arg_idx);
1776 // Generate transaction id to be set for the new exchange.
1777 const uint32_t transid = generateTransid();
1778 // Create packet.
1779 PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
1780 transid_offset, transid));
1781 if (!pkt6) {
1782 isc_throw(Unexpected, "failed to create SOLICIT packet");
1783 }
1784 size_t rand_offset = getRandomOffset(arg_idx);
1785 // randomized will pick number of bytes randomized so we can
1786 // just use part of the generated duid and substitute a few bytes
1788 uint8_t randomized = 0;
1789 std::vector<uint8_t> duid = generateDuid(randomized);
1790 if (rand_offset > template_buf.size()) {
1791 isc_throw(OutOfRange, "randomization offset is out of bounds");
1792 }
1793 // Store random part of the DUID into the packet.
1794 pkt6->writeAt(rand_offset - randomized + 1,
1795 duid.end() - randomized, duid.end());
1796
1797 // Prepare on-wire data.
1798 pkt6->rawPack();
1799 setDefaults6(pkt6);
1800
1801 // Add any extra options that user may have specified.
1802 addExtraOpts(pkt6);
1803
1804 // Send solicit packet.
1805 socket_.send(pkt6);
1806 if (!preload) {
1807 // Update packet stats.
1808 stats_mgr_.passSentPacket(ExchangeType::SA, pkt6);
1809 }
1810 saveFirstPacket(pkt6);
1811}
1812
1813
1814void
1815TestControl::setDefaults4(const Pkt4Ptr& pkt) {
1816 // Interface name.
1817 IfacePtr iface = socket_.getIface();
1818 if (iface == NULL) {
1819 isc_throw(BadValue, "unable to find interface with given index");
1820 }
1821 pkt->setIface(iface->getName());
1822 // Interface index.
1823 pkt->setIndex(socket_.ifindex_);
1824 // Local client's port (68)
1825 pkt->setLocalPort(DHCP4_CLIENT_PORT);
1826 // Server's port (67)
1827 if (options_.getRemotePort()) {
1828 pkt->setRemotePort(options_.getRemotePort());
1829 } else {
1830 pkt->setRemotePort(DHCP4_SERVER_PORT);
1831 }
1832 // The remote server's name or IP.
1833 pkt->setRemoteAddr(IOAddress(options_.getServerName()));
1834 // Set local address.
1835 pkt->setLocalAddr(IOAddress(socket_.addr_));
1836 // Set relay (GIADDR) address to local address if multiple
1837 // subnet mode is not enabled
1838 if (!options_.checkMultiSubnet()) {
1839 pkt->setGiaddr(IOAddress(socket_.addr_));
1840 } else {
1841 pkt->setGiaddr(IOAddress(options_.getRandRelayAddr()));
1842 }
1843 // Pretend that we have one relay (which is us).
1844 pkt->setHops(1);
1845}
1846
1847void
1848TestControl::setDefaults6(const Pkt6Ptr& pkt) {
1849 // Interface name.
1850 IfacePtr iface = socket_.getIface();
1851 if (iface == NULL) {
1852 isc_throw(BadValue, "unable to find interface with given index");
1853 }
1854 pkt->setIface(iface->getName());
1855 // Interface index.
1856 pkt->setIndex(socket_.ifindex_);
1857 // Local client's port (547)
1858 pkt->setLocalPort(DHCP6_CLIENT_PORT);
1859 // Server's port (548)
1860 if (options_.getRemotePort()) {
1861 pkt->setRemotePort(options_.getRemotePort());
1862 } else {
1863 pkt->setRemotePort(DHCP6_SERVER_PORT);
1864 }
1865 // Set local address.
1866 pkt->setLocalAddr(socket_.addr_);
1867 // The remote server's name or IP.
1868 pkt->setRemoteAddr(IOAddress(options_.getServerName()));
1869
1870 // only act as a relay agent when told so.
1873 if (options_.isUseRelayedV6()) {
1874 Pkt6::RelayInfo relay_info;
1875 relay_info.msg_type_ = DHCPV6_RELAY_FORW;
1876 relay_info.hop_count_ = 0;
1877 if (options_.checkMultiSubnet()) {
1878 relay_info.linkaddr_ = IOAddress(options_.getRandRelayAddr());
1879 } else {
1880 relay_info.linkaddr_ = IOAddress(socket_.addr_);
1881 }
1882 relay_info.peeraddr_ = IOAddress(socket_.addr_);
1883 pkt->addRelayInfo(relay_info);
1884 }
1885}
1886
1887namespace {
1888
1889static OptionBuffer const concatenateBuffers(OptionBuffer const& a,
1890 OptionBuffer const& b) {
1891 OptionBuffer result;
1892 result.insert(result.end(), a.begin(), a.end());
1893 result.insert(result.end(), b.begin(), b.end());
1894 return result;
1895}
1896
1897static void mergeOptionIntoPacket(Pkt4Ptr const& packet,
1898 OptionPtr const& extra_option) {
1899 uint16_t const code(extra_option->getType());
1900 // If option already exists...
1901 OptionPtr const& option(packet->getOption(code));
1902 if (option) {
1903 switch (code) {
1904 // List here all the options for which we want to concatenate buffers.
1905 case DHO_DHCP_PARAMETER_REQUEST_LIST:
1906 packet->delOption(code);
1907 packet->addOption(boost::make_shared<Option>(
1908 Option::V4, code,
1909 concatenateBuffers(option->getData(),
1910 extra_option->getData())));
1911 return;
1912 default:
1913 // For all others, add option as usual, it will result in "Option
1914 // already present in this message" error.
1915 break;
1916 }
1917 }
1918 packet->addOption(extra_option);
1919}
1920
1921} // namespace
1922
1923void
1924TestControl::addExtraOpts(const Pkt4Ptr& pkt) {
1925 // Add all extra options that the user may have specified.
1926 const dhcp::OptionCollection& extra_opts = options_.getExtraOpts();
1927 for (auto entry : extra_opts) {
1928 mergeOptionIntoPacket(pkt, entry.second);
1929 }
1930}
1931
1932void
1933 TestControl::addExtraOpts(const Pkt6Ptr& pkt) {
1934 // Add all extra options that the user may have specified.
1935 const dhcp::OptionCollection& extra_opts = options_.getExtraOpts();
1936 for (auto entry : extra_opts) {
1937 pkt->addOption(entry.second);
1938 }
1939}
1940
1941} // namespace perfdhcp
1942} // namespace isc
check_valgrind.h
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::InvalidOperation
A generic exception that is thrown if a function is called in a prohibited way.
Definition: exceptions/exceptions.h:143
isc::NotFound
A generic exception that is thrown when an object can not be found.
Definition: exceptions/exceptions.h:175
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition: exceptions/exceptions.h:115
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic)
Definition: io_address.h:45
isc::asiolink::IOAddress::toText
std::string toText() const
Convert the address to a string.
Definition: io_address.cc:52
isc::asiolink::IOAddress::toUint32
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
Definition: io_address.cc:113
isc::asiolink::IOAddress::isV4
bool isV4() const
Convenience function to check for an IPv4 address.
Definition: io_address.h:103
isc::dhcp::Option6IAAddr
Definition: option6_iaaddr.h:22
isc::dhcp::Option6IAAddr::getAddress
isc::asiolink::IOAddress getAddress() const
Returns address contained within this option.
Definition: option6_iaaddr.h:98
isc::dhcp::Option6IAPrefix
Class that represents IAPREFIX option in DHCPv6.
Definition: option6_iaprefix.h:51
isc::dhcp::OptionInt
Forward declaration to OptionInt.
Definition: option_int.h:49
isc::dhcp::Option
Definition: option.h:74
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
isc::dhcp::Pkt4
Represents DHCPv4 packet.
Definition: pkt4.h:37
isc::dhcp::Pkt6
Represents a DHCPv6 packet.
Definition: pkt6.h:44
isc::perfdhcp::BasePerfSocket
Socket wrapper structure.
Definition: perf_socket.h:26
isc::perfdhcp::BasePerfSocket::getIface
virtual dhcp::IfacePtr getIface()=0
See description of this method in PerfSocket class below.
isc::perfdhcp::BasePerfSocket::ifindex_
uint16_t ifindex_
Interface index.
Definition: perf_socket.h:29
isc::perfdhcp::BasePerfSocket::send
virtual bool send(const dhcp::Pkt4Ptr &pkt)=0
See description of this method in PerfSocket class below.
isc::perfdhcp::CommandOptions::LeaseType::ADDRESS
@ ADDRESS
Definition: command_options.h:55
isc::perfdhcp::CommandOptions::LeaseType::ADDRESS_AND_PREFIX
@ ADDRESS_AND_PREFIX
Definition: command_options.h:57
isc::perfdhcp::CommandOptions::LeaseType::PREFIX
@ PREFIX
Definition: command_options.h:56
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:58
isc::perfdhcp::CommandOptions
Command Options.
Definition: command_options.h:30
isc::perfdhcp::CommandOptions::testDiags
bool testDiags(const char diag)
Find if diagnostic flag has been set.
Definition: command_options.h:419
isc::perfdhcp::CommandOptions::getRandRelayAddr
std::string getRandRelayAddr()
Returns random relay address.
Definition: command_options.h:408
isc::perfdhcp::CommandOptions::getIncreaseElapsedTime
int getIncreaseElapsedTime() const
Returns increased elapsed time.
Definition: command_options.h:231
isc::perfdhcp::CommandOptions::getServerIdOffset
int getServerIdOffset() const
Returns template offset for server-ID.
Definition: command_options.h:358
isc::perfdhcp::CommandOptions::getWrapped
std::string getWrapped() const
Returns wrapped command.
Definition: command_options.h:373
isc::perfdhcp::CommandOptions::getRenewRate
int getRenewRate() const
Returns a rate at which DHCPv6 Renew messages are sent.
Definition: command_options.h:164
isc::perfdhcp::CommandOptions::getIpVersion
uint8_t getIpVersion() const
Returns IP version.
Definition: command_options.h:144
isc::perfdhcp::CommandOptions::getDuidTemplate
std::vector< uint8_t > getDuidTemplate() const
Returns DUID template.
Definition: command_options.h:199
isc::perfdhcp::CommandOptions::getAddrUnique
bool getAddrUnique() const
Returns address uniqueness value.
Definition: command_options.h:209
isc::perfdhcp::CommandOptions::getRate
int getRate() const
Returns exchange rate.
Definition: command_options.h:159
isc::perfdhcp::CommandOptions::getCleanReportSeparator
std::string getCleanReportSeparator() const
Returns clean report separator.
Definition: command_options.h:184
isc::perfdhcp::CommandOptions::isRapidCommit
bool isRapidCommit() const
Check if rapid commit option used.
Definition: command_options.h:308
isc::perfdhcp::CommandOptions::checkMultiSubnet
bool checkMultiSubnet()
Check if multi subnet mode is enabled.
Definition: command_options.h:413
isc::perfdhcp::CommandOptions::getExtraOpts
const isc::dhcp::OptionCollection & getExtraOpts() const
Returns extra options to be inserted.
Definition: command_options.h:378
isc::perfdhcp::CommandOptions::isUseFirst
bool isUseFirst() const
Check if server-ID to be taken from first package.
Definition: command_options.h:313
isc::perfdhcp::CommandOptions::getReportDelay
int getReportDelay() const
Returns delay between two performance reports.
Definition: command_options.h:174
isc::perfdhcp::CommandOptions::getRandomOffset
std::vector< int > getRandomOffset() const
Returns template offsets for rnd.
Definition: command_options.h:348
isc::perfdhcp::CommandOptions::getRemotePort
int getRemotePort() const
Returns remote port number.
Definition: command_options.h:283
isc::perfdhcp::CommandOptions::getWaitForElapsedTime
int getWaitForElapsedTime() const
Returns time to wait for elapsed time increase.
Definition: command_options.h:225
isc::perfdhcp::CommandOptions::ExchangeMode
ExchangeMode
2-way (cmd line param -i) or 4-way exchanges
Definition: command_options.h:117
isc::perfdhcp::CommandOptions::DO_SA
@ DO_SA
Definition: command_options.h:118
isc::perfdhcp::CommandOptions::DORA_SARR
@ DORA_SARR
Definition: command_options.h:119
isc::perfdhcp::CommandOptions::getMacsFromFile
const MacAddrsVector & getMacsFromFile() const
Returns reference to a vector of MAC addresses read from a file.
Definition: command_options.h:338
isc::perfdhcp::CommandOptions::getTemplateFiles
std::vector< std::string > getTemplateFiles() const
Returns template file names.
Definition: command_options.h:323
isc::perfdhcp::CommandOptions::getTransactionIdOffset
std::vector< int > getTransactionIdOffset() const
brief Returns template offsets for xid.
Definition: command_options.h:343
isc::perfdhcp::CommandOptions::MacAddrsVector
std::vector< std::vector< uint8_t > > MacAddrsVector
A vector holding MAC addresses.
Definition: command_options.h:42
isc::perfdhcp::CommandOptions::getElapsedTimeOffset
int getElapsedTimeOffset() const
Returns template offset for elapsed time.
Definition: command_options.h:353
isc::perfdhcp::CommandOptions::getServerName
std::string getServerName() const
Returns server name.
Definition: command_options.h:393
isc::perfdhcp::CommandOptions::getNumRequests
std::vector< int > getNumRequests() const
Returns maximum number of exchanges.
Definition: command_options.h:214
isc::perfdhcp::CommandOptions::getLeaseType
LeaseType getLeaseType() const
\ brief Returns the type of lease being requested.
Definition: command_options.h:154
isc::perfdhcp::CommandOptions::isUseRelayedV6
bool isUseRelayedV6() const
Check if generated DHCPv6 messages should appear as relayed.
Definition: command_options.h:318
isc::perfdhcp::CommandOptions::getExitWaitTime
int getExitWaitTime() const
Returns the time in microseconds to delay the program by.
Definition: command_options.h:288
isc::perfdhcp::CommandOptions::getClientsNum
uint32_t getClientsNum() const
Returns number of simulated clients.
Definition: command_options.h:189
isc::perfdhcp::CommandOptions::isSeeded
bool isSeeded() const
Checks if seed provided.
Definition: command_options.h:293
isc::perfdhcp::CommandOptions::getSeed
uint32_t getSeed() const
Returns random seed.
Definition: command_options.h:298
isc::perfdhcp::CommandOptions::getExchangeMode
ExchangeMode getExchangeMode() const
Returns packet exchange mode.
Definition: command_options.h:149
isc::perfdhcp::CommandOptions::printCommandLine
void printCommandLine() const
Print command line arguments.
Definition: command_options.cc:1058
isc::perfdhcp::CommandOptions::getCleanReport
int getCleanReport() const
Returns clean report mode.
Definition: command_options.h:179
isc::perfdhcp::CommandOptions::getMacTemplate
std::vector< uint8_t > getMacTemplate() const
Returns MAC address template.
Definition: command_options.h:194
isc::perfdhcp::CommandOptions::getRequestedIpOffset
int getRequestedIpOffset() const
Returns template offset for requested IP.
Definition: command_options.h:363
isc::perfdhcp::ExchangeStats::malformed_pkts_
static int malformed_pkts_
Definition: bin/perfdhcp/stats_mgr.h:585
isc::perfdhcp::LocalizedOption
DHCP option at specific offset.
Definition: localized_option.h:37
isc::perfdhcp::PerfPkt4
PerfPkt4 (DHCPv4 packet)
Definition: perf_pkt4.h:42
isc::perfdhcp::PerfPkt6
PerfPkt6 (DHCPv6 packet)
Definition: perf_pkt6.h:41
isc::perfdhcp::Receiver::getPkt
dhcp::PktPtr getPkt()
Get DHCP packet.
Definition: receiver.cc:58
isc::perfdhcp::StatsMgr::updateRejLeases
void updateRejLeases(const ExchangeType xchg_type)
Increase total number of rejected leases.
Definition: bin/perfdhcp/stats_mgr.h:1042
isc::perfdhcp::StatsMgr::printStats
void printStats() const
Print statistics counters for all exchange types.
Definition: bin/perfdhcp/stats_mgr.h:1096
isc::perfdhcp::StatsMgr::printCustomCounters
void printCustomCounters() const
Print names and values of custom counters.
Definition: bin/perfdhcp/stats_mgr.h:1198
isc::perfdhcp::StatsMgr::updateNonUniqueAddrNum
void updateNonUniqueAddrNum(const ExchangeType xchg_type)
Increase total number of non unique addresses.
Definition: bin/perfdhcp/stats_mgr.h:1051
isc::perfdhcp::StatsMgr::getRcvdPacketsNum
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
Definition: bin/perfdhcp/stats_mgr.h:992
isc::perfdhcp::StatsMgr::hasExchangeStats
bool hasExchangeStats(const ExchangeType xchg_type) const
Check if the exchange type has been specified.
Definition: bin/perfdhcp/stats_mgr.h:756
isc::perfdhcp::StatsMgr::printIntermediateStats
void printIntermediateStats(bool clean_report, std::string clean_sep) const
Print intermediate statistics.
Definition: bin/perfdhcp/stats_mgr.h:1123
isc::perfdhcp::StatsMgr::getTestPeriod
boost::posix_time::time_period getTestPeriod() const
Get time period since the start of test.
Definition: bin/perfdhcp/stats_mgr.h:1076
isc::perfdhcp::StatsMgr::passSentPacket
void passSentPacket(const ExchangeType xchg_type, const dhcp::PktPtr &packet)
Adds new packet to the sent packets list.
Definition: bin/perfdhcp/stats_mgr.h:831
isc::perfdhcp::StatsMgr::passRcvdPacket
dhcp::PktPtr passRcvdPacket(const ExchangeType xchg_type, const dhcp::PktPtr &packet)
Add new received packet and match with sent packet.
Definition: bin/perfdhcp/stats_mgr.h:851
isc::perfdhcp::TestControl::SequentialGenerator
Sequential numbers generator class.
Definition: test_control.h:158
isc::perfdhcp::TestControl::saveFirstPacket
void saveFirstPacket(const dhcp::Pkt4Ptr &pkt)
Save the first DHCPv4 sent packet of the specified type.
Definition: test_control.cc:1175
isc::perfdhcp::TestControl::address6Uniqueness
void address6Uniqueness(const dhcp::Pkt6Ptr &pkt6, ExchangeType xchg_type)
Process received v6 addresses uniqueness.
Definition: test_control.cc:858
isc::perfdhcp::TestControl::HW_ETHER_LEN
static const uint8_t HW_ETHER_LEN
Length of the Ethernet HW address (MAC) in bytes.
Definition: test_control.h:190
isc::perfdhcp::TestControl::waitToExit
bool waitToExit()
Delay the exit by a fixed given time to catch up to all exchanges that were already started.
Definition: test_control.cc:48
isc::perfdhcp::TestControl::template_packets_v4_
std::map< uint8_t, dhcp::Pkt4Ptr > template_packets_v4_
First packets send.
Definition: test_control.h:1101
isc::perfdhcp::TestControl::sendMessageFromReply
bool sendMessageFromReply(const uint16_t msg_type)
Send DHCPv6 Renew or Release message.
Definition: test_control.cc:1340
isc::perfdhcp::TestControl::addExtraOpts
void addExtraOpts(const dhcp::Pkt4Ptr &pkt4)
Inserts extra options specified by user.
Definition: test_control.cc:1924
isc::perfdhcp::TestControl::printDiagnostics
void printDiagnostics() const
Print main diagnostics data.
Definition: test_control.cc:609
isc::perfdhcp::TestControl::handleChild
static void handleChild(int sig)
Handle child signal.
Definition: test_control.cc:534
isc::perfdhcp::TestControl::registerOptionFactories4
void registerOptionFactories4() const
Register option factory functions for DHCPv4.
Definition: test_control.cc:1023
isc::perfdhcp::TestControl::transid_gen_
NumberGeneratorPtr transid_gen_
Transaction id generator.
Definition: test_control.h:1086
isc::perfdhcp::TestControl::macaddr_gen_
NumberGeneratorPtr macaddr_gen_
Numbers generator for MAC address.
Definition: test_control.h:1089
isc::perfdhcp::TestControl::getRequestedIpOffset
int getRequestedIpOffset() const
Return requested ip offset in a packet.
Definition: test_control.cc:496
isc::perfdhcp::TestControl::NumberGeneratorPtr
boost::shared_ptr< NumberGenerator > NumberGeneratorPtr
The default generator pointer.
Definition: test_control.h:155
isc::perfdhcp::TestControl::sendMultipleMessages4
uint64_t sendMultipleMessages4(const uint32_t msg_type, const uint64_t msg_num)
Send number of DHCPREQUEST (renew) messages to a server.
Definition: test_control.cc:587
isc::perfdhcp::TestControl::validateIA
bool validateIA(const dhcp::Pkt6Ptr &pkt6)
Process IA in received DHCPv6 packet.
Definition: test_control.cc:909
isc::perfdhcp::TestControl::createMessageFromAck
dhcp::Pkt4Ptr createMessageFromAck(const uint16_t msg_type, const dhcp::Pkt4Ptr &ack)
Creates DHCPREQUEST from a DHCPACK message.
Definition: test_control.cc:164
isc::perfdhcp::TestControl::interrupted_
static bool interrupted_
Program interrupted flag.
Definition: test_control.h:1107
isc::perfdhcp::TestControl::readPacketTemplate
void readPacketTemplate(const std::string &file_name)
Read DHCP message template from file.
Definition: test_control.cc:766
isc::perfdhcp::TestControl::getTemplateBuffer
TemplateBuffer getTemplateBuffer(const size_t idx) const
Return template buffer.
Definition: test_control.cc:516
isc::perfdhcp::TestControl::generateMacAddress
std::vector< uint8_t > generateMacAddress(uint8_t &randomized)
Generate MAC address.
Definition: test_control.cc:360
isc::perfdhcp::TestControl::setDefaults4
void setDefaults4(const dhcp::Pkt4Ptr &pkt)
Set default DHCPv4 packet parameters.
Definition: test_control.cc:1815
isc::perfdhcp::TestControl::exit_time_
boost::posix_time::ptime exit_time_
Initialized at first exit condition with the time perfdhcp should exit.
Definition: test_control.h:343
isc::perfdhcp::TestControl::options_
CommandOptions & options_
Command options.
Definition: test_control.h:1110
isc::perfdhcp::TestControl::receiver_
Receiver receiver_
Receiver used to receive DHCP traffic.
Definition: test_control.h:1071
isc::perfdhcp::TestControl::vector2Hex
static std::string vector2Hex(const std::vector< uint8_t > &vec, const std::string &separator="")
Convert vector in hexadecimal string.
Definition: test_control.cc:750
isc::perfdhcp::TestControl::sendMultipleMessages6
uint64_t sendMultipleMessages6(const uint32_t msg_type, const uint64_t msg_num)
Send number of DHCPv6 Renew or Release messages to the server.
Definition: test_control.cc:598
isc::perfdhcp::TestControl::setMacAddrGenerator
void setMacAddrGenerator(const NumberGeneratorPtr &generator)
Set new MAC address generator.
Definition: test_control.h:206
isc::perfdhcp::TestControl::setDefaults6
void setDefaults6(const dhcp::Pkt6Ptr &pkt)
Set default DHCPv6 packet parameters.
Definition: test_control.cc:1848
isc::perfdhcp::TestControl::last_report_
boost::posix_time::ptime last_report_
Last intermediate report time.
Definition: test_control.h:1074
isc::perfdhcp::TestControl::haveAllPacketsBeenReceived
bool haveAllPacketsBeenReceived() const
Checks if all expected packets were already received.
Definition: test_control.cc:69
isc::perfdhcp::TestControl::cleanCachedPackets
void cleanCachedPackets()
Removes cached DHCPv6 Reply packets every second.
Definition: test_control.cc:96
isc::perfdhcp::TestControl::processReceivedPacket4
void processReceivedPacket4(const dhcp::Pkt4Ptr &pkt4)
Process received DHCPv4 packet.
Definition: test_control.cc:814
isc::perfdhcp::TestControl::sendRequest6
void sendRequest6(const dhcp::Pkt6Ptr &advertise_pkt6)
Send DHCPv6 REQUEST message.
Definition: test_control.cc:1541
isc::perfdhcp::TestControl::TestControl
TestControl(CommandOptions &options, BasePerfSocket &socket)
Default constructor.
Definition: test_control.cc:1108
isc::perfdhcp::TestControl::factoryOptionRequestOption6
static dhcp::OptionPtr factoryOptionRequestOption6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 ORO option.
Definition: test_control.cc:327
isc::perfdhcp::TestControl::sendSolicit6
void sendSolicit6(const bool preload=false)
Send DHCPv6 SOLICIT message.
Definition: test_control.cc:1707
isc::perfdhcp::TestControl::factoryIapd6
static dhcp::OptionPtr factoryIapd6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create IA_PD option.
Definition: test_control.cc:305
isc::perfdhcp::TestControl::template_packets_v6_
std::map< uint8_t, dhcp::Pkt6Ptr > template_packets_v6_
Template for v6.
Definition: test_control.h:1104
isc::perfdhcp::TestControl::factoryRapidCommit6
static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 RAPID_COMMIT option instance.
Definition: test_control.cc:321
isc::perfdhcp::TestControl::reply_storage_
PacketStorage< dhcp::Pkt6 > reply_storage_
Storage for reply messages.
Definition: test_control.h:1083
isc::perfdhcp::TestControl::registerOptionFactories6
void registerOptionFactories6() const
Register option factory functions for DHCPv6.
Definition: test_control.cc:1043
isc::perfdhcp::TestControl::sendPackets
void sendPackets(const uint64_t packets_num, const bool preload=false)
Send number of packets to initiate new exchanges.
Definition: test_control.cc:559
isc::perfdhcp::TestControl::registerOptionFactories
void registerOptionFactories() const
Register option factory functions for DHCPv4 or DHCPv6.
Definition: test_control.cc:1082
isc::perfdhcp::TestControl::number_generator_
UniformRandomIntegerGenerator number_generator_
Generate uniformly distributed integers in range of [min, max].
Definition: test_control.h:351
isc::perfdhcp::TestControl::TemplateBuffer
std::vector< uint8_t > TemplateBuffer
Packet template buffer.
Definition: test_control.h:124
isc::perfdhcp::TestControl::sendMessageFromAck
bool sendMessageFromAck(const uint16_t msg_type)
Send DHCPv4 renew (DHCPREQUEST).
Definition: test_control.cc:1300
isc::perfdhcp::TestControl::runWrapped
void runWrapped(bool do_stop=false) const
Run wrapped command.
Definition: test_control.cc:1161
isc::perfdhcp::TestControl::processReceivedPacket6
void processReceivedPacket6(const dhcp::Pkt6Ptr &pkt6)
Process received DHCPv6 packet.
Definition: test_control.cc:943
isc::perfdhcp::TestControl::getElapsedTime
uint32_t getElapsedTime(const T &pkt1, const T &pkt2)
Calculate elapsed time between two packets.
Definition: test_control.cc:472
isc::perfdhcp::TestControl::socket_
BasePerfSocket & socket_
Socket used for DHCP traffic.
Definition: test_control.h:1068
isc::perfdhcp::TestControl::reset
void reset()
Resets internal state of the object.
Definition: test_control.cc:1097
isc::perfdhcp::TestControl::addUniqeAddr
void addUniqeAddr(const std::set< std::string > &current, ExchangeType xchg_type)
add unique address to already assigned list.
Definition: test_control.h:615
isc::perfdhcp::TestControl::address4Uniqueness
void address4Uniqueness(const dhcp::Pkt4Ptr &pkt4, ExchangeType xchg_type)
Process received v4 addresses uniqueness.
Definition: test_control.cc:896
isc::perfdhcp::TestControl::getRandomOffset
int getRandomOffset(const int arg_idx) const
Return randomization offset in a packet.
Definition: test_control.cc:486
isc::perfdhcp::TestControl::createMessageFromReply
dhcp::Pkt6Ptr createMessageFromReply(const uint16_t msg_type, const dhcp::Pkt6Ptr &reply)
Creates DHCPv6 message from the Reply packet.
Definition: test_control.cc:225
isc::perfdhcp::TestControl::getElapsedTimeOffset
int getElapsedTimeOffset() const
Return elapsed time offset in a packet.
Definition: test_control.cc:461
isc::perfdhcp::TestControl::byte2Hex
static std::string byte2Hex(const uint8_t b)
Convert binary value to hex string.
Definition: test_control.cc:155
isc::perfdhcp::TestControl::printTemplates
void printTemplates() const
Print templates information.
Definition: test_control.cc:680
isc::perfdhcp::TestControl::sendRequest4
void sendRequest4(const dhcp::Pkt4Ptr &discover_pkt4, const dhcp::Pkt4Ptr &offer_pkt4)
Send DHCPv4 REQUEST message.
Definition: test_control.cc:1371
isc::perfdhcp::TestControl::consumeReceivedPackets
unsigned int consumeReceivedPackets()
Pull packets from receiver and process them.
Definition: test_control.cc:1007
isc::perfdhcp::TestControl::template_buffers_
TemplateBufferCollection template_buffers_
Packet template buffers.
Definition: test_control.h:1095
isc::perfdhcp::TestControl::stats_mgr_
StatsMgr stats_mgr_
Statistics Manager.
Definition: test_control.h:1077
isc::perfdhcp::TestControl::printStats
void printStats() const
Print performance statistics.
Definition: test_control.cc:741
isc::perfdhcp::TestControl::ack_storage_
PacketStorage< dhcp::Pkt4 > ack_storage_
Storage for DHCPACK messages.
Definition: test_control.h:1080
isc::perfdhcp::TestControl::copyIaOptions
void copyIaOptions(const dhcp::Pkt6Ptr &pkt_from, dhcp::Pkt6Ptr &pkt_to)
Copies IA_NA or IA_PD option from one packet to another.
Definition: test_control.cc:127
isc::perfdhcp::TestControl::setTransidGenerator
void setTransidGenerator(const NumberGeneratorPtr &generator)
Set new transaction id generator.
Definition: test_control.h:195
isc::perfdhcp::TestControl::factoryGeneric
static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create generic option.
Definition: test_control.cc:282
isc::perfdhcp::TestControl::factoryRequestList4
static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv4 Request List option.
Definition: test_control.cc:340
isc::perfdhcp::TestControl::factoryElapsedTime6
static dhcp::OptionPtr factoryElapsedTime6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 ELAPSED_TIME option.
Definition: test_control.cc:269
isc::perfdhcp::TestControl::handleInterrupt
static void handleInterrupt(int sig)
Handle interrupt signal.
Definition: test_control.cc:542
isc::perfdhcp::TestControl::getTransactionIdOffset
int getTransactionIdOffset(const int arg_idx) const
Return transaction id offset in a packet.
Definition: test_control.cc:524
isc::perfdhcp::TestControl::initPacketTemplates
void initPacketTemplates()
Reads packet templates from files.
Definition: test_control.cc:547
isc::perfdhcp::TestControl::printRate
void printRate() const
Print rate statistics.
Definition: test_control.cc:691
isc::perfdhcp::TestControl::printIntermediateStats
void printIntermediateStats()
Print intermediate statistics.
Definition: test_control.cc:729
isc::perfdhcp::TestControl::printTemplate
void printTemplate(const uint8_t packet_type) const
Print template information.
Definition: test_control.cc:623
isc::perfdhcp::TestControl::getServerIdOffset
int getServerIdOffset() const
Return server id offset in a packet.
Definition: test_control.cc:506
isc::perfdhcp::TestControl::generateDuid
std::vector< uint8_t > generateDuid(uint8_t &randomized)
Generate DUID.
Definition: test_control.cc:415
isc::perfdhcp::TestControl::sendDiscover4
void sendDiscover4(const bool preload=false)
Send DHCPv4 DISCOVER message.
Definition: test_control.cc:1193
isc::perfdhcp::TestControl::generateClientId
dhcp::OptionPtr generateClientId(const dhcp::HWAddrPtr &hwaddr) const
Generate DHCPv4 client identifier from HW address.
Definition: test_control.cc:406
isc::perfdhcp::TestControl::first_packet_serverid_
dhcp::OptionBuffer first_packet_serverid_
Buffer holding server id received in first packet.
Definition: test_control.h:1092
isc::perfdhcp::TestControl::generateTransid
uint32_t generateTransid()
generate transaction id.
Definition: test_control.h:538
isc::perfdhcp::TestControl::factoryIana6
static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create IA_NA option.
Definition: test_control.cc:289
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
isc::util::OutputBuffer::getLength
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
isc::util::OutputBuffer::getData
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
command_options.h
dhcp4.h
D6O_SERVERID
@ D6O_SERVERID
Definition: dhcp6.h:22
D6O_CLIENTID
@ D6O_CLIENTID
Definition: dhcp6.h:21
D6O_NAME_SERVERS
@ D6O_NAME_SERVERS
Definition: dhcp6.h:43
D6O_RAPID_COMMIT
@ D6O_RAPID_COMMIT
Definition: dhcp6.h:34
D6O_IA_NA
@ D6O_IA_NA
Definition: dhcp6.h:23
D6O_ORO
@ D6O_ORO
Definition: dhcp6.h:26
D6O_IA_PD
@ D6O_IA_PD
Definition: dhcp6.h:45
D6O_DOMAIN_SEARCH
@ D6O_DOMAIN_SEARCH
Definition: dhcp6.h:44
D6O_IAADDR
@ D6O_IAADDR
Definition: dhcp6.h:25
D6O_ELAPSED_TIME
@ D6O_ELAPSED_TIME
Definition: dhcp6.h:28
D6O_IAPREFIX
@ D6O_IAPREFIX
Definition: dhcp6.h:46
DHCPV6_ADVERTISE
@ DHCPV6_ADVERTISE
Definition: dhcp6.h:206
DHCPV6_REQUEST
@ DHCPV6_REQUEST
Definition: dhcp6.h:207
DHCPV6_RENEW
@ DHCPV6_RENEW
Definition: dhcp6.h:209
DHCPV6_REPLY
@ DHCPV6_REPLY
Definition: dhcp6.h:211
DHCPV6_SOLICIT
@ DHCPV6_SOLICIT
Definition: dhcp6.h:205
DHCPV6_RELEASE
@ DHCPV6_RELEASE
Definition: dhcp6.h:212
DHCPV6_RELAY_FORW
@ DHCPV6_RELAY_FORW
Definition: dhcp6.h:216
exceptions.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:210
iface_mgr.h
libdhcp++.h
isc::asiolink
Definition: addr_utilities.cc:170
isc::data::copy
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1360
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
isc::dhcp
Definition: dhcp4/client_handler.cc:20
isc::dhcp::PktPtr
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition: pkt.h:797
isc::dhcp::DHO_SUBNET_MASK
@ DHO_SUBNET_MASK
Definition: dhcp4.h:70
isc::dhcp::DHO_ROUTERS
@ DHO_ROUTERS
Definition: dhcp4.h:72
isc::dhcp::DHO_DOMAIN_NAME
@ DHO_DOMAIN_NAME
Definition: dhcp4.h:84
isc::dhcp::DHO_DOMAIN_NAME_SERVERS
@ DHO_DOMAIN_NAME_SERVERS
Definition: dhcp4.h:75
isc::dhcp::DHO_DHCP_MESSAGE_TYPE
@ DHO_DHCP_MESSAGE_TYPE
Definition: dhcp4.h:122
isc::dhcp::DHO_DHCP_SERVER_IDENTIFIER
@ DHO_DHCP_SERVER_IDENTIFIER
Definition: dhcp4.h:123
isc::dhcp::DHO_HOST_NAME
@ DHO_HOST_NAME
Definition: dhcp4.h:81
isc::dhcp::DHO_DHCP_CLIENT_IDENTIFIER
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition: dhcp4.h:130
isc::dhcp::DHO_DHCP_REQUESTED_ADDRESS
@ DHO_DHCP_REQUESTED_ADDRESS
Definition: dhcp4.h:119
isc::dhcp::DHO_TIME_OFFSET
@ DHO_TIME_OFFSET
Definition: dhcp4.h:71
isc::dhcp::DHO_DHCP_PARAMETER_REQUEST_LIST
@ DHO_DHCP_PARAMETER_REQUEST_LIST
Definition: dhcp4.h:124
isc::dhcp::DHO_BROADCAST_ADDRESS
@ DHO_BROADCAST_ADDRESS
Definition: dhcp4.h:97
isc::dhcp::Pkt4Ptr
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
isc::dhcp::IfacePtr
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:487
isc::dhcp::OptionCollection
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition: option.h:40
isc::dhcp::Option6IAPrefixPtr
boost::shared_ptr< Option6IAPrefix > Option6IAPrefixPtr
Pointer to the Option6IAPrefix object.
Definition: option6_iaprefix.h:143
isc::dhcp::HWAddrPtr
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
isc::dhcp::Option6IAAddrPtr
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
Definition: option6_iaaddr.h:17
isc::dhcp::DHCPREQUEST
@ DHCPREQUEST
Definition: dhcp4.h:236
isc::dhcp::DHCPOFFER
@ DHCPOFFER
Definition: dhcp4.h:235
isc::dhcp::DHCPRELEASE
@ DHCPRELEASE
Definition: dhcp4.h:240
isc::dhcp::DHCPDISCOVER
@ DHCPDISCOVER
Definition: dhcp4.h:234
isc::dhcp::DHCPACK
@ DHCPACK
Definition: dhcp4.h:238
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
isc::dhcp::HTYPE_ETHER
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition: dhcp4.h:56
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
isc::perfdhcp::PerfPkt4Ptr
boost::shared_ptr< PerfPkt4 > PerfPkt4Ptr
Definition: perf_pkt4.h:128
isc::perfdhcp::ExchangeType
ExchangeType
DHCP packet exchange types.
Definition: bin/perfdhcp/stats_mgr.h:32
isc::perfdhcp::ExchangeType::RA
@ RA
DHCPv4 REQUEST-ACK.
isc::perfdhcp::ExchangeType::SA
@ SA
DHCPv6 SOLICIT-ADVERTISE.
isc::perfdhcp::ExchangeType::RNA
@ RNA
DHCPv4 REQUEST-ACK (renewal)
isc::perfdhcp::ExchangeType::RL
@ RL
DHCPv6 RELEASE-REPLY.
isc::perfdhcp::ExchangeType::RLA
@ RLA
DHCPv4 RELEASE.
isc::perfdhcp::ExchangeType::RN
@ RN
DHCPv6 RENEW-REPLY.
isc::perfdhcp::ExchangeType::DO
@ DO
DHCPv4 DISCOVER-OFFER.
isc::perfdhcp::ExchangeType::RR
@ RR
DHCPv6 REQUEST-REPLY.
isc::perfdhcp::PerfPkt6Ptr
boost::shared_ptr< PerfPkt6 > PerfPkt6Ptr
Definition: perf_pkt6.h:127
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
perfdhcp
option6_ia.h
option6_iaaddr.h
option6_iaprefix.h
option_int.h
perf_pkt4.h
perf_pkt6.h
receiver.h
isc::dhcp::Pkt6::RelayInfo
structure that describes a single relay information
Definition: pkt6.h:85
isc::dhcp::Pkt6::RelayInfo::msg_type_
uint8_t msg_type_
message type (RELAY-FORW oro RELAY-REPL)
Definition: pkt6.h:94
isc::dhcp::Pkt6::RelayInfo::linkaddr_
isc::asiolink::IOAddress linkaddr_
fixed field in relay-forw/relay-reply
Definition: pkt6.h:96
isc::dhcp::Pkt6::RelayInfo::hop_count_
uint8_t hop_count_
number of traversed relays (up to 32)
Definition: pkt6.h:95
isc::dhcp::Pkt6::RelayInfo::peeraddr_
isc::asiolink::IOAddress peeraddr_
fixed field in relay-forw/relay-reply
Definition: pkt6.h:97
isc::dhcp::SocketInfo::addr_
isc::asiolink::IOAddress addr_
Definition: socket_info.h:21
test_control.h