return (lease_type == type_);
}
+bool
+CommandOptions::LeaseType::includes(const Type lease_type) const {
+ return (is(ADDRESS_AND_PREFIX) || (lease_type == type_));
+}
+
void
CommandOptions::LeaseType::set(const Type lease_type) {
type_ = lease_type;
} else if (cmd_line_arg == "prefix-only") {
type_ = PREFIX_ONLY;
+ } else if (cmd_line_arg == "address-and-prefix") {
+ type_ = ADDRESS_AND_PREFIX;
+
} else {
isc_throw(isc::InvalidParameter, "value of lease-type: -e<lease-type>,"
" must be one of the following: 'address-only' or"
return ("address-only (IA_NA option added to the client's request)");
case PREFIX_ONLY:
return ("prefix-only (IA_PD option added to the client's request)");
+ case ADDRESS_AND_PREFIX:
+ return ("address-and-prefix (Both IA_NA and IA_PD options added to the"
+ " client's request)");
default:
isc_throw(Unexpected, "internal error: undefined lease type code when"
" returning textual representation of the lease type");
" having been lost. The value is given in seconds and may contain a\n"
" fractional component. The default is 1 second.\n"
"-e<lease-type>: A type of lease being requested from the server. It\n"
- " may be one of the following: address-only or prefix-only. The\n"
- " former indicates that the regular IP (v4 or v6) will be requested,\n"
- " the latter indicates that the IPv6 prefixes will be requested. The\n"
- " '-e prefix-only' must not be used with -4.\n"
+ " may be one of the following: address-only, prefix-only or\n"
+ " address-and-prefix. The address-only indicates that the regular\n"
+ " address (v4 or v6) will be requested. The prefix-only indicates\n"
+ " that the IPv6 prefix will be requested. The address-and-prefix\n"
+ " indicates that both IPv6 address and prefix will be requested.\n"
+ " The '-e prefix-only' and -'e address-and-prefix' must not be\n"
+ " used with -4.\n"
"-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)\n"
" elapsed-time option in the (second/request) template.\n"
" The value 0 disables it.\n"
/// The lease type code.
enum Type {
ADDRESS_ONLY,
- PREFIX_ONLY
+ PREFIX_ONLY,
+ ADDRESS_AND_PREFIX
};
LeaseType();
/// \return true if lease type is matched with the specified code.
bool is(const Type lease_type) const;
+ /// \brief Checks if lease type implies request for the address,
+ /// prefix (or both) as specified by the function argument.
+ ///
+ /// This is a convenience function to check that, for the lease type
+ /// specified from the command line, the address or prefix
+ /// (IA_NA or IA_PD) option should be sent to the server.
+ /// For example, if user specified '-e address-and-prefix' in the
+ /// command line this function will return true for both ADDRESS_ONLY
+ /// and PREFIX_ONLY, because both address and prefix is requested from
+ /// the server.
+ ///
+ /// \param lease_type A lease type.
+ ///
+ /// \return true if the lease type implies creation of the address,
+ /// prefix or both as specified by the argument.
+ bool includes(const Type lease_type) const;
+
/// \brief Sets the lease type code.
///
/// \param lease_type A lease type code.
isc_throw(BadValue, "NULL pointers must not be specified as arguments"
" for the copyIaOptions function");
}
- OptionPtr option;
+ // IA_NA
if (CommandOptions::instance().getLeaseType()
- .is(CommandOptions::LeaseType::ADDRESS_ONLY)) {
- option = pkt_from->getOption(D6O_IA_NA);
+ .includes(CommandOptions::LeaseType::ADDRESS_ONLY)) {
+ OptionPtr 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);
+ pkt_to->addOption(option);
+ }
+ // IA_PD
+ if (CommandOptions::instance().getLeaseType()
+ .includes(CommandOptions::LeaseType::PREFIX_ONLY)) {
+ OptionPtr 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);
}
- pkt_to->addOption(option);
+
}
uint16_t port = options.getLocalPort();
int sock = 0;
- uint8_t family = (options.getIpVersion() == 6) ? AF_INET6 : AF_INET;
+ uint8_t family = (options.getIpVersion() == 6) ? AF_INET6 : AF_INET;
IOAddress remoteaddr(servername);
-
+
// Check for mismatch between IP option and server address
if (family != remoteaddr.getFamily()) {
- isc_throw(InvalidParameter,
- "Values for IP version: " <<
+ isc_throw(InvalidParameter,
+ "Values for IP version: " <<
static_cast<unsigned int>(options.getIpVersion()) <<
- " and server address: " << servername << " are mismatched.");
+ " and server address: " << servername << " are mismatched.");
}
if (port == 0) {
pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
// Depending on the lease-type option specified, we should request
- // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD).
+ // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD) or both.
+
+ // IA_NA
if (CommandOptions::instance().getLeaseType()
- .is(CommandOptions::LeaseType::ADDRESS_ONLY)) {
+ .includes(CommandOptions::LeaseType::ADDRESS_ONLY)) {
pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
- } else {
+ }
+ // IA_PD
+ if (CommandOptions::instance().getLeaseType()
+ .includes(CommandOptions::LeaseType::PREFIX_ONLY)) {
pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
}
EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::PREFIX_ONLY));
}
+TEST(LeaseTypeTest, includes) {
+ CommandOptions::LeaseType
+ lease_type(CommandOptions::LeaseType::ADDRESS_ONLY);
+ ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS_ONLY));
+ EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::ADDRESS_ONLY));
+ EXPECT_FALSE(lease_type.includes(CommandOptions::LeaseType::PREFIX_ONLY));
+ EXPECT_FALSE(
+ lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
+ );
+
+ lease_type.set(CommandOptions::LeaseType::PREFIX_ONLY);
+ EXPECT_FALSE(lease_type.includes(CommandOptions::LeaseType::ADDRESS_ONLY));
+ EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::PREFIX_ONLY));
+ EXPECT_FALSE(
+ lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
+ );
+
+ lease_type.set(CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
+ EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::ADDRESS_ONLY));
+ EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::PREFIX_ONLY));
+ EXPECT_TRUE(
+ lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
+ );
+
+}
+
+
TEST(LeaseTypeTest, fromCommandLine) {
CommandOptions::LeaseType
lease_type(CommandOptions::LeaseType::ADDRESS_ONLY);
/* ASSERT_NO_THROW(tc.processReceivedPacket6(sock,
advertise_pkt6)); */
try {
- tc.processReceivedPacket6(sock, advertise_pkt6);
+ tc.processReceivedPacket6(sock,
+ advertise_pkt6);
} catch (const Exception& ex) {
std::cout << ex.what() << std::endl;
}
/// \return instance of the packet.
boost::shared_ptr<Pkt6>
createAdvertisePkt6(uint32_t transid) const {
- OptionPtr opt_ia;
+ boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
+ // Add IA_NA if requested by the client.
+ if (CommandOptions::instance().getLeaseType()
+ .includes(CommandOptions::LeaseType::ADDRESS_ONLY)) {
+ OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+ advertise->addOption(opt_ia_na);
+ }
+ // Add IA_PD if requested by the client.
if (CommandOptions::instance().getLeaseType()
- .is(CommandOptions::LeaseType::ADDRESS_ONLY)) {
- opt_ia = Option::factory(Option::V6, D6O_IA_NA);
- } else {
- opt_ia = Option::factory(Option::V6, D6O_IA_PD);
+ .includes(CommandOptions::LeaseType::PREFIX_ONLY)) {
+ OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+ advertise->addOption(opt_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);
advertise->addOption(opt_serverid);
advertise->addOption(opt_clientid);
advertise->updateTimestamp();
EXPECT_EQ(10, iterations_performed);
}
+TEST_F(TestControlTest, Packet6ExchangeAddressAndPrefix) {
+ // 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 address-and-prefix"
+ + " -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");