Browse Source

[3947] Implemented test for acqusition of the address in Renew.

Marcin Siodelski 10 years ago
parent
commit
fc345a3a34

+ 3 - 10
src/bin/dhcp6/dhcp6_srv.cc

@@ -482,7 +482,7 @@ bool Dhcpv6Srv::run() {
         LOG_DEBUG(packet_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
             .arg(query->getLabel())
             .arg(query->getName())
-            .arg(query->getType())
+            .arg(static_cast<int>(query->getType()))
             .arg(query->getRemoteAddr())
             .arg(query->getLocalAddr())
             .arg(query->getIface());
@@ -1721,6 +1721,7 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
     ctx.ia_rsp_ = ia_rsp;
     ctx.hwaddr_ = orig_ctx.hwaddr_;
     ctx.host_ = orig_ctx.host_;
+    ctx.allow_new_leases_in_renewals_ = true;
 
     // Extract the addresses that the client is trying to obtain.
     OptionCollection addrs = ia->getOptions();
@@ -1746,15 +1747,6 @@ Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
     // we extend, cancel or otherwise deal with the leases.
     bool hints_present = !ctx.hints_.empty();
 
-    /// @todo: This was clarified in draft-ietf-dhc-dhcpv6-stateful-issues that
-    /// the server is allowed to assign new leases in both Renew and Rebind. For
-    /// now, we only support it in Renew, because it breaks a lot of Rebind
-    /// unit-tests. Ultimately, whether we allow it or not, should be exposed
-    /// as configurable policy. See ticket #3717.
-    if (query->getType() == DHCPV6_RENEW) {
-        ctx.allow_new_leases_in_renewals_ = true;
-    }
-
     Lease6Collection leases = alloc_engine_->renewLeases6(ctx);
 
     // Ok, now we have the leases extended. We have:
@@ -1897,6 +1889,7 @@ Dhcpv6Srv::extendIA_PD(const Pkt6Ptr& query,
     ctx.ia_rsp_ = ia_rsp;
     ctx.hwaddr_ = orig_ctx.hwaddr_;
     ctx.host_ = orig_ctx.host_;
+    ctx.allow_new_leases_in_renewals_ = true;
 
     // Extract prefixes that the client is trying to renew.
     OptionCollection addrs = ia->getOptions();

+ 20 - 9
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -80,8 +80,6 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
     // Let's try to get a MAC
     HWAddrPtr hwaddr = reply->getMAC(HWAddr::HWADDR_SOURCE_ANY);
 
-    // Set the global status code to default: success and not received.
-    config_.resetGlobalStatusCode();
     for (Opts::const_iterator opt = opts.begin(); opt != opts.end(); ++opt) {
         Option6IAPtr ia = boost::dynamic_pointer_cast<Option6IA>(opt->second);
         if (!ia) {
@@ -94,7 +92,9 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
         for (Opts::const_iterator iter_ia_opt = ia_opts.begin();
              iter_ia_opt != ia_opts.end(); ++iter_ia_opt) {
             OptionPtr ia_opt = iter_ia_opt->second;
-            LeaseInfo lease_info;
+            LeaseInfo lease_info(ia->getType());
+            lease_info.lease_.iaid_ = ia->getIAID();
+
             switch (ia_opt->getType()) {
             case D6O_IAADDR:
                 {
@@ -107,7 +107,6 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
                         // lease and keep IAID around.
                         lease_info.lease_ = Lease6();
                         lease_info.lease_.type_ = Lease::TYPE_NA;
-                        lease_info.lease_.iaid_ = ia->getIAID();
                         break;
                     }
 
@@ -132,7 +131,6 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
                         // lease and keep IAID around.
                         lease_info.lease_ = Lease6();
                         lease_info.lease_.type_ = Lease::TYPE_PD;
-                        lease_info.lease_.iaid_ = ia->getIAID();
                         break;
                     }
                     lease_info.lease_ = Lease6(Lease::TYPE_PD,
@@ -193,12 +191,15 @@ Dhcp6Client::applyLease(const LeaseInfo& lease_info) {
             config_.leases_[i] = lease_info;
             return;
 
-        } else if (lease_info.lease_.addr_ == asiolink::IOAddress("::")) {
+        } else if ((existing_lease.iaid_ == lease_info.lease_.iaid_) &&
+                   (lease_info.lease_.addr_ == asiolink::IOAddress("::"))) {
+            config_.leases_[i] = lease_info;
             config_.leases_[i].status_code_ = lease_info.status_code_;
             return;
 
         }
     }
+
     // It is a new lease. Add it.
     config_.leases_.push_back(lease_info);
 }
@@ -286,6 +287,11 @@ Dhcp6Client::copyIAsFromLeases(const Pkt6Ptr& dest) const {
     for (std::set<uint32_t>::const_iterator iaid = iaids.begin();
          iaid != iaids.end(); ++iaid) {
         std::vector<Lease6> leases = getLeasesByIAID(*iaid);
+        // Only a valid lease should be included. If we have received an
+        // error status code, it should not be copied.
+        if (leases[0].valid_lft_ == 0) {
+            continue;
+        }
         Option6IAPtr opt(new Option6IA(leases[0].type_ == Lease::TYPE_NA ?
                                        D6O_IA_NA : D6O_IA_PD, *iaid));
         opt->setT1(leases[0].t1_);
@@ -370,6 +376,7 @@ Dhcp6Client::doSolicit() {
     // let's apply received configuration.
     if (use_rapid_commit_ && context_.response_ &&
         context_.response_->getType() == DHCPV6_REPLY) {
+        config_.clear();
         applyRcvdConfiguration(context_.response_);
     }
 }
@@ -396,6 +403,7 @@ Dhcp6Client::doRequest() {
 
     // Apply new configuration only if the server has responded.
     if (context_.response_) {
+        config_.clear();
         applyRcvdConfiguration(context_.response_);
     }
 }
@@ -444,6 +452,7 @@ Dhcp6Client::doRenew() {
     context_.response_ = receiveOneMsg();
     // Apply configuration only if the server has responded.
     if (context_.response_) {
+        config_.clear();
         applyRcvdConfiguration(context_.response_);
     }
 }
@@ -465,6 +474,7 @@ Dhcp6Client::doRebind() {
     context_.response_ = receiveOneMsg();
     // Apply configuration only if the server has responded.
     if (context_.response_) {
+        config_.clear();
         applyRcvdConfiguration(context_.response_);
     }
 }
@@ -478,6 +488,7 @@ Dhcp6Client::doConfirm() {
     // Set the global status code to default: success and not received.
     config_.resetGlobalStatusCode();
     if (context_.response_) {
+        config_.resetGlobalStatusCode();
         applyRcvdConfiguration(context_.response_);
     }
 }
@@ -543,13 +554,13 @@ Dhcp6Client::getLeasesByIAID(const uint32_t iaid) const {
     return (leases);
 }
 
-std::vector<Lease6>
+std::vector<Dhcp6Client::LeaseInfo>
 Dhcp6Client::getLeasesByType(const Lease::Type& lease_type) const {
-    std::vector<Lease6> leases;
+    std::vector<Dhcp6Client::LeaseInfo> leases;
     LeaseInfo lease_info;
     BOOST_FOREACH(lease_info, config_.leases_) {
         if (lease_info.lease_.type_ == lease_type) {
-            leases.push_back(lease_info.lease_);
+            leases.push_back(lease_info);
         }
     }
     return (leases);

+ 10 - 1
src/bin/dhcp6/tests/dhcp6_client.h

@@ -70,6 +70,15 @@ public:
         /// @brief Default constructor for the structure.
         LeaseInfo() :
             lease_(), status_code_(0) { }
+
+        /// @brief Constructor which sets the lease type.
+        ///
+        /// @param lease_type One of the D6O_IA_NA or D6O_IA_PD.
+        LeaseInfo(const uint16_t lease_type) :
+            lease_(), status_code_(0) {
+            lease_.type_ = lease_type == D6O_IA_NA ? Lease::TYPE_NA :
+                Lease::TYPE_PD;
+        }
     };
 
     /// @brief Holds the current client configuration obtained from the
@@ -317,7 +326,7 @@ public:
     /// @param type Lease type: D6O_IA_NA or D6O_IA_PD.
     ///
     /// @return Vector containing leases of the specified type.
-    std::vector<Lease6> getLeasesByType(const Lease::Type& lease_type) const;
+    std::vector<LeaseInfo> getLeasesByType(const Lease::Type& lease_type) const;
 
     /// @brief Returns the value of the global status code for the last
     /// transaction.

+ 89 - 13
src/bin/dhcp6/tests/renew_unittest.cc

@@ -32,17 +32,17 @@ namespace {
 ///
 /// - Configuration 0:
 ///   - only addresses (no prefixes)
-///   - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::64
-///   - 1 subnet for eth0 and 1 subnet for eth1
+///   - 1 subnet with 2001:db8:1::/64 pool
 ///
 /// - Configuration 1:
-///   - similar to Configuration 0 but different subnets
-///   - pools configured: 2001:db8:3::/64 and 2001:db8:4::/64
+///   - only prefixes (no addresses)
+///   - prefix pool: 3000::/72
 ///
 /// - Configuration 2:
-///   - similar to Configuration 0 and Configuration 1
-///   - pools configured: 3000:1::/64 and 3000:2::/64
-///   - this specific configuration is used by tests using relays
+///   - addresses and prefixes
+///   - 1 subnet with one address pool and one prefix pool
+///   - address pool: 2001:db8:1::/64
+///   - prefix pool: 3000::/72
 ///
 const char* RENEW_CONFIGS[] = {
 // Configuration 0
@@ -68,6 +68,25 @@ const char* RENEW_CONFIGS[] = {
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"subnet6\": [ { "
+        "    \"pd-pools\": ["
+        "        { \"prefix\": \"3000::\", "
+        "          \"prefix-len\": 72, "
+        "          \"delegated-len\": 80"
+        "        } ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface-id\": \"\","
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 }",
+
+// Configuration 2
+    "{ \"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
         "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
         "    \"pd-pools\": ["
         "        { \"prefix\": \"3000::\", "
@@ -112,29 +131,86 @@ TEST_F(RenewTest, requestPrefixInRenew) {
     client.fastFwdTime(1000);
 
     // Make sure that the client has acquired NA lease.
-    std::vector<Lease6> leases_client_na = client.getLeasesByType(Lease::TYPE_NA);
+    std::vector<Dhcp6Client::LeaseInfo> 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());
+    std::vector<Dhcp6Client::LeaseInfo> leases_client_pd =
+        client.getLeasesByType(Lease::TYPE_PD);
+    ASSERT_EQ(1, leases_client_pd.size());
+    ASSERT_EQ(STATUS_NoPrefixAvail, leases_client_pd[0].status_code_);
 
     // Reconfigure the server to use both NA and PD pools.
-    configure(RENEW_CONFIGS[1], *client.getServer());
+    configure(RENEW_CONFIGS[2], *client.getServer());
 
     // Send Renew message to the server, including IA_NA and requesting IA_PD.
     ASSERT_NO_THROW(client.doRenew());
 
     // Make sure that the client has acquired NA lease.
-    std::vector<Lease6> leases_client_na_renewed = client.getLeasesByType(Lease::TYPE_NA);
+    std::vector<Dhcp6Client::LeaseInfo> leases_client_na_renewed =
+        client.getLeasesByType(Lease::TYPE_NA);
     ASSERT_EQ(1, leases_client_na_renewed.size());
+    EXPECT_EQ(STATUS_Success, leases_client_na_renewed[0].status_code_);
 
     // The lease should have been renewed.
-    EXPECT_EQ(1000, leases_client_na_renewed[0].cltt_ - leases_client_na[0].cltt_);
+    EXPECT_EQ(1000, leases_client_na_renewed[0].lease_.cltt_ -
+              leases_client_na[0].lease_.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, leases_client_pd[0].status_code_);
+}
+
+// This test verifies that the client can request the prefix delegation
+// while it is renewing an address lease.
+TEST_F(RenewTest, requestAddressInRenew) {
+    Dhcp6Client client;
+
+    // Configure client to request IA_NA and IA_PD.
+    client.useNA();
+    client.usePD();
+
+    // Configure the server with PD pools only.
+    ASSERT_NO_THROW(configure(RENEW_CONFIGS[1], *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 PD lease.
+    std::vector<Dhcp6Client::LeaseInfo> leases_client_pd =
+        client.getLeasesByType(Lease::TYPE_PD);
+    ASSERT_EQ(1, leases_client_pd.size());
+    EXPECT_EQ(STATUS_Success, leases_client_pd[0].status_code_);
+
+    // The client should not acquire a NA lease.
+    std::vector<Dhcp6Client::LeaseInfo> leases_client_na =
+        client.getLeasesByType(Lease::TYPE_NA);
+    ASSERT_EQ(1, leases_client_na.size());
+    ASSERT_EQ(STATUS_NoAddrsAvail, leases_client_na[0].status_code_);
+
+    // Reconfigure the server to use both NA and PD pools.
+    configure(RENEW_CONFIGS[2], *client.getServer());
+
+    // Send Renew message to the server, including IA_PD and requesting IA_NA.
+    ASSERT_NO_THROW(client.doRenew());
+
+    // Make sure that the client has renewed PD lease.
+    std::vector<Dhcp6Client::LeaseInfo> leases_client_pd_renewed =
+        client.getLeasesByType(Lease::TYPE_PD);
+    ASSERT_EQ(1, leases_client_pd_renewed.size());
+    EXPECT_EQ(STATUS_Success, leases_client_pd_renewed[0].status_code_);
+    EXPECT_EQ(1000, leases_client_pd_renewed[0].lease_.cltt_ -
+              leases_client_pd[0].lease_.cltt_);
+
+    // The client should now also acquire a NA lease.
+    leases_client_na = client.getLeasesByType(Lease::TYPE_NA);
+    ASSERT_EQ(1, leases_client_na.size());
+    EXPECT_EQ(STATUS_Success, leases_client_na[0].status_code_);
 }