EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
-// Verify the relay-agent-info entry must be a map or a string.
+// Verify that the relay-agent-info entry must be a map or a string.
TEST_F(StashAgentOptionTest, badRelayAgentInfoEntry) {
// Set the relay-agent-info entry to a boolean.
relay_agent_info_ = Element::create(true);
EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
-// Verify the sub-options entry is required in new extended info format.
+// Verify that the sub-options entry is required in new extended info format.
TEST_F(StashAgentOptionTest, subOptionsEntry) {
// Remove the sub-options entry.
relay_agent_info_ = Element::createMap();
EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
-// Verify the sub-options entry must be a string.
+// Verify that the sub-options entry must be a string.
TEST_F(StashAgentOptionTest, badSubOptionsEntry) {
// Set the sub-options entry to a boolean.
sub_options_ = Element::create(true);
EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
-// Verify the sub-options entry must be not empty.
+// Verify that the sub-options entry must be not empty.
TEST_F(StashAgentOptionTest, emptySubOptionsEntry) {
// Set the sub-options entry to empty.
sub_options_ = Element::create("");
EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
-// Verify the sub-options entry must be a valid hexstring.
+// Verify that the sub-options entry must be a valid hexstring.
TEST_F(StashAgentOptionTest, hexString) {
// Set the sub-options entry to invalid hexstring.
sub_options_ = Element::create("foobar");
EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
-// Verify the sub-options entry must be a valid RAI content.
+// Verify that the sub-options entry must be a valid RAI content.
TEST_F(StashAgentOptionTest, badRelayAgentInfo) {
// Set the sub-options entry to truncated RAI content.
string content = sub_options_->stringValue();
EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
}
+// Verify that the client id when set must match.
+TEST_F(StashAgentOptionTest, badClientId) {
+ // Use another the client id.
+ query_->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
+ query_->addOption(generateClientId(8));
+
+ CfgMgr::instance().commit();
+ EXPECT_NO_THROW(LeaseMgrFactory::instance().addLease(lease_));
+
+ EXPECT_NO_THROW(srv_.recoverStashedAgentOption(query_));
+ OptionPtr rai_query = query_->getOption(DHO_DHCP_AGENT_OPTIONS);
+ EXPECT_FALSE(rai_query);
+ EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
+}
+
+// Verify that when the client id is not used the hardware address must match.
+TEST_F(StashAgentOptionTest, badHwareAddress) {
+ // No longer use the client id.
+ query_->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
+ lease_.reset(new Lease4(addr_, hwaddr_, ClientIdPtr(), 100, time(0), 1));
+ lease_->setContext(user_context_);
+
+ // Change the hardware address.
+ auto hwaddr2 = generateHWAddr(8);
+ ASSERT_NE(hwaddr_, hwaddr2);
+ query_->setHWAddr(hwaddr2);
+
+ CfgMgr::instance().commit();
+ EXPECT_NO_THROW(LeaseMgrFactory::instance().addLease(lease_));
+
+ EXPECT_NO_THROW(srv_.recoverStashedAgentOption(query_));
+ OptionPtr rai_query = query_->getOption(DHO_DHCP_AGENT_OPTIONS);
+ EXPECT_FALSE(rai_query);
+ EXPECT_FALSE(query_->inClass("STASH_AGENT_OPTIONS"));
+}
+
/// @todo: lease ownership
/// @todo: Implement proper tests for MySQL lease/host database,
/// - Configuration 20:
/// - No subnets.
/// - Global authoritative flag is true.
+///
+/// - Configuration 21:
+/// - Use for testing stash agent options (flag true).
+/// - 1 subnet with storing extended info enabled
+///
+/// - Configuration 22:
+/// - Use for testing stash agent options (flag true).
+/// - 1 subnet with storing extended info enabled
+/// - 1 reservation using the circuit-id
+///
+/// - Configuration 23:
+/// - Use for testing stash agent options (flag false).
+/// - 1 subnet with storing extended info enabled
+/// - 1 reservation using the circuit-id
const char* DORA_CONFIGS[] = {
// Configuration 0
"{ \"interfaces-config\": {"
"\"authoritative\": true,"
"\"subnet4\": []"
"}",
+
+ // Configuration 21
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"stash-agent-options\": true,"
+ "\"subnet4\": [ {"
+ " \"subnet\": \"10.0.0.0/24\", "
+ " \"id\": 1, "
+ " \"store-extended-info\": true,"
+ " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]"
+ "} ]"
+ "}",
+
+ // Configuration 22
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"stash-agent-options\": true,"
+ "\"host-reservation-identifiers\": [ \"circuit-id\" ],"
+ "\"subnet4\": [ {"
+ " \"subnet\": \"10.0.0.0/24\", "
+ " \"id\": 1, "
+ " \"store-extended-info\": true,"
+ " \"reservations\": [ {"
+ " \"circuit-id\": \"'charter950'\","
+ " \"ip-address\": \"10.0.0.9\" } ]"
+ "} ]"
+ "}",
+
+ // Configuration 23
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"stash-agent-options\": false,"
+ "\"host-reservation-identifiers\": [ \"circuit-id\" ],"
+ "\"subnet4\": [ {"
+ " \"subnet\": \"10.0.0.0/24\", "
+ " \"id\": 1, "
+ " \"store-extended-info\": true,"
+ " \"reservations\": [ {"
+ " \"circuit-id\": \"'charter950'\","
+ " \"ip-address\": \"10.0.0.9\" } ]"
+ "} ]"
+ "}",
};
/// @brief Test fixture class for testing 4-way (DORA) exchanges.
/// @brief Checks that features related to lease caching (such as lease reuse statistics) work.
void leaseCaching();
+ /// @brief Checks that stash-agent-options enables direct renewall
+ /// of addresses from pool allocation for a relayed client.
+ ///
+ /// @note: no negative counterpart as the stash-agent-options is not
+ /// required for this scenario.
+ void stashAgentOptions();
+
+ /// @brief Checks that stash-agent-options enables direct renewall
+ /// of addresses from host reservation using the relay-agent-info option.
+ void stashAgentOptionsReservation();
+
+ /// @brief Checks that stash-agent-options is required for direct
+ /// renewall of addresses from host reservation using the
+ /// relay-agent-info option.
+ void noStashAgentOptionsReservation();
+
/// @brief Checks the value of a statistic.
///
/// @param name name of statistic to check
leaseCaching();
}
+void
+DORATest::stashAgentOptions() {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ // Use relay agent to make sure that the desired subnet is
+ // selected for our client.
+ client.useRelay(true, IOAddress("10.0.0.20"), IOAddress("10.0.0.21"));
+ // Specify client identifier.
+ client.includeClientId("01:11:22:33:44:55:66");
+ // Set the circuit id.
+ client.setCircuitId("charter950");
+
+ // Configure DHCP server.
+ configure(DORA_CONFIGS[21], *client.getServer());
+ // Perform 4-way exchange and should obtain an address from pool.
+ ASSERT_NO_THROW_LOG(client.doDORA());
+ // Make sure that the server responded.
+ ASSERT_TRUE(client.getContext().response_);
+ Pkt4Ptr resp = client.getContext().response_;
+ // Make sure that the server has responded with DHCPACK.
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+ // Make sure that the client has got the lease for the first address
+ // of the pool.
+ ASSERT_EQ("10.0.0.10", client.config_.lease_.addr_.toText());
+
+ // Renew.
+ client.setState(Dhcp4Client::RENEWING);
+ // Set the unicast destination address to indicate that it is a renewal.
+ client.setDestAddress(IOAddress("10.0.0.1"));
+ // Disable relay.
+ client.useRelay(false);
+ ASSERT_NO_THROW_LOG(client.doRequest());
+ ASSERT_TRUE(client.getContext().response_);
+ resp = client.getContext().response_;
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+ ASSERT_EQ("10.0.0.10", client.config_.lease_.addr_.toText());
+}
+
+TEST_F(DORATest, stashAgentOptions) {
+ Dhcpv4SrvMTTestGuard guard(*this, false);
+ stashAgentOptions();
+}
+
+TEST_F(DORATest, stashAgentOptionsMultiThreading) {
+ Dhcpv4SrvMTTestGuard guard(*this, true);
+ stashAgentOptions();
+}
+
+void
+DORATest::stashAgentOptionsReservation() {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ // Use relay agent to make sure that the desired subnet is
+ // selected for our client.
+ client.useRelay(true, IOAddress("10.0.0.20"), IOAddress("10.0.0.21"));
+ // Specify client identifier.
+ client.includeClientId("01:11:22:33:44:55:66");
+ // Set the circuit id.
+ client.setCircuitId("charter950");
+
+ // Configure DHCP server.
+ configure(DORA_CONFIGS[22], *client.getServer());
+ // Perform 4-way exchange and should obtain the reserved address.
+ ASSERT_NO_THROW_LOG(client.doDORA());
+ // Make sure that the server responded.
+ ASSERT_TRUE(client.getContext().response_);
+ Pkt4Ptr resp = client.getContext().response_;
+ // Make sure that the server has responded with DHCPACK.
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+ // Make sure that the client has got the lease for the reserved address.
+ ASSERT_EQ("10.0.0.9", client.config_.lease_.addr_.toText());
+
+ // Renew.
+ client.setState(Dhcp4Client::RENEWING);
+ // Set the unicast destination address to indicate that it is a renewal.
+ client.setDestAddress(IOAddress("10.0.0.1"));
+ // Disable relay.
+ client.useRelay(false);
+ ASSERT_NO_THROW_LOG(client.doRequest());
+ ASSERT_TRUE(client.getContext().response_);
+ resp = client.getContext().response_;
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+ ASSERT_EQ("10.0.0.9", client.config_.lease_.addr_.toText());
+}
+
+TEST_F(DORATest, stashAgentOptionsReservation) {
+ Dhcpv4SrvMTTestGuard guard(*this, false);
+ stashAgentOptionsReservation();
+}
+
+TEST_F(DORATest, stashAgentOptionsReservationMultiThreading) {
+ Dhcpv4SrvMTTestGuard guard(*this, true);
+ stashAgentOptionsReservation();
+}
+
+void
+DORATest::noStashAgentOptionsReservation() {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ // Use relay agent to make sure that the desired subnet is
+ // selected for our client.
+ client.useRelay(true, IOAddress("10.0.0.20"), IOAddress("10.0.0.21"));
+ // Specify client identifier.
+ client.includeClientId("01:11:22:33:44:55:66");
+ // Set the circuit id.
+ client.setCircuitId("charter950");
+
+ // Configure DHCP server.
+ configure(DORA_CONFIGS[23], *client.getServer());
+ // Perform 4-way exchange and should obtain the reserved address.
+ ASSERT_NO_THROW_LOG(client.doDORA());
+ // Make sure that the server responded.
+ ASSERT_TRUE(client.getContext().response_);
+ Pkt4Ptr resp = client.getContext().response_;
+ // Make sure that the server has responded with DHCPACK.
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+ // Make sure that the client has got the lease for the reserved address.
+ ASSERT_EQ("10.0.0.9", client.config_.lease_.addr_.toText());
+
+ // Renew.
+ client.setState(Dhcp4Client::RENEWING);
+ // Set the unicast destination address to indicate that it is a renewal.
+ client.setDestAddress(IOAddress("10.0.0.1"));
+ // Disable relay.
+ client.useRelay(false);
+ ASSERT_NO_THROW_LOG(client.doRequest());
+ ASSERT_TRUE(client.getContext().response_);
+ resp = client.getContext().response_;
+ // The client is not recognized so a NAK is returned.
+ ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
+}
+
+TEST_F(DORATest, noStashAgentOptionsReservation) {
+ Dhcpv4SrvMTTestGuard guard(*this, false);
+ noStashAgentOptionsReservation();
+}
+
+TEST_F(DORATest, noStashAgentOptionsReservationMultiThreading) {
+ Dhcpv4SrvMTTestGuard guard(*this, true);
+ noStashAgentOptionsReservation();
+}
+
/// @brief Checks the value of a statistic.
///
/// @param name name of statistic to check