reset();
}
+void
+TestControl::copyIaOptions(const Pkt6Ptr& pkt_from, Pkt6Ptr& pkt_to) {
+ if (!pkt_from || !pkt_to) {
+ isc_throw(BadValue, "NULL pointers must not be specified as arguments"
+ " for the copyIaOptions function");
+ }
+ OptionPtr option;
+ if (CommandOptions::instance().getLeaseType() ==
+ CommandOptions::ADDRESS_ONLY) {
+ option = pkt_from->getOption(D6O_IA_NA);
+ if (!option) {
+ isc_throw(OptionNotFound, "IA_NA option not found in the"
+ " server's response");
+ }
+ } else {
+ option = pkt_from->getOption(D6O_IA_PD);
+ if (!option) {
+ isc_throw(OptionNotFound, "IA_PD option not found in the"
+ " server's response");
+ }
+ }
+ pkt_to->addOption(option);
+
+}
+
std::string
TestControl::byte2Hex(const uint8_t b) const {
const int b1 = b / 16;
return (OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)));
}
+OptionPtr
+TestControl::factoryIapd6(Option::Universe, uint16_t,
+ const OptionBuffer& buf) {
+ // @todo allow different values of T1, T2 and IAID.
+ static const uint8_t buf_array[] = {
+ 0, 0, 0, 1, // IAID = 1
+ 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
+ 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
+ };
+ OptionBuffer buf_ia_pd(buf_array, buf_array + sizeof(buf_array));
+ // Append sub-options to IA_PD.
+ buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
+ return (OptionPtr(new Option(Option::V6, D6O_IA_PD, buf_ia_pd)));
+}
+
+
OptionPtr
TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
const OptionBuffer&) {
D6O_IA_NA,
&TestControl::factoryIana6);
+ // D6O_IA_PD option factory.
+ LibDHCP::OptionFactoryRegister(Option::V6,
+ D6O_IA_PD,
+ &TestControl::factoryIapd6);
+
}
factories_registered = true;
}
pkt6->addOption(opt_serverid);
}
- // Set IA_NA option.
- OptionPtr opt_ia_na = advertise_pkt6->getOption(D6O_IA_NA);
- if (!opt_ia_na) {
- isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
- "packet");
- }
- pkt6->addOption(opt_ia_na);
+
+ // Copy IA_NA or IA_PD option from the Advertise message to the Request
+ // message being sent to the server. This will throw exception if the
+ // option to be copied is not found. Note that this function will copy
+ // one of IA_NA or IA_PD options, depending on the lease-type value
+ // specified in the command line.
+ copyIaOptions(advertise_pkt6, pkt6);
// Set default packet data.
setDefaults6(socket, pkt6);
}
pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
- pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
+
+ // Depending on the lease-type option specified, we should request
+ // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD).
+ if (CommandOptions::instance().getLeaseType() ==
+ CommandOptions::ADDRESS_ONLY) {
+ pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
+ } else {
+ pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
+ }
setDefaults6(socket, pkt6);
pkt6->pack();
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
/// Default DHCPV6 IA_NA offset in the packet template.
static const size_t DHCPV6_IA_NA_OFFSET = 40;
+/// @brief Exception thrown when the required option is not found in a packet.
+class OptionNotFound : public Exception {
+public:
+ OptionNotFound(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
/// \brief Test Control class.
///
/// This singleton class is used to run the performance test with
uint16_t type,
const dhcp::OptionBuffer& buf);
+ /// \brief Factory function to create IA_PD option.
+ ///
+ /// this factory function creates DHCPv6 IA_PD option instance.
+ ///
+ /// \param u universe (ignored).
+ /// \param type option-type (ignored).
+ /// \param buf option-buffer carrying sub-options.
+ static dhcp::OptionPtr factoryIapd6(dhcp::Option::Universe u,
+ uint16_t type,
+ const dhcp::OptionBuffer& buf);
+
/// \brief Factory function to create DHCPv6 ORO option.
///
/// This factory function creates DHCPv6 Option Request Option instance.
private:
+ /// \brief Copies IA_NA or IA_PD option from one packet to another.
+ ///
+ /// This function checks the lease-type specified in the command line
+ /// with option -e<lease-type>. If 'address-only' value has been specified
+ /// this function expects that IA_NA option is present in the packet
+ /// encapsulated by pkt_from object. If 'prefix-only' value has been
+ /// specified, this function expects that IA_PD option is present in the
+ /// packet encapsulated by pkt_to object.
+ ///
+ /// \todo In the future it is planned to add support for the perfdhcp to
+ /// request address and prefix in the same DHCP message (request both
+ /// IA_NA and IA_PD options). In this case, this function will have to
+ /// be extended to copy both IA_NA and IA_PD options.
+ ///
+ /// \warning
+ ///
+ /// \param [in] pkt_from A packet from which options should be copied.
+ /// \parma [out] pkt_to A packet to which options should be copied.
+ ///
+ /// \throw isc::perfdhcp::OptionNotFound if a required option is not
+ /// found in the packet from which options should be copied.
+ /// \throw isc::BadValue if any of the specified pointers to packets
+ /// is NULL.
+ void copyIaOptions(const dhcp::Pkt6Ptr& pkt_from, dhcp::Pkt6Ptr& pkt_to);
+
/// \brief Convert binary value to hex string.
///
/// \todo Consider moving this function to src/lib/util.
boost::shared_ptr<Pkt6>
advertise_pkt6(createAdvertisePkt6(transid));
// Receive ADVERTISE and send REQUEST.
- ASSERT_NO_THROW(tc.processReceivedPacket6(sock, advertise_pkt6));
+ /* ASSERT_NO_THROW(tc.processReceivedPacket6(sock,
+ advertise_pkt6)); */
+ try {
+ tc.processReceivedPacket6(sock, advertise_pkt6);
+ } catch (const Exception& ex) {
+ std::cout << ex.what() << std::endl;
+ }
++transid;
}
if (tc.checkExitConditions()) {
/// \return instance of the packet.
boost::shared_ptr<Pkt6>
createAdvertisePkt6(uint32_t transid) const {
- OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+ OptionPtr opt_ia;
+ if (CommandOptions::instance().getLeaseType() ==
+ CommandOptions::ADDRESS_ONLY) {
+ opt_ia = Option::factory(Option::V6, D6O_IA_NA);
+ } else {
+ opt_ia = Option::factory(Option::V6, D6O_IA_PD);
+ }
OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
NakedTestControl tc;
uint8_t randomized = 0;
std::vector<uint8_t> duid(tc.generateDuid(randomized));
OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
- advertise->addOption(opt_ia_na);
+ advertise->addOption(opt_ia);
advertise->addOption(opt_serverid);
advertise->addOption(opt_clientid);
advertise->updateTimestamp();
EXPECT_EQ(6, iterations_performed);
}
+TEST_F(TestControlTest, Packet6ExchangePrefixDelegation) {
+ // Get the local loopback interface to open socket on
+ // it and test packets exchanges. We don't want to fail
+ // the test if interface is not available.
+ std::string loopback_iface(getLocalLoopback());
+ if (loopback_iface.empty()) {
+ std::cout << "Unable to find the loopback interface. Skip test."
+ << std::endl;
+ return;
+ }
+
+ const int iterations_num = 100;
+ // Set number of iterations to 10.
+ processCmdLine("perfdhcp -l " + loopback_iface
+ + " -e prefix-only"
+ + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
+ int iterations_performed = 0;
+ // Set number of received packets equal to number of iterations.
+ // This simulates no packet drops.
+ bool use_templates = false;
+ testPkt6Exchange(iterations_num, iterations_num, use_templates,
+ iterations_performed);
+ // Actual number of iterations should be 10.
+ EXPECT_EQ(10, iterations_performed);
+}
+
TEST_F(TestControlTest, PacketTemplates) {
std::vector<uint8_t> template1(256);
std::string file1("test1.hex");