Browse Source

[3947] DHCPv6 server returns NoPrefixAvail on Rebind now.

Marcin Siodelski 9 years ago
parent
commit
c8fd96a6f2

+ 21 - 21
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."));
         }
     }
 

+ 104 - 0
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<Lease6> 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<Lease6> 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<Lease6> 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

+ 6 - 0
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());