From: Marcin Siodelski Date: Sat, 18 Jul 2015 11:39:26 +0000 (+0200) Subject: [3947] DHCPv6 server returns NoPrefixAvail on Rebind now. X-Git-Tag: trac3238_base~6^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8fd96a6f2c04d6828e810f1fa63a1768d0fd529;p=thirdparty%2Fkea.git [3947] DHCPv6 server returns NoPrefixAvail on Rebind now. --- diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index da58f13d47..35202c99ad 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -1961,12 +1961,11 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, // All is left is to insert the status code. if (leases.empty()) { - if (query->getType() == DHCPV6_RENEW) { - - // We did not assign anything. If client has sent something, then - // the status code is NoBinding, if he sent an empty IA_NA, then it's - // NoAddrsAvailable - if (hints_present) { + // We did not assign anything. If client has sent something, then + // the status code is NoBinding, if he sent an empty IA_PD, then it's + // NoAddrsAvailable + if (hints_present && !subnet->getAllocLeasesOnRenew()) { + if (query->getType() == DHCPV6_RENEW) { // Insert status code NoBinding to indicate that the lease does not // exist for this client. ia_rsp->addOption(createStatusCode(*query, *ia_rsp, @@ -1974,23 +1973,24 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query, "Sorry, no known PD leases for" " this duid/iaid/subnet.")); } else { - ia_rsp->addOption(createStatusCode(*query, *ia_rsp, - STATUS_NoPrefixAvail, - "Sorry, no prefixes could be" - " assigned at this time.")); + // Per RFC3633, section 12.2, if there is no binding and we are + // processing Rebind, the message has to be discarded (assuming that + // the server doesn't know if the prefix in the IA_PD option is + // appropriate for the client's link). The exception being thrown + // here should propagate to the main loop and cause the message to + // be discarded. + isc_throw(DHCPv6DiscardMessageError, "no binding found for the" + " DUID=" << duid->toText() << ", IAID=" + << ia->getIAID() << ", subnet=" + << subnet->toText() << " when processing a Rebind" + " message with IA_PD option"); } + } else { - // Per RFC3633, section 12.2, if there is no binding and we are - // processing Rebind, the message has to be discarded (assuming that - // the server doesn't know if the prefix in the IA_PD option is - // appropriate for the client's link). The exception being thrown - // here should propagate to the main loop and cause the message to - // be discarded. - isc_throw(DHCPv6DiscardMessageError, "no binding found for the" - " DUID=" << duid->toText() << ", IAID=" - << ia->getIAID() << ", subnet=" - << subnet->toText() << " when processing a Rebind" - " message with IA_PD option"); + ia_rsp->addOption(createStatusCode(*query, *ia_rsp, + STATUS_NoPrefixAvail, + "Sorry, no prefixes could be" + " assigned at this time.")); } } diff --git a/src/bin/dhcp6/tests/rebind_unittest.cc b/src/bin/dhcp6/tests/rebind_unittest.cc index 83ccf8f86b..7c4c6ca2e2 100644 --- a/src/bin/dhcp6/tests/rebind_unittest.cc +++ b/src/bin/dhcp6/tests/rebind_unittest.cc @@ -62,6 +62,18 @@ namespace { /// - 2 prefix pools: 2001:db8:3::/72 and 2001:db8:4::/72 /// - delegated length /80 /// - this specific configuration is used by tests which don't use relays +/// +/// - Configuration 6: +/// - only addresses (no prefixes) +/// - 1 subnet with the 2001:db8:1::/64 prefix +/// - 'new-leases-on-renew' enabled +/// +/// - Configuration 7: +/// - addresses and prefixes +/// - address pool: 2001:db8:1::/64 +/// - prefix pool: 3000::/72 +/// - 'new-leases-on-renew' enabled +/// const char* REBIND_CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -211,6 +223,42 @@ const char* REBIND_CONFIGS[] = { " } ]," "\"valid-lifetime\": 4000 }", +// Configuration 6 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"new-leases-on-renew\": True," + "\"subnet6\": [ { " + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," + " \"subnet\": \"2001:db8:1::/48\", " + " \"interface-id\": \"\"," + " \"interface\": \"eth0\"" + " } ]," + "\"valid-lifetime\": 4000 }", + +// Configuration 7 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ { " + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," + " \"pd-pools\": [" + " { \"prefix\": \"3000::\", " + " \"prefix-len\": 72, " + " \"delegated-len\": 80" + " } ]," + " \"subnet\": \"2001:db8:1::/48\", " + " \"interface-id\": \"\"," + " \"interface\": \"eth0\"" + " } ]," + "\"valid-lifetime\": 4000 }" + }; /// @brief Test fixture class for testing Rebind. @@ -727,4 +775,60 @@ TEST_F(RebindTest, relayedUnicast) { EXPECT_TRUE(lease_server2); } +// This test verifies that the client can request the prefix delegation +// while it is rebinding an address lease. +TEST_F(RebindTest, requestPrefixInRebind) { + Dhcp6Client client; + + // Configure client to request IA_NA and IA_PD. + client.useNA(); + client.usePD(); + + // Configure the server with NA pools only. + ASSERT_NO_THROW(configure(REBIND_CONFIGS[6], *client.getServer())); + + // Perform 4-way exchange. + ASSERT_NO_THROW(client.doSARR()); + + // Simulate aging of leases. + client.fastFwdTime(1000); + + // Make sure that the client has acquired NA lease. + std::vector leases_client_na = client.getLeasesByType(Lease::TYPE_NA); + ASSERT_EQ(1, leases_client_na.size()); + + // The client should not acquire a PD lease. + std::vector leases_client_pd = client.getLeasesByType(Lease::TYPE_PD); + ASSERT_TRUE(leases_client_pd.empty()); + ASSERT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(5678)); + + // Send Rebind message to the server, including IA_NA and requesting IA_PD. + ASSERT_NO_THROW(client.doRebind()); + ASSERT_TRUE(client.getContext().response_); + leases_client_pd = client.getLeasesByType(Lease::TYPE_PD); + ASSERT_TRUE(leases_client_pd.empty()); + ASSERT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(5678)); + + // Reconfigure the server to use both NA and PD pools. + configure(REBIND_CONFIGS[7], *client.getServer()); + + // Send Rebind message to the server, including IA_NA and requesting IA_PD. + ASSERT_NO_THROW(client.doRebind()); + + // Make sure that the client has acquired NA lease. + std::vector leases_client_na_rebound = + client.getLeasesByType(Lease::TYPE_NA); + ASSERT_EQ(1, leases_client_na_rebound.size()); + EXPECT_EQ(STATUS_Success, client.getStatusCode(1234)); + + // The lease should have been rebound. + EXPECT_EQ(1000, leases_client_na_rebound[0].cltt_ - leases_client_na[0].cltt_); + + // The client should now also acquire a PD lease. + leases_client_pd = client.getLeasesByType(Lease::TYPE_PD); + ASSERT_EQ(1, leases_client_pd.size()); + EXPECT_EQ(STATUS_Success, client.getStatusCode(5678)); +} + + } // end of anonymous namespace diff --git a/src/bin/dhcp6/tests/renew_unittest.cc b/src/bin/dhcp6/tests/renew_unittest.cc index 3691fc95c3..d4143be514 100644 --- a/src/bin/dhcp6/tests/renew_unittest.cc +++ b/src/bin/dhcp6/tests/renew_unittest.cc @@ -139,6 +139,12 @@ TEST_F(RenewTest, requestPrefixInRenew) { ASSERT_TRUE(leases_client_pd.empty()); ASSERT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(5678)); + // Send Renew message to the server, including IA_NA and requesting IA_PD. + ASSERT_NO_THROW(client.doRenew()); + leases_client_pd = client.getLeasesByType(Lease::TYPE_PD); + ASSERT_TRUE(leases_client_pd.empty()); + ASSERT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(5678)); + // Reconfigure the server to use both NA and PD pools. configure(RENEW_CONFIGS[2], *client.getServer());