From: Francis Dupont Date: Wed, 24 May 2023 00:21:08 +0000 (+0200) Subject: [#2868] Implemented getLeases6ByLink X-Git-Tag: Kea-2.3.8~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=02b5540f793d258b0220984931a7b823076988dc;p=thirdparty%2Fkea.git [#2868] Implemented getLeases6ByLink --- diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.cc b/src/lib/dhcpsrv/dhcpsrv_messages.cc index 38ee2217e5..3b47fcf4d4 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.cc +++ b/src/lib/dhcpsrv/dhcpsrv_messages.cc @@ -167,6 +167,7 @@ extern const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME6 = "DHCPSRV_MYSQL_GE extern const isc::log::MessageID DHCPSRV_MYSQL_GET_HWADDR = "DHCPSRV_MYSQL_GET_HWADDR"; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_DUID = "DHCPSRV_MYSQL_GET_IAID_DUID"; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_SUBID_DUID = "DHCPSRV_MYSQL_GET_IAID_SUBID_DUID"; +extern const isc::log::MessageID DHCPSRV_MYSQL_GET_LINKADDR6 = "DHCPSRV_MYSQL_GET_LINKADDR6"; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE4 = "DHCPSRV_MYSQL_GET_PAGE4"; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE6 = "DHCPSRV_MYSQL_GET_PAGE6"; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_RELAYID4 = "DHCPSRV_MYSQL_GET_RELAYID4"; @@ -224,6 +225,7 @@ extern const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME6 = "DHCPSRV_PGSQL_GE extern const isc::log::MessageID DHCPSRV_PGSQL_GET_HWADDR = "DHCPSRV_PGSQL_GET_HWADDR"; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_DUID = "DHCPSRV_PGSQL_GET_IAID_DUID"; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_SUBID_DUID = "DHCPSRV_PGSQL_GET_IAID_SUBID_DUID"; +extern const isc::log::MessageID DHCPSRV_PGSQL_GET_LINKADDR6 = "DHCPSRV_PGSQL_GET_LINKADDR6"; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE4 = "DHCPSRV_PGSQL_GET_PAGE4"; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE6 = "DHCPSRV_PGSQL_GET_PAGE6"; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_RELAYID4 = "DHCPSRV_PGSQL_GET_RELAYID4"; @@ -444,6 +446,7 @@ const char* values[] = { "DHCPSRV_MYSQL_GET_HWADDR", "obtaining IPv4 leases for hardware address %1", "DHCPSRV_MYSQL_GET_IAID_DUID", "obtaining IPv6 leases for IAID %1, DUID %2, lease type %3", "DHCPSRV_MYSQL_GET_IAID_SUBID_DUID", "obtaining IPv6 leases for IAID %1, Subnet ID %2, DUID %3, lease type %4", + "DHCPSRV_MYSQL_GET_LINKADDR6", "obtaining at most %1 IPv6 leases starting from address %2 with link %3/%4", "DHCPSRV_MYSQL_GET_PAGE4", "obtaining at most %1 IPv4 leases starting from address %2", "DHCPSRV_MYSQL_GET_PAGE6", "obtaining at most %1 IPv6 leases starting from address %2", "DHCPSRV_MYSQL_GET_RELAYID4", "obtaining at most %1 IPv4 leases starting from address %2 with relay id %3 and cltt between %4 and %5", @@ -501,6 +504,7 @@ const char* values[] = { "DHCPSRV_PGSQL_GET_HWADDR", "obtaining IPv4 leases for hardware address %1", "DHCPSRV_PGSQL_GET_IAID_DUID", "obtaining IPv4 leases for IAID %1 and DUID %2, lease type %3", "DHCPSRV_PGSQL_GET_IAID_SUBID_DUID", "obtaining IPv4 leases for IAID %1, Subnet ID %2, DUID %3, and lease type %4", + "DHCPSRV_PGSQL_GET_LINKADDR6", "obtaining at most %1 IPv6 leases starting from address %2 with link %3/%4", "DHCPSRV_PGSQL_GET_PAGE4", "obtaining at most %1 IPv4 leases starting from address %2", "DHCPSRV_PGSQL_GET_PAGE6", "obtaining at most %1 IPv6 leases starting from address %2", "DHCPSRV_PGSQL_GET_RELAYID4", "obtaining at most %1 IPv4 leases starting from address %2 with relay id %3 and cltt between %4 and %5", diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.h b/src/lib/dhcpsrv/dhcpsrv_messages.h index 5640310c4f..0786c21e95 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.h +++ b/src/lib/dhcpsrv/dhcpsrv_messages.h @@ -168,6 +168,7 @@ extern const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME6; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_HWADDR; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_DUID; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_SUBID_DUID; +extern const isc::log::MessageID DHCPSRV_MYSQL_GET_LINKADDR6; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE4; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE6; extern const isc::log::MessageID DHCPSRV_MYSQL_GET_RELAYID4; @@ -225,6 +226,7 @@ extern const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME6; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_HWADDR; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_DUID; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_SUBID_DUID; +extern const isc::log::MessageID DHCPSRV_PGSQL_GET_LINKADDR6; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE4; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE6; extern const isc::log::MessageID DHCPSRV_PGSQL_GET_RELAYID4; diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes index ade253aed9..324db1f75c 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.mes +++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes @@ -861,6 +861,10 @@ A debug message issued when the server is attempting to obtain an IPv6 lease from the MySQL database for a client with the specified IAID (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier). +% DHCPSRV_MYSQL_GET_LINKADDR6 obtaining at most %1 IPv6 leases starting from address %2 with link %3/%4 +A debug message issued when the server is attempting to obtain a page of +IPv6 leases beginning with the specified address within a link. + % DHCPSRV_MYSQL_GET_PAGE4 obtaining at most %1 IPv4 leases starting from address %2 A debug message issued when the server is attempting to obtain a page of leases beginning with the specified address. @@ -1129,6 +1133,10 @@ A debug message issued when the server is attempting to obtain an IPv6 lease from the PostgreSQL database for a client with the specified IAID (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier). +% DHCPSRV_PGSQL_GET_LINKADDR6 obtaining at most %1 IPv6 leases starting from address %2 with link %3/%4 +A debug message issued when the server is attempting to obtain a page of +IPv6 leases beginning with the specified address within a link. + % DHCPSRV_PGSQL_GET_PAGE4 obtaining at most %1 IPv4 leases starting from address %2 A debug message issued when the server is attempting to obtain a page of leases beginning with the specified address. diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index ad25c8f44d..7e2fda1f28 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include @@ -401,6 +401,18 @@ tagged_statements = { { "AND expire < ? " "ORDER BY expire ASC " "LIMIT ?"}, + {MySqlLeaseMgr::GET_LEASE6_LINK, + "SELECT address, duid, valid_lifetime, " + "expire, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source, " + "state, user_context " + "FROM lease6 " + "WHERE binaddr IS NOT NULL " + "AND binaddr BETWEEN ? AND ? " + "ORDER BY binaddr " + "LIMIT ?"}, {MySqlLeaseMgr::INSERT_LEASE4, "INSERT INTO lease4(address, hwaddr, client_id, " "valid_lifetime, expire, subnet_id, " @@ -4031,11 +4043,87 @@ MySqlLeaseMgr::getLeases6ByRemoteId(const OptionBuffer& /* remote_id */, } Lease6Collection -MySqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */, - uint8_t /* link_len */, - const IOAddress& /* lower_bound_address */, - const LeasePageSize& /* page_size */) { - isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases6ByLink not implemented"); +MySqlLeaseMgr::getLeases6ByLink(const IOAddress& link_addr, + uint8_t link_len, + const IOAddress& lower_bound_address, + const LeasePageSize& page_size) { + // Expecting IPv6 valid prefix and address. + if (!link_addr.isV6()) { + isc_throw(InvalidAddressFamily, "expected IPv6 address while " + "retrieving leases from the lease database, got " + << link_addr); + } + if ((link_len == 0) || (link_len > 128)) { + isc_throw(OutOfRange, "invalid IPv6 prefix length " + << static_cast(link_len)); + } + if (!lower_bound_address.isV6()) { + isc_throw(InvalidAddressFamily, "expected IPv6 address while " + "retrieving leases from the lease database, got " + << lower_bound_address); + } + + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, + DHCPSRV_MYSQL_GET_LINKADDR6) + .arg(page_size.page_size_) + .arg(lower_bound_address.toText()) + .arg(link_addr.toText()) + .arg(static_cast(link_len)); + + Lease6Collection result; + const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len); + const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len); + IOAddress start_addr = lower_bound_address; + if (lower_bound_address < first_addr) { + start_addr = first_addr; + } else if (last_addr <= lower_bound_address) { + // Range was already done. + return (result); + } else { + // The lower bound address is from the last call so skip it. + start_addr = IOAddress::increase(lower_bound_address); + } + + // Prepare WHERE clause + MYSQL_BIND inbind[3]; + memset(inbind, 0, sizeof(inbind)); + + // Bind start address + std::vector start_addr_data = start_addr.toBytes(); + if (start_addr_data.size() != 16) { + isc_throw(DbOperationError, "start address is not 16 byte long"); + } + unsigned long start_addr_size = 16; + inbind[0].buffer_type = MYSQL_TYPE_BLOB; + inbind[0].buffer = reinterpret_cast(&start_addr_data[0]); + inbind[0].buffer_length = 16; + inbind[0].length = &start_addr_size; + + // Bind last address + std::vector last_addr_data = last_addr.toBytes(); + if (last_addr_data.size() != 16) { + isc_throw(DbOperationError, "last address is not 16 byte long"); + } + unsigned long last_addr_size = 16; + inbind[1].buffer_type = MYSQL_TYPE_BLOB; + inbind[1].buffer = reinterpret_cast(&last_addr_data[0]); + inbind[1].buffer_length = 16; + inbind[1].length = &last_addr_size; + + // Bind page size value + uint32_t ps = static_cast(page_size.page_size_); + inbind[2].buffer_type = MYSQL_TYPE_LONG; + inbind[2].buffer = reinterpret_cast(&ps); + inbind[2].is_unsigned = MLM_TRUE; + + // Get a context + MySqlLeaseContextAlloc get_context(*this); + MySqlLeaseContextPtr ctx = get_context.ctx_; + + // Get the leases + getLeaseCollection(ctx, GET_LEASE6_LINK, inbind, result); + + return (result); } size_t diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h index a08d1909d3..a3621bd371 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.h +++ b/src/lib/dhcpsrv/mysql_lease_mgr.h @@ -725,6 +725,7 @@ public: GET_LEASE6_DUID, // Get IPv6 leases by DUID GET_LEASE6_HOSTNAME, // Get IPv6 leases by hostname GET_LEASE6_EXPIRE, // Get lease6 by expiration. + GET_LEASE6_LINK, // Get page of lease6 by link INSERT_LEASE4, // Add entry to lease4 table INSERT_LEASE6, // Add entry to lease6 table UPDATE_LEASE4, // Update a Lease4 entry diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index e57ceac796..0d46c0b873 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include @@ -420,6 +420,20 @@ PgSqlTaggedStatement tagged_statements[] = { "ORDER BY expire " "LIMIT $3"}, + // GET_LEASE6_LINK + { 3, { OID_BYTEA, OID_BYTEA, OID_INT8 }, + "get_lease6_link", + "SELECT address, duid, valid_lifetime, " + "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source, " + "state, user_context " + "FROM lease6 " + "WHERE binaddr IS NOT NULL " + "AND binaddr BETWEEN $1 and $2 " + "ORDER BY binaddr " + "LIMIT $3"}, + // INSERT_LEASE4 { 13, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_BYTEA, @@ -2264,7 +2278,8 @@ PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address, bind_array.add(lb_address_data); // Bind page size value - std::string page_size_data = boost::lexical_cast(page_size.page_size_); + std::string page_size_data = + boost::lexical_cast(page_size.page_size_); bind_array.add(page_size_data); // Get the leases @@ -3159,11 +3174,77 @@ PgSqlLeaseMgr::getLeases6ByRemoteId(const OptionBuffer& /* remote_id */, } Lease6Collection -PgSqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */, - uint8_t /* link_len */, - const IOAddress& /* lower_bound_address */, - const LeasePageSize& /* page_size */) { - isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByLink not implemented"); +PgSqlLeaseMgr::getLeases6ByLink(const IOAddress& link_addr, + uint8_t link_len, + const IOAddress& lower_bound_address, + const LeasePageSize& page_size) { + // Expecting IPv6 valid prefix and address. + if (!link_addr.isV6()) { + isc_throw(InvalidAddressFamily, "expected IPv6 address while " + "retrieving leases from the lease database, got " + << link_addr); + } + if ((link_len == 0) || (link_len > 128)) { + isc_throw(OutOfRange, "invalid IPv6 prefix length " + << static_cast(link_len)); + } + if (!lower_bound_address.isV6()) { + isc_throw(InvalidAddressFamily, "expected IPv6 address while " + "retrieving leases from the lease database, got " + << lower_bound_address); + } + + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, + DHCPSRV_PGSQL_GET_LINKADDR6) + .arg(page_size.page_size_) + .arg(lower_bound_address.toText()) + .arg(link_addr.toText()) + .arg(static_cast(link_len)); + + Lease6Collection result; + const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len); + const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len); + IOAddress start_addr = lower_bound_address; + if (lower_bound_address < first_addr) { + start_addr = first_addr; + } else if (last_addr <= lower_bound_address) { + // Range was already done. + return (result); + } else { + // The lower bound address is from the last call so skip it. + start_addr = IOAddress::increase(lower_bound_address); + } + + // Prepare WHERE clause + PsqlBindArray bind_array; + + // Bind start address + std::vector start_addr_data = start_addr.toBytes(); + if (start_addr_data.size() != 16) { + isc_throw(DbOperationError, "start address is not 16 byte long"); + } + bind_array.add(start_addr_data); + + // Bind last address + std::vector last_addr_data = last_addr.toBytes(); + if (last_addr_data.size() != 16) { + isc_throw(DbOperationError, "last address is not 16 byte long"); + } + bind_array.add(last_addr_data); + + // Bind page size value + std::string page_size_data = + boost::lexical_cast(page_size.page_size_); + bind_array.add(page_size_data); + + // Get a context + PgSqlLeaseContextAlloc get_context(*this); + PgSqlLeaseContextPtr ctx = get_context.ctx_; + + // Get the leases + getLeaseCollection(ctx, GET_LEASE6_LINK, bind_array, result); + + return (result); } size_t diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index c3369540ba..fe5f363d0d 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -701,6 +701,7 @@ public: GET_LEASE6_DUID, // Get IPv6 leases by DUID GET_LEASE6_HOSTNAME, // Get IPv6 leases by hostname GET_LEASE6_EXPIRE, // Get lease6 by expiration. + GET_LEASE6_LINK, // Get page of lease6 by link INSERT_LEASE4, // Add entry to lease4 table INSERT_LEASE6, // Add entry to lease6 table UPDATE_LEASE4, // Update a Lease4 entry diff --git a/src/lib/dhcpsrv/tests/mysql_lease_extended_info_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_extended_info_unittest.cc index c3529c2ac6..fc077f5f6f 100644 --- a/src/lib/dhcpsrv/tests/mysql_lease_extended_info_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_extended_info_unittest.cc @@ -36,6 +36,12 @@ const vector ADDRESS4 = { "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7" }; +/// @brief IPv6 addresses used in the tests. +const vector ADDRESS6 = { + "2001:db8::0", "2001:db8::1", "2001:db8::2", "2001:db8::3", + "2001:db8::4", "2001:db8::5", "2001:db8::6", "2001:db8::7" +}; + /// @brief DUIDs used in the tests. const vector DUIDS = { "wwwwwwww", "BBBBBBBB", "::::::::", "0123456789acdef", @@ -64,6 +70,7 @@ public: lease_mgr_ = &(LeaseMgrFactory::instance()); leases4.clear(); + leases6.clear(); MultiThreadingMgr::instance().setMode(false); now_ = time(0); } @@ -76,6 +83,7 @@ public: destroyMySQLSchema(); leases4.clear(); + leases6.clear(); MultiThreadingMgr::instance().setMode(false); } @@ -104,6 +112,23 @@ public: ASSERT_EQ(ADDRESS4.size(), leases4.size()); } + /// @brief Create and set v6 leases. + void initLease6() { + ASSERT_EQ(ADDRESS6.size(), DUIDS.size()); + for (size_t i = 0; i < ADDRESS6.size(); ++i) { + Lease6Ptr lease; + vector duid_data = createFromString(DUIDS[i]); + DuidPtr duid(new DUID(duid_data)); + IOAddress addr(ADDRESS6[i]); + ASSERT_NO_THROW(lease.reset(new Lease6(((i % 2) ? Lease::TYPE_NA : Lease::TYPE_PD), addr, duid, + 123, 1000, 2000, + static_cast(i)))); + leases6.push_back(lease); + EXPECT_TRUE(lease_mgr_->addLease(lease)); + } + ASSERT_EQ(ADDRESS6.size(), leases6.size()); + } + /// @brief Create a vector of uint8_t from a string. /// /// @param content A not empty string holding the content. @@ -118,6 +143,9 @@ public: /// @brief Test initLease4. void testInitLease4(); + /// @brief Test initLease6. + void testInitLease6(); + /// @brief Test getLease4ByRelayId. void testGetLeases4ByRelayId(); @@ -128,12 +156,18 @@ public: void testUpgradeExtendedInfo4(const CfgConsistency::ExtendedInfoSanity& check, const LeasePageSize& page_size); + /// @brief Test getLeases6ByLink. + void testGetLeases6ByLink(); + /// @brief Lease manager. LeaseMgr* lease_mgr_; /// @brief V4 leases. Lease4Collection leases4; + /// @brief V6 leases. + Lease6Collection leases6; + /// @brief Current timestamp. time_t now_; }; @@ -965,4 +999,105 @@ TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfo4_1) { LeasePageSize(1)); } +/// @brief Verifies that the lease manager can add the v6 leases. +void +MySqlExtendedInfoTest::testInitLease6() { + initLease6(); + EXPECT_EQ(8, leases6.size()); + Lease6Collection got; + EXPECT_NO_THROW(got = lease_mgr_->getLeases6()); + ASSERT_EQ(leases6.size(), got.size()); + for (size_t i = 0; i < leases6.size(); ++i) { + ConstElementPtr expected = leases6[i]->toElement(); + LeasePtr lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_TRUE(expected->equals(*lease->toElement())) + << "expected: " << expected->str() << "\n" + << "got: " << lease->toElement()->str() << "\n"; + } +} + +TEST_F(MySqlExtendedInfoTest, initLease6) { + testInitLease6(); +} + +TEST_F(MySqlExtendedInfoTest, initLease6MultiThreading) { + MultiThreadingTest mt(true); + testInitLease6(); +} + +/// @brief Verifies that getLeases6ByLink works as expected. +void +MySqlExtendedInfoTest::testGetLeases6ByLink() { + // Lease manager is created with empty tables. + initLease6(); + + // Create parameter values. + IOAddress link_addr(ADDRESS6[4]); + IOAddress other_link_addr("2001:db8:1::4"); + IOAddress zero = IOAddress::IPV6_ZERO_ADDRESS(); + + Lease6Collection got; + // Other link: nothing. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(other_link_addr, + 64, + zero, + LeasePageSize(10))); + EXPECT_EQ(0, got.size()); + + // Link: 8 entries. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + zero, + LeasePageSize(10))); + + ASSERT_EQ(8, got.size()); + Lease6Ptr lease; + for (size_t i = 0; i < 8; ++i) { + lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_EQ(IOAddress(ADDRESS6[i]), lease->addr_); + } + + // Link: initial partial: 4 entries. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + zero, + LeasePageSize(4))); + ASSERT_EQ(4, got.size()); + for (size_t i = 0; i < 4; ++i) { + lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_EQ(IOAddress(ADDRESS6[i]), lease->addr_); + } + + // Link: next partial: 4 entries. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + lease->addr_, + LeasePageSize(4))); + ASSERT_EQ(4, got.size()); + for (size_t i = 0; i < 4; ++i) { + lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_EQ(IOAddress(ADDRESS6[i + 4]), lease->addr_); + } + + // Link: further partial: nothing. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + lease->addr_, + LeasePageSize(4))); + EXPECT_EQ(0, got.size()); +} + +TEST_F(MySqlExtendedInfoTest, getLeases6ByLink) { + testGetLeases6ByLink(); +} + +TEST_F(MySqlExtendedInfoTest, getLeases6ByLinkMultiThreading) { + MultiThreadingTest mt(true); + testGetLeases6ByLink(); +} + } // namespace diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_extended_info_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_extended_info_unittest.cc index be224447bb..1bd8291428 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_extended_info_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_extended_info_unittest.cc @@ -36,6 +36,12 @@ const vector ADDRESS4 = { "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7" }; +/// @brief IPv6 addresses used in the tests. +const vector ADDRESS6 = { + "2001:db8::0", "2001:db8::1", "2001:db8::2", "2001:db8::3", + "2001:db8::4", "2001:db8::5", "2001:db8::6", "2001:db8::7" +}; + /// @brief DUIDs used in the tests. const vector DUIDS = { "wwwwwwww", "BBBBBBBB", "::::::::", "0123456789acdef", @@ -64,6 +70,7 @@ public: lease_mgr_ = &(LeaseMgrFactory::instance()); leases4.clear(); + leases6.clear(); MultiThreadingMgr::instance().setMode(false); now_ = time(0); } @@ -76,6 +83,7 @@ public: destroyPgSQLSchema(); leases4.clear(); + leases6.clear(); MultiThreadingMgr::instance().setMode(false); } @@ -104,6 +112,23 @@ public: ASSERT_EQ(ADDRESS4.size(), leases4.size()); } + /// @brief Create and set v6 leases. + void initLease6() { + ASSERT_EQ(ADDRESS6.size(), DUIDS.size()); + for (size_t i = 0; i < ADDRESS6.size(); ++i) { + Lease6Ptr lease; + vector duid_data = createFromString(DUIDS[i]); + DuidPtr duid(new DUID(duid_data)); + IOAddress addr(ADDRESS6[i]); + ASSERT_NO_THROW(lease.reset(new Lease6(((i % 2) ? Lease::TYPE_NA : Lease::TYPE_PD), addr, duid, + 123, 1000, 2000, + static_cast(i)))); + leases6.push_back(lease); + EXPECT_TRUE(lease_mgr_->addLease(lease)); + } + ASSERT_EQ(ADDRESS6.size(), leases6.size()); + } + /// @brief Create a vector of uint8_t from a string. /// /// @param content A not empty string holding the content. @@ -118,6 +143,9 @@ public: /// @brief Test initLease4. void testInitLease4(); + /// @brief Test initLease6. + void testInitLease6(); + /// @brief Test getLease4ByRelayId. void testGetLeases4ByRelayId(); @@ -128,12 +156,18 @@ public: void testUpgradeExtendedInfo4(const CfgConsistency::ExtendedInfoSanity& check, const LeasePageSize& page_size); + /// @brief Test getLeases6ByLink. + void testGetLeases6ByLink(); + /// @brief Lease manager. LeaseMgr* lease_mgr_; /// @brief V4 leases. Lease4Collection leases4; + /// @brief V6 leases. + Lease6Collection leases6; + /// @brief Current timestamp. time_t now_; }; @@ -965,4 +999,105 @@ TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfo4_1) { LeasePageSize(1)); } +/// @brief Verifies that the lease manager can add the v6 leases. +void +PgSqlExtendedInfoTest::testInitLease6() { + initLease6(); + EXPECT_EQ(8, leases6.size()); + Lease6Collection got; + EXPECT_NO_THROW(got = lease_mgr_->getLeases6()); + ASSERT_EQ(leases6.size(), got.size()); + for (size_t i = 0; i < leases6.size(); ++i) { + ConstElementPtr expected = leases6[i]->toElement(); + LeasePtr lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_TRUE(expected->equals(*lease->toElement())) + << "expected: " << expected->str() << "\n" + << "got: " << lease->toElement()->str() << "\n"; + } +} + +TEST_F(PgSqlExtendedInfoTest, initLease6) { + testInitLease6(); +} + +TEST_F(PgSqlExtendedInfoTest, initLease6MultiThreading) { + MultiThreadingTest mt(true); + testInitLease6(); +} + +/// @brief Verifies that getLeases6ByLink works as expected. +void +PgSqlExtendedInfoTest::testGetLeases6ByLink() { + // Lease manager is created with empty tables. + initLease6(); + + // Create parameter values. + IOAddress link_addr(ADDRESS6[4]); + IOAddress other_link_addr("2001:db8:1::4"); + IOAddress zero = IOAddress::IPV6_ZERO_ADDRESS(); + + Lease6Collection got; + // Other link: nothing. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(other_link_addr, + 64, + zero, + LeasePageSize(10))); + EXPECT_EQ(0, got.size()); + + // Link: 8 entries. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + zero, + LeasePageSize(10))); + + ASSERT_EQ(8, got.size()); + Lease6Ptr lease; + for (size_t i = 0; i < 8; ++i) { + lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_EQ(IOAddress(ADDRESS6[i]), lease->addr_); + } + + // Link: initial partial: 4 entries. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + zero, + LeasePageSize(4))); + ASSERT_EQ(4, got.size()); + for (size_t i = 0; i < 4; ++i) { + lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_EQ(IOAddress(ADDRESS6[i]), lease->addr_); + } + + // Link: next partial: 4 entries. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + lease->addr_, + LeasePageSize(4))); + ASSERT_EQ(4, got.size()); + for (size_t i = 0; i < 4; ++i) { + lease = got[i]; + ASSERT_TRUE(lease); + EXPECT_EQ(IOAddress(ADDRESS6[i + 4]), lease->addr_); + } + + // Link: further partial: nothing. + EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByLink(link_addr, + 64, + lease->addr_, + LeasePageSize(4))); + EXPECT_EQ(0, got.size()); +} + +TEST_F(PgSqlExtendedInfoTest, getLeases6ByLink) { + testGetLeases6ByLink(); +} + +TEST_F(PgSqlExtendedInfoTest, getLeases6ByLinkMultiThreading) { + MultiThreadingTest mt(true); + testGetLeases6ByLink(); +} + } // namespace