]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#226] Checkpoint v6 code
authorFrancis Dupont <fdupont@isc.org>
Wed, 13 Aug 2025 09:32:03 +0000 (11:32 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 20 Aug 2025 15:39:16 +0000 (17:39 +0200)
src/bin/dhcp6/tests/flq_unittest.cc [new file with mode: 0644]
src/bin/dhcp6/tests/meson.build
src/lib/dhcpsrv/alloc_engine.cc

diff --git a/src/bin/dhcp6/tests/flq_unittest.cc b/src/bin/dhcp6/tests/flq_unittest.cc
new file mode 100644 (file)
index 0000000..798634f
--- /dev/null
@@ -0,0 +1,436 @@
+// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <asiolink/io_address.h>
+#include <dhcp/testutils/iface_mgr_test_config.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <dhcp6/tests/dhcp6_client.h>
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+
+namespace {
+
+/// @brief JSON configuration
+std::string FLQ_CONFIG =
+    "{ \"interfaces-config\": {"
+    "      \"interfaces\": [ \"*\" ]"
+    "},"
+    "\"min-preferred-lifetime\": 100,"
+    "\"preferred-lifetime\": 200,"
+    "\"max-preferred-lifetime\": 300,"
+    "\"min-valid-lifetime\": 400,"
+    "\"valid-lifetime\": 500,"
+    "\"max-valid-lifetime\": 600,"
+    "\"rebind-timer\": 250,"
+    "\"renew-timer\": 250,"
+    "\"adaptive-lease-time-threshold\": .5,"
+    "\"cache-threshold\": 0.,"
+    "\"subnet6\": [ { "
+    "    \"subnet\": \"3000::/32\", "
+    "    \"id\": 1,"
+    "    \"interface\": \"eth0\","
+    "    \"pd-pools\": [ {"
+    "        \"prefix\": \"2001:db8:1::\","
+    "        \"prefix-len\": 48,"
+    "        \"delegated-len\": 51"
+    "    } ],"
+    "    \"pd-allocator\": \"flq\""
+    " } ]"
+    "}";
+
+/// @brief Test fixture class for testing FLQ / adaptive-lease-time-threshold.
+class FLQTest : public Dhcpv6SrvTest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Sets up fake interfaces.
+    FLQTest() : Dhcpv6SrvTest(), iface_mgr_test_config_(true) {
+    }
+
+    /// @brief Creates a DHCPv6 lease for an address and MAC address.
+    ///
+    /// @param address Lease address.
+    /// @param duid_seed a seed from which the DUID is generated.
+    /// @return Created lease pointer.
+    Lease6Ptr
+    createLease6(const IOAddress& address, uint64_t duid_seed) const {
+        vector<uint8_t> duid_vec(sizeof(duid_seed));
+        for (unsigned i = 0; i < sizeof(duid_seed); ++i) {
+            duid_vec[i] = (duid_seed >> i) & 0xFF;
+        }
+        DuidPtr duid(new DUID(duid_vec));
+        Lease6Ptr lease(new Lease6(Lease::TYPE_PD, address, duid, 1,
+                                   800, 1200, 1, HWAddrPtr(), 51));
+        return (lease);
+    }
+
+    /// @brief Interface Manager's fake configuration control.
+    IfaceMgrTestConfig iface_mgr_test_config_;
+};
+
+// Test allocation with empty pool.
+TEST_F(FLQTest, empty) {
+    Dhcp6Client client(srv_);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Perform 4-way exchange with the server requesting the last prefix.
+    client.requestPrefix(1, 51, IOAddress("2001:db8:1:e000::"));
+    ASSERT_NO_THROW(client.doSARR());
+
+    // Server should have assigned a prefix.
+    ASSERT_EQ(1, client.getLeaseNum());
+    Lease6Ptr lease = checkLease(client.getLease(0));
+    ASSERT_TRUE(lease);
+
+    // Make sure that the client has got the requested prefix.
+    EXPECT_EQ("2001:db8:1:e000::", lease->addr_.toText());
+    EXPECT_EQ(51, lease->prefixlen_);
+
+    // Preferred lifetime should be the config preferred-lifetime (200).
+    EXPECT_EQ(200, lease->preferred_lft_);
+
+    // Valid lifetime should be the config valid-lifetime (500).
+    EXPECT_EQ(500, lease->valid_lft_);
+}
+
+// Test allocation with almost full pool.
+TEST_F(FLQTest, last) {
+    Dhcp6Client client(srv_);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Create leases for the first prefixes.
+    auto& lease_mgr = LeaseMgrFactory::instance();
+    auto lease0 = createLease6(IOAddress("2001:db8:1::"), 1);
+    EXPECT_TRUE(lease_mgr.addLease(lease0));
+    auto lease1 = createLease6(IOAddress("2001:db8:1:2000::"), 2);
+    EXPECT_TRUE(lease_mgr.addLease(lease1));
+    auto lease2 = createLease6(IOAddress("2001:db8:1:4000::"), 3);
+    EXPECT_TRUE(lease_mgr.addLease(lease2));
+    auto lease3 = createLease6(IOAddress("2001:db8:1:6000::"), 4);
+    EXPECT_TRUE(lease_mgr.addLease(lease3));
+    auto lease4 = createLease6(IOAddress("2001:db8:1:8000::"), 5);
+    EXPECT_TRUE(lease_mgr.addLease(lease4));
+    auto lease5 = createLease6(IOAddress("2001:db8:1:a000::"), 6);
+    EXPECT_TRUE(lease_mgr.addLease(lease5));
+    auto lease6 = createLease6(IOAddress("2001:db8:1:c000::"), 7);
+    EXPECT_TRUE(lease_mgr.addLease(lease6));
+
+    // Perform 4-way exchange with the server.
+    client.requestPrefix();
+    ASSERT_NO_THROW(client.doSARR());
+
+    // Server should have assigned a prefix.
+    ASSERT_EQ(1, client.getLeaseNum());
+    Lease6Ptr lease = checkLease(client.getLease(0));
+    ASSERT_TRUE(lease);
+
+    // Make sure that the client has got the requested prefix.
+    EXPECT_EQ("2001:db8:1:e000::", lease->addr_.toText());
+    EXPECT_EQ(51, lease->prefixlen_);
+
+    // Preferred lifetime should be the config min-preferred-lifetime (100).
+    EXPECT_EQ(100, lease->preferred_lft_);
+
+    // Valid lifetime should be the config min-valid-lifetime (400).
+    EXPECT_EQ(400, lease->valid_lft_);
+}
+
+// Test allocation with an expired lease.
+TEST_F(FLQTest, expired) {
+    Dhcp6Client client(srv_);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Create leases for the first prefixes.
+    auto& lease_mgr = LeaseMgrFactory::instance();
+    auto lease0 = createLease6(IOAddress("2001:db8:1::"), 1);
+    EXPECT_TRUE(lease_mgr.addLease(lease0));
+    auto lease1 = createLease6(IOAddress("2001:db8:1:2000::"), 2);
+    EXPECT_TRUE(lease_mgr.addLease(lease1));
+    auto lease2 = createLease6(IOAddress("2001:db8:1:4000::"), 3);
+    EXPECT_TRUE(lease_mgr.addLease(lease2));
+    auto lease3 = createLease6(IOAddress("2001:db8:1:6000::"), 4);
+    EXPECT_TRUE(lease_mgr.addLease(lease3));
+    auto lease4 = createLease6(IOAddress("2001:db8:1:8000::"), 5);
+    EXPECT_TRUE(lease_mgr.addLease(lease4));
+    auto lease5 = createLease6(IOAddress("2001:db8:1:a000::"), 6);
+    EXPECT_TRUE(lease_mgr.addLease(lease5));
+    auto lease6 = createLease6(IOAddress("2001:db8:1:c000::"), 7);
+    EXPECT_TRUE(lease_mgr.addLease(lease6));
+    auto lease7 = createLease6(IOAddress("2001:db8:1:e000::"), 8);
+    // Expired lease.
+    lease7->cltt_ -= 10000;
+    lease7->current_cltt_ -= 10000;
+    ASSERT_TRUE(lease7->expired());
+    EXPECT_TRUE(lease_mgr.addLease(lease7));
+
+    // Perform 4-way exchange with the server.
+    client.requestPrefix();
+    ASSERT_NO_THROW(client.doSARR());
+
+    // Server should have assigned a prefix.
+    ASSERT_EQ(1, client.getLeaseNum());
+    Lease6Ptr lease = checkLease(client.getLease(0));
+    ASSERT_TRUE(lease);
+
+    // Make sure that the client has got the requested prefix.
+    EXPECT_EQ("2001:db8:1:e000::", lease->addr_.toText());
+    EXPECT_EQ(51, lease->prefixlen_);
+
+    // Preferred lifetime should be the config min-preferred-lifetime (100).
+    EXPECT_EQ(100, lease->preferred_lft_);
+
+    // Valid lifetime should be the config min-valid-lifetime (400).
+    EXPECT_EQ(400, lease->valid_lft_);
+}
+
+// Test allocation with a reclaimed lease.
+TEST_F(FLQTest, reclaimed) {
+    Dhcp6Client client(srv_);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Create leases for the first prefixes.
+    auto& lease_mgr = LeaseMgrFactory::instance();
+    auto lease0 = createLease6(IOAddress("2001:db8:1::"), 1);
+    EXPECT_TRUE(lease_mgr.addLease(lease0));
+    auto lease1 = createLease6(IOAddress("2001:db8:1:2000::"), 2);
+    EXPECT_TRUE(lease_mgr.addLease(lease1));
+    auto lease2 = createLease6(IOAddress("2001:db8:1:4000::"), 3);
+    EXPECT_TRUE(lease_mgr.addLease(lease2));
+    auto lease3 = createLease6(IOAddress("2001:db8:1:6000::"), 4);
+    EXPECT_TRUE(lease_mgr.addLease(lease3));
+    auto lease4 = createLease6(IOAddress("2001:db8:1:8000::"), 5);
+    EXPECT_TRUE(lease_mgr.addLease(lease4));
+    auto lease5 = createLease6(IOAddress("2001:db8:1:a000::"), 6);
+    EXPECT_TRUE(lease_mgr.addLease(lease5));
+    auto lease6 = createLease6(IOAddress("2001:db8:1:c000::"), 7);
+    EXPECT_TRUE(lease_mgr.addLease(lease6));
+    auto lease7 = createLease6(IOAddress("2001:db8:1:e000::"), 8);
+    // Reclaimed lease.
+    lease7->cltt_ -= 10000;
+    lease7->current_cltt_ -= 10000;
+    ASSERT_TRUE(lease7->expired());
+    lease7->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+    EXPECT_TRUE(lease_mgr.addLease(lease7));
+
+    // Perform 4-way exchange with the server.
+    client.requestPrefix();
+    ASSERT_NO_THROW(client.doSARR());
+
+    // Server should have assigned a prefix.
+    ASSERT_EQ(1, client.getLeaseNum());
+    Lease6Ptr lease = checkLease(client.getLease(0));
+    ASSERT_TRUE(lease);
+
+    // Make sure that the client has got the requested prefix.
+    EXPECT_EQ("2001:db8:1:e000::", lease->addr_.toText());
+    EXPECT_EQ(51, lease->prefixlen_);
+
+    // Preferred lifetime should be the config min-preferred-lifetime (100).
+    EXPECT_EQ(100, lease->preferred_lft_);
+
+    // Valid lifetime should be the config min-valid-lifetime (400).
+    EXPECT_EQ(400, lease->valid_lft_);
+}
+#if 0
+// Test renewal with almost empty pool.
+TEST_F(FLQTest, renew) {
+    Dhcp6Client client(srv_, Dhcp6Client::SELECTING);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Obtain a lease from the server using the 4-way exchange.
+    boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
+    ASSERT_NO_THROW(client.doDORA(hint));
+
+    // Make sure that the server responded.
+    Pkt6Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+
+    // 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 requested address.
+    EXPECT_EQ(*hint, resp->getYiaddr());
+
+    // Valid lifetime should be the valid-lifetime parameter value (200).
+    OptionUint32Ptr opt = boost::dynamic_pointer_cast<
+        OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
+    ASSERT_TRUE(opt);
+    EXPECT_EQ(200, opt->getValue());
+
+    // Age the lease.
+    auto& lease_mgr = LeaseMgrFactory::instance();
+    Lease6Ptr lease = lease_mgr.getLease6(*hint);
+    ASSERT_TRUE(lease);
+    lease->cltt_ -= 150;
+    lease->current_cltt_ -= 150;
+    EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
+
+    // Let's transition the client to Renewing state.
+    client.setState(Dhcp6Client::RENEWING);
+
+    // Set the unicast destination address to indicate that it is a renewal.
+    client.setDestAddress(IOAddress("10.0.0.1"));
+    ASSERT_NO_THROW(client.doRequest());
+
+    // Make sure that renewal was ACKed.
+    resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+    // Make sure that the client renewed the requested address.
+    EXPECT_EQ(*hint, resp->getYiaddr());
+
+    // Valid lifetime should be the valid-lifetime parameter value (200).
+    opt = boost::dynamic_pointer_cast<OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
+    ASSERT_TRUE(opt);
+    EXPECT_EQ(200, opt->getValue());
+}
+
+// Test renewal with full pool.
+TEST_F(FLQTest, renewFull) {
+    Dhcp6Client client(srv_, Dhcp6Client::SELECTING);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Obtain a lease from the server using the 4-way exchange.
+    boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
+    ASSERT_NO_THROW(client.doDORA(hint));
+
+    // Make sure that the server responded.
+    Pkt6Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+
+    // 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 requested address.
+    EXPECT_EQ(*hint, resp->getYiaddr());
+
+    // Valid lifetime should be the valid-lifetime parameter value (200).
+    OptionUint32Ptr opt = boost::dynamic_pointer_cast<
+        OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
+    ASSERT_TRUE(opt);
+    EXPECT_EQ(200, opt->getValue());
+
+    // Age the lease.
+    auto& lease_mgr = LeaseMgrFactory::instance();
+    Lease6Ptr lease = lease_mgr.getLease6(*hint);
+    ASSERT_TRUE(lease);
+    lease->cltt_ -= 150;
+    lease->current_cltt_ -= 150;
+    EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
+
+    // Create leases for the first addresses.
+    auto lease1 = createLease6(IOAddress("10.0.0.11"), 1);
+    EXPECT_TRUE(lease_mgr.addLease(lease1));
+    auto lease2 = createLease6(IOAddress("10.0.0.12"), 2);
+    EXPECT_TRUE(lease_mgr.addLease(lease2));
+    auto lease3 = createLease6(IOAddress("10.0.0.13"), 3);
+    EXPECT_TRUE(lease_mgr.addLease(lease3));
+
+    // Let's transition the client to Renewing state.
+    client.setState(Dhcp6Client::RENEWING);
+
+    // Set the unicast destination address to indicate that it is a renewal.
+    client.setDestAddress(IOAddress("10.0.0.1"));
+    ASSERT_NO_THROW(client.doRequest());
+
+    // Make sure that renewal was ACKed.
+    resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+    // Make sure that the client renewed the requested address.
+    EXPECT_EQ(*hint, resp->getYiaddr());
+
+    // Valid lifetime should be the min-valid-lifetime parameter value (100).
+    opt = boost::dynamic_pointer_cast<OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
+    ASSERT_TRUE(opt);
+    EXPECT_EQ(100, opt->getValue());
+}
+
+// Test renewal with full pool but remaining lifetime greater than minimal.
+TEST_F(FLQTest, renewRemaining) {
+    Dhcp6Client client(srv_, Dhcp6Client::SELECTING);
+
+    // Configure DHCP server.
+    configure(FLQ_CONFIG, *client.getServer());
+
+    // Obtain a lease from the server using the 4-way exchange.
+    boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
+    ASSERT_NO_THROW(client.doDORA(hint));
+
+    // Make sure that the server responded.
+    Pkt6Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+
+    // 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 requested address.
+    EXPECT_EQ(*hint, resp->getYiaddr());
+
+    // Valid lifetime should be the valid-lifetime parameter value (200).
+    OptionUint32Ptr opt = boost::dynamic_pointer_cast<
+        OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
+    ASSERT_TRUE(opt);
+    EXPECT_EQ(200, opt->getValue());
+
+    // Age the lease but only by 50 seconds.
+    auto& lease_mgr = LeaseMgrFactory::instance();
+    Lease6Ptr lease = lease_mgr.getLease6(*hint);
+    ASSERT_TRUE(lease);
+    lease->cltt_ -= 50;
+    lease->current_cltt_ -= 50;
+    EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
+
+    // Create leases for the first addresses.
+    auto lease1 = createLease6(IOAddress("10.0.0.11"), 1);
+    EXPECT_TRUE(lease_mgr.addLease(lease1));
+    auto lease2 = createLease6(IOAddress("10.0.0.12"), 2);
+    EXPECT_TRUE(lease_mgr.addLease(lease2));
+    auto lease3 = createLease6(IOAddress("10.0.0.13"), 3);
+    EXPECT_TRUE(lease_mgr.addLease(lease3));
+
+    // Let's transition the client to Renewing state.
+    client.setState(Dhcp6Client::RENEWING);
+
+    // Set the unicast destination address to indicate that it is a renewal.
+    client.setDestAddress(IOAddress("10.0.0.1"));
+    ASSERT_NO_THROW(client.doRequest());
+
+    // Make sure that renewal was ACKed.
+    resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+    // Make sure that the client renewed the requested address.
+    EXPECT_EQ(*hint, resp->getYiaddr());
+
+    // Valid lifetime should be the remaining lifetime so ~150 seconds.
+    opt = boost::dynamic_pointer_cast<OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
+    ASSERT_TRUE(opt);
+    EXPECT_NEAR(150, opt->getValue(), 2);
+}
+#endif
+
+}
index 56cb1a9c8da3d5d6f900ed7ee51c6d44c1a44abb..fb84a2fe635ea27ef2707b48f3dc47dea36d2ba8 100644 (file)
@@ -127,6 +127,7 @@ kea_dhcp6_tests = executable(
     'dhcp6_test_utils.cc',
     'dhcp6_unittests.cc',
     'dhcp6to4_ipc_unittest.cc',
+    'flq_unittest.cc',
     'fqdn_unittest.cc',
     'get_config_unittest.cc',
     'hooks_unittest.cc',
index abd56db5ceb733577dda0a7bfaff384e14b324ed..1b322d0e9fc86d27ee98407429b6f9c68a1d4bc0 100644 (file)
@@ -1750,8 +1750,19 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
         isc_throw(BadValue, "Attempt to recycle registered address");
     }
 
+    bool use_min = false;
     if (expired->type_ != Lease::TYPE_PD) {
         prefix_len = 128; // non-PD lease types must be always /128
+    } else {
+       auto const& threshold = ctx.subnet_->getAdaptiveLeaseTimeThreshold();
+        if (!threshold.unspecified() && (threshold < 1.0)) {
+            auto const& occupancy = ctx.subnet_->getAllocator(Lease::TYPE_PD)->
+                getOccupancyRate(expired->addr_, prefix_len,
+                                 ctx.query_->getClasses());
+            if (occupancy >= threshold) {
+                use_min = true;
+            }
+        }
     }
 
     if (!ctx.fake_allocation_) {
@@ -1764,12 +1775,19 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
     // address, lease type and prefixlen (0) stay the same
     expired->iaid_ = ctx.currentIA().iaid_;
     expired->duid_ = ctx.duid_;
+    expired->hwaddr_ = ctx.hwaddr_;
 
     // Calculate life times.
-    getLifetimes6(ctx, expired->preferred_lft_, expired->valid_lft_);
+    expired->preferred_lft_ = 0;
+    expired->valid_lft_ = 0;
+    if (use_min) {
+       getMinLifetimes6(ctx, expired->preferred_lft_, expired->valid_lft_);
+    } else {
+       getLifetimes6(ctx, expired->preferred_lft_, expired->valid_lft_);
+    }
     expired->reuseable_valid_lft_ = 0;
 
-    expired->cltt_ = time(NULL);
+    expired->cltt_ = time(0);
     expired->subnet_id_ = ctx.subnet_->getID();
     expired->hostname_ = ctx.hostname_;
     expired->fqdn_fwd_ = ctx.fwd_dns_update_;
@@ -2035,13 +2053,27 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
                                     uint8_t prefix_len,
                                     CalloutHandle::CalloutNextStep& callout_status) {
 
+    uint32_t preferred = 0;
+    uint32_t valid = 0;
+    bool use_min = false;
     if (ctx.currentIA().type_ != Lease::TYPE_PD) {
         prefix_len = 128; // non-PD lease types must be always /128
+    } else {
+        auto const& threshold = ctx.subnet_->getAdaptiveLeaseTimeThreshold();
+        if (!threshold.unspecified() && (threshold < 1.0)) {
+            auto const& occupancy = ctx.subnet_->getAllocator(Lease::TYPE_PD)->
+                getOccupancyRate(addr, prefix_len,
+                                 ctx.query_->getClasses());
+            if (occupancy >= threshold) {
+                use_min = true;
+            }
+        }
+    }
+    if (use_min) {
+        getMinLifetimes6(ctx, preferred, valid);
+    } else {
+        getLifetimes6(ctx, preferred, valid);
     }
-
-    uint32_t preferred = 0;
-    uint32_t valid = 0;
-    getLifetimes6(ctx, preferred, valid);
 
     Lease6Ptr lease(new Lease6(ctx.currentIA().type_, addr, ctx.duid_,
                                ctx.currentIA().iaid_, preferred,