From: Marcin Siodelski Date: Tue, 20 Sep 2016 07:29:06 +0000 (+0200) Subject: [5009] Implemented get6(subnet_id, address) function for SQL backends. X-Git-Tag: trac5049_base~13^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8cce1aa713e547e624443fcdcf637426ada2d451;p=thirdparty%2Fkea.git [5009] Implemented get6(subnet_id, address) function for SQL backends. Also removed uint32_t cast operator from IOAddress to remove ambiguity when calling this new function. --- diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 9902160838..523b81a003 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -2092,7 +2092,7 @@ Dhcpv4Srv::setFixedFields(Dhcpv4Exchange& ex) { OptionPtr Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) { - uint32_t netmask = getNetmask4(subnet->get().second); + uint32_t netmask = getNetmask4(subnet->get().second).toUint32(); OptionPtr opt(new OptionInt(Option::V4, DHO_SUBNET_MASK, netmask)); diff --git a/src/bin/dhcp4/tests/decline_unittest.cc b/src/bin/dhcp4/tests/decline_unittest.cc index f824c98562..3dce25821f 100644 --- a/src/bin/dhcp4/tests/decline_unittest.cc +++ b/src/bin/dhcp4/tests/decline_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2016 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 @@ -280,7 +280,7 @@ TEST_F(DeclineTest, declineNonMatchingIPAddress) { // Modify the client's address to force it to decline a different address // than it has obtained from the server. - client.config_.lease_.addr_ = IOAddress(static_cast(leased_address) + 1); + client.config_.lease_.addr_ = IOAddress(leased_address.toUint32() + 1); // Send DHCPDECLINE and make sure it was unsuccessful, i.e. the lease // remains in the database. diff --git a/src/bin/dhcp4/tests/release_unittest.cc b/src/bin/dhcp4/tests/release_unittest.cc index 5e3842df4d..4ea8c4d282 100644 --- a/src/bin/dhcp4/tests/release_unittest.cc +++ b/src/bin/dhcp4/tests/release_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 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 @@ -265,7 +265,7 @@ TEST_F(ReleaseTest, releaseNonMatchingIPAddress) { // Modify the client's address to force it to release a different address // than it has obtained from the server. - client.config_.lease_.addr_ = IOAddress(static_cast(leased_address) + 1); + client.config_.lease_.addr_ = IOAddress(leased_address.toUint32() + 1); // Send DHCPRELEASE and make sure it was unsuccessful, i.e. the lease // remains in the database. diff --git a/src/bin/perfdhcp/test_control.cc b/src/bin/perfdhcp/test_control.cc index 5c79b2cc02..c4c665b411 100644 --- a/src/bin/perfdhcp/test_control.cc +++ b/src/bin/perfdhcp/test_control.cc @@ -1797,7 +1797,7 @@ TestControl::sendRequest4(const TestControlSocket& socket, OptionPtr opt_requested_address = OptionPtr(new Option(Option::V4, DHO_DHCP_REQUESTED_ADDRESS, OptionBuffer())); - opt_requested_address->setUint32(static_cast(yiaddr)); + opt_requested_address->setUint32(yiaddr.toUint32()); pkt4->addOption(opt_requested_address); OptionPtr opt_parameter_list = Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST); @@ -1916,8 +1916,8 @@ TestControl::sendRequest4(const TestControlSocket& socket, DHO_DHCP_REQUESTED_ADDRESS, OptionBuffer(), rip_offset)); - // The IOAddress is castable to uint32_t and returns exactly what we need. - opt_requested_ip->setUint32(static_cast(yiaddr)); + // The IOAddress is convertible to uint32_t and returns exactly what we need. + opt_requested_ip->setUint32(yiaddr.toUint32()); pkt4->addOption(opt_requested_ip); setDefaults4(socket, boost::static_pointer_cast(pkt4)); diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc index de5cf3a351..dae8074066 100644 --- a/src/lib/asiolink/io_address.cc +++ b/src/lib/asiolink/io_address.cc @@ -107,7 +107,8 @@ IOAddress::isV6Multicast() const { return (asio_address_.to_v6().is_multicast()); } -IOAddress::operator uint32_t() const { +uint32_t +IOAddress::toUint32() const { if (asio_address_.is_v4()) { return (asio_address_.to_v4().to_ulong()); } else { @@ -128,8 +129,8 @@ IOAddress::subtract(const IOAddress& a, const IOAddress& b) { isc_throw(BadValue, "Both addresses have to be the same family"); } if (a.isV4()) { - // Subtracting v4 is easy. We have uint32_t operator. - return (IOAddress(static_cast(a) - static_cast(b))); + // Subtracting v4 is easy. We have a conversion function to uint32_t. + return (IOAddress(a.toUint32() - b.toUint32())); } else { // v6 is more involved. diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h index 684a7b1a79..6a08575173 100644 --- a/src/lib/asiolink/io_address.h +++ b/src/lib/asiolink/io_address.h @@ -1,4 +1,4 @@ -// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2010-2016 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 @@ -285,7 +285,7 @@ public: /// /// \return uint32_t that represents IPv4 address in /// network byte order - operator uint32_t () const; + uint32_t toUint32() const; /// @name Methods returning @c IOAddress objects encapsulating typical addresses. /// diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc index a6cbc675aa..ad6faec87d 100644 --- a/src/lib/asiolink/tests/io_address_unittest.cc +++ b/src/lib/asiolink/tests/io_address_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2011-2016 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 @@ -172,7 +172,7 @@ TEST(IOAddressTest, uint32) { IOAddress addr1("192.0.2.5"); // operator uint_32() is used here - uint32_t tmp = addr1; + uint32_t tmp = addr1.toUint32(); uint32_t expected = (192U << 24) + (0U << 16) + (2U << 8) + 5U; diff --git a/src/lib/dhcp/option4_addrlst.cc b/src/lib/dhcp/option4_addrlst.cc index 478eb997f1..d83aa7022d 100644 --- a/src/lib/dhcp/option4_addrlst.cc +++ b/src/lib/dhcp/option4_addrlst.cc @@ -77,7 +77,7 @@ Option4AddrLst::pack(isc::util::OutputBuffer& buf) const { AddressContainer::const_iterator addr = addrs_.begin(); while (addr != addrs_.end()) { - buf.writeUint32(*addr); + buf.writeUint32(addr->toUint32()); ++addr; } } diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc index abe71fda1f..b0150c4d62 100644 --- a/src/lib/dhcp/pkt4.cc +++ b/src/lib/dhcp/pkt4.cc @@ -106,10 +106,10 @@ Pkt4::pack() { buffer_out_.writeUint32(transid_); buffer_out_.writeUint16(secs_); buffer_out_.writeUint16(flags_); - buffer_out_.writeUint32(ciaddr_); - buffer_out_.writeUint32(yiaddr_); - buffer_out_.writeUint32(siaddr_); - buffer_out_.writeUint32(giaddr_); + buffer_out_.writeUint32(ciaddr_.toUint32()); + buffer_out_.writeUint32(yiaddr_.toUint32()); + buffer_out_.writeUint32(siaddr_.toUint32()); + buffer_out_.writeUint32(giaddr_.toUint32()); if ((hw_len > 0) && (hw_len <= MAX_CHADDR_LEN)) { diff --git a/src/lib/dhcp/pkt_filter.cc b/src/lib/dhcp/pkt_filter.cc index 4619c7e9f5..3544e3b2b3 100644 --- a/src/lib/dhcp/pkt_filter.cc +++ b/src/lib/dhcp/pkt_filter.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2013-2016 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 @@ -36,7 +36,7 @@ PktFilter::openFallbackSocket(const isc::asiolink::IOAddress& addr, struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_family = AF_INET; - addr4.sin_addr.s_addr = htonl(addr); + addr4.sin_addr.s_addr = htonl(addr.toUint32()); addr4.sin_port = htons(port); if (bind(sock, reinterpret_cast(&addr4), diff --git a/src/lib/dhcp/pkt_filter_bpf.cc b/src/lib/dhcp/pkt_filter_bpf.cc index 6c634c3fb2..474b8684e1 100644 --- a/src/lib/dhcp/pkt_filter_bpf.cc +++ b/src/lib/dhcp/pkt_filter_bpf.cc @@ -341,7 +341,7 @@ PktFilterBPF::openSocket(Iface& iface, // Configure the BPF program to receive unicast packets sent to the // specified address. The program will also allow packets sent to the // 255.255.255.255 broadcast address. - prog.bf_insns[8].k = static_cast(addr); + prog.bf_insns[8].k = addr.toUint32(); // Configure the BPF program to receive packets on the specified port. prog.bf_insns[11].k = port; diff --git a/src/lib/dhcp/pkt_filter_inet.cc b/src/lib/dhcp/pkt_filter_inet.cc index 1a0bb8e08a..287dfbd83c 100644 --- a/src/lib/dhcp/pkt_filter_inet.cc +++ b/src/lib/dhcp/pkt_filter_inet.cc @@ -40,7 +40,7 @@ PktFilterInet::openSocket(Iface& iface, if (receive_bcast && iface.flag_broadcast_) { addr4.sin_addr.s_addr = INADDR_ANY; } else { - addr4.sin_addr.s_addr = htonl(addr); + addr4.sin_addr.s_addr = htonl(addr.toUint32()); } int sock = socket(AF_INET, SOCK_DGRAM, 0); @@ -218,7 +218,7 @@ PktFilterInet::send(const Iface&, uint16_t sockfd, memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_port = htons(pkt->getRemotePort()); - to.sin_addr.s_addr = htonl(pkt->getRemoteAddr()); + to.sin_addr.s_addr = htonl(pkt->getRemoteAddr().toUint32()); struct msghdr m; // Initialize our message header structure. diff --git a/src/lib/dhcp/protocol_util.cc b/src/lib/dhcp/protocol_util.cc index a7a74edef9..d4fda21ed7 100644 --- a/src/lib/dhcp/protocol_util.cc +++ b/src/lib/dhcp/protocol_util.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2013-2016 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 @@ -168,8 +168,8 @@ writeIpUdpHeader(const Pkt4Ptr& pkt, util::OutputBuffer& out_buf) { out_buf.writeUint8(128); // TTL out_buf.writeUint8(IPPROTO_UDP); // Protocol UDP. out_buf.writeUint16(0); // Temporarily set checksum to 0. - out_buf.writeUint32(pkt->getLocalAddr()); // Source address. - out_buf.writeUint32(pkt->getRemoteAddr()); // Destination address. + out_buf.writeUint32(pkt->getLocalAddr().toUint32()); // Source address. + out_buf.writeUint32(pkt->getRemoteAddr().toUint32()); // Destination address. // Calculate pseudo header checksum. It will be necessary to compute // UDP checksum. diff --git a/src/lib/dhcp/tests/pkt_filter_test_utils.cc b/src/lib/dhcp/tests/pkt_filter_test_utils.cc index af00481e5f..7b5a79ec56 100644 --- a/src/lib/dhcp/tests/pkt_filter_test_utils.cc +++ b/src/lib/dhcp/tests/pkt_filter_test_utils.cc @@ -105,7 +105,7 @@ PktFilterTest::sendMessage(const IOAddress& dest) { memset(&dest_addr4, 0, sizeof(sockaddr)); dest_addr4.sin_family = AF_INET; dest_addr4.sin_port = htons(port_); - dest_addr4.sin_addr.s_addr = htonl(dest); + dest_addr4.sin_addr.s_addr = htonl(dest.toUint32()); ASSERT_EQ(sendto(send_msg_sock_, test_message_->getBuffer().getData(), test_message_->getBuffer().getLength(), 0, reinterpret_cast(&dest_addr4), diff --git a/src/lib/dhcpsrv/addr_utilities.cc b/src/lib/dhcpsrv/addr_utilities.cc index b3179ffe6d..b55d8ec2d5 100644 --- a/src/lib/dhcpsrv/addr_utilities.cc +++ b/src/lib/dhcpsrv/addr_utilities.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 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 @@ -95,7 +95,7 @@ isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& pref // We don't check that it is a valid IPv4 address and thus has // a required length of 4 bytes because it has been already // checked by the calling function. - uint32_t addr = prefix; + uint32_t addr = prefix.toUint32(); return (IOAddress(addr & (~bitMask4[len]))); } @@ -112,7 +112,7 @@ isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefi isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4"); } - uint32_t addr = prefix; + uint32_t addr = prefix.toUint32(); return (IOAddress(addr | bitMask4[len])); } @@ -215,8 +215,8 @@ addrsInRange(const isc::asiolink::IOAddress& min, // Let's explicitly cast last_ and first_ (IOAddress). This conversion is // automatic, but let's explicitly cast it show that we moved to integer // domain and addresses are now substractable. - uint64_t max_numeric = static_cast(max); - uint64_t min_numeric = static_cast(min); + uint64_t max_numeric = static_cast(max.toUint32()); + uint64_t min_numeric = static_cast(min.toUint32()); // We can simply subtract the values. We need to increase the result // by one, as both min and max are included in the range. So even if diff --git a/src/lib/dhcpsrv/base_host_data_source.h b/src/lib/dhcpsrv/base_host_data_source.h index 0230efcfbe..2fbd1aec84 100644 --- a/src/lib/dhcpsrv/base_host_data_source.h +++ b/src/lib/dhcpsrv/base_host_data_source.h @@ -225,6 +225,16 @@ public: virtual ConstHostPtr get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const = 0; + /// @brief Returns a host connected to the IPv6 subnet and having + /// a reservation for a specified IPv6 address or prefix. + /// + /// @param subnet_id Subnet identifier. + /// @param address reserved IPv6 address/prefix. + /// + /// @return Const @c Host object using a specified IPv6 address/prefix. + virtual ConstHostPtr + get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const = 0; + /// @brief Adds a new host to the collection. /// /// The implementations of this method should guard against duplicate diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index 3dde4c4c04..927f10a13f 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -294,7 +294,7 @@ public: // ipv4_address : INT UNSIGNED NULL // The address in the Host structure is an IOAddress object. Convert // this to an integer for storage. - ipv4_address_ = static_cast(host->getIPv4Reservation()); + ipv4_address_ = host->getIPv4Reservation().toUint32(); bind_[5].buffer_type = MYSQL_TYPE_LONG; bind_[5].buffer = reinterpret_cast(&ipv4_address_); bind_[5].is_unsigned = MLM_TRUE; @@ -327,7 +327,7 @@ public: // ipv4_address : INT UNSIGNED NULL // The address in the Host structure is an IOAddress object. Convert // this to an integer for storage. - dhcp4_next_server_ = static_cast(host->getNextServer()); + dhcp4_next_server_ = host->getNextServer().toUint32(); bind_[9].buffer_type = MYSQL_TYPE_LONG; bind_[9].buffer = reinterpret_cast(&dhcp4_next_server_); bind_[9].is_unsigned = MLM_TRUE; @@ -1757,6 +1757,7 @@ public: GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address GET_HOST_PREFIX, // Gets host by IPv6 prefix + GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix GET_VERSION, // Obtain version number INSERT_HOST, // Insert new host to collection INSERT_V6_RESRV, // Insert v6 reservation @@ -2046,6 +2047,30 @@ TaggedStatementArray tagged_statements = { { "WHERE address = ? AND prefix_len = ?) " "ORDER BY h.host_id, o.option_id, r.reservation_id"}, + // Retrieves host information, IPv6 reservations and DHCPv6 options + // associated with a host using subnet id and prefix. This query + // returns host information for a single host. However, multiple rows + // are returned due to left joining IPv6 reservations and DHCPv6 options. + // The number of rows returned is multiplication of number of existing + // IPv6 reservations and DHCPv6 options. + {MySqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR, + "SELECT h.host_id, h.dhcp_identifier, " + "h.dhcp_identifier_type, h.dhcp4_subnet_id, " + "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " + "h.dhcp4_client_classes, h.dhcp6_client_classes, " + "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " + "o.option_id, o.code, o.value, o.formatted_value, o.space, " + "o.persistent, " + "r.reservation_id, r.address, r.prefix_len, r.type, " + "r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp6_options AS o " + "ON h.host_id = o.host_id " + "LEFT JOIN ipv6_reservations AS r " + "ON h.host_id = r.host_id " + "WHERE h.dhcp6_subnet_id = ? AND r.address = ? " + "ORDER BY h.host_id, o.option_id, r.reservation_id"}, + // Retrieves MySQL schema version. {MySqlHostDataSourceImpl::GET_VERSION, "SELECT version, minor FROM schema_version"}, @@ -2441,7 +2466,7 @@ MySqlHostDataSource::getAll4(const asiolink::IOAddress& address) const { MYSQL_BIND inbind[1]; memset(inbind, 0, sizeof(inbind)); - uint32_t addr4 = static_cast(address); + uint32_t addr4 = address.toUint32(); inbind[0].buffer_type = MYSQL_TYPE_LONG; inbind[0].buffer = reinterpret_cast(&addr4); inbind[0].is_unsigned = MLM_TRUE; @@ -2504,7 +2529,7 @@ MySqlHostDataSource::get4(const SubnetID& subnet_id, inbind[0].buffer = reinterpret_cast(&subnet); inbind[0].is_unsigned = MLM_TRUE; - uint32_t addr4 = static_cast(address); + uint32_t addr4 = address.toUint32(); inbind[1].buffer_type = MYSQL_TYPE_LONG; inbind[1].buffer = reinterpret_cast(&addr4); inbind[1].is_unsigned = MLM_TRUE; @@ -2597,6 +2622,42 @@ MySqlHostDataSource::get6(const asiolink::IOAddress& prefix, return (result); } +ConstHostPtr +MySqlHostDataSource::get6(const SubnetID& subnet_id, + const asiolink::IOAddress& address) const { + // Set up the WHERE clause value + MYSQL_BIND inbind[2]; + memset(inbind, 0, sizeof(inbind)); + + uint32_t subnet_buffer = static_cast(subnet_id); + inbind[0].buffer_type = MYSQL_TYPE_LONG; + inbind[0].buffer = reinterpret_cast(&subnet_buffer); + inbind[0].is_unsigned = MLM_TRUE; + + std::string addr6 = address.toText(); + unsigned long addr6_length = addr6.size(); + + inbind[1].buffer_type = MYSQL_TYPE_BLOB; + inbind[1].buffer = reinterpret_cast + (const_cast(addr6.c_str())); + inbind[1].length = &addr6_length; + inbind[1].buffer_length = addr6_length; + + ConstHostCollection collection; + impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR, + inbind, impl_->host_ipv6_exchange_, + collection, true); + + // Return single record if present, else clear the host. + ConstHostPtr result; + if (!collection.empty()) { + result = *collection.begin(); + } + + return (result); +} + + // Miscellaneous database methods. std::string MySqlHostDataSource::getName() const { diff --git a/src/lib/dhcpsrv/mysql_host_data_source.h b/src/lib/dhcpsrv/mysql_host_data_source.h index d5e56949a0..fe7a592037 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.h +++ b/src/lib/dhcpsrv/mysql_host_data_source.h @@ -198,6 +198,16 @@ public: virtual ConstHostPtr get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const; + /// @brief Returns a host connected to the IPv6 subnet and having + /// a reservation for a specified IPv6 address or prefix. + /// + /// @param subnet_id Subnet identifier. + /// @param address reserved IPv6 address/prefix. + /// + /// @return Const @c Host object using a specified IPv6 address/prefix. + virtual ConstHostPtr + get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const; + /// @brief Adds a new host to the collection. /// /// The implementations of this method should guard against duplicate diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index 262c0d68fd..570e611dd0 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -361,7 +361,7 @@ public: // Address: uint32_t // The address in the Lease structure is an IOAddress object. Convert // this to an integer for storage. - addr4_ = static_cast(lease_->addr_); + addr4_ = lease_->addr_.toUint32(); bind_[0].buffer_type = MYSQL_TYPE_LONG; bind_[0].buffer = reinterpret_cast(&addr4_); bind_[0].is_unsigned = MLM_TRUE; @@ -1596,7 +1596,7 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { MYSQL_BIND inbind[1]; memset(inbind, 0, sizeof(inbind)); - uint32_t addr4 = static_cast(addr); + uint32_t addr4 = addr.toUint32(); inbind[0].buffer_type = MYSQL_TYPE_LONG; inbind[0].buffer = reinterpret_cast(&addr4); inbind[0].is_unsigned = MLM_TRUE; @@ -1960,7 +1960,7 @@ MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { MYSQL_BIND where; memset(&where, 0, sizeof(where)); - uint32_t addr4 = static_cast(lease->addr_); + uint32_t addr4 = lease->addr_.toUint32(); where.buffer_type = MYSQL_TYPE_LONG; where.buffer = reinterpret_cast(&addr4); where.is_unsigned = MLM_TRUE; @@ -2032,7 +2032,7 @@ MySqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) { memset(inbind, 0, sizeof(inbind)); if (addr.isV4()) { - uint32_t addr4 = static_cast(addr); + uint32_t addr4 = addr.toUint32(); inbind[0].buffer_type = MYSQL_TYPE_LONG; inbind[0].buffer = reinterpret_cast(&addr4); diff --git a/src/lib/dhcpsrv/pgsql_exchange.cc b/src/lib/dhcpsrv/pgsql_exchange.cc index dc38e98638..259dfadbcb 100644 --- a/src/lib/dhcpsrv/pgsql_exchange.cc +++ b/src/lib/dhcpsrv/pgsql_exchange.cc @@ -66,7 +66,7 @@ void PsqlBindArray::add(const uint8_t& byte) { void PsqlBindArray::add(const isc::asiolink::IOAddress& addr) { if (addr.isV4()) { addTempString(boost::lexical_cast - (static_cast(addr))); + (addr.toUint32())); } else { addTempString(addr.toText()); } diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index c3f0a63830..f1b4295219 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -1148,6 +1148,7 @@ public: GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address GET_HOST_PREFIX, // Gets host by IPv6 prefix + GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix GET_VERSION, // Obtain version number INSERT_HOST, // Insert new host to collection INSERT_V6_RESRV, // Insert v6 reservation @@ -1454,6 +1455,32 @@ TaggedStatementArray tagged_statements = { { "ORDER BY h.host_id, o.option_id, r.reservation_id" }, + // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR + // Retrieves host information, IPv6 reservations and DHCPv6 options + // associated with a host using IPv6 subnet id and prefix. This query + // returns host information for a single host. However, multiple rows + // are returned due to left joining IPv6 reservations and DHCPv6 options. + // The number of rows returned is multiplication of number of existing + // IPv6 reservations and DHCPv6 options. + {2, + { OID_INT4, OID_VARCHAR }, + "get_host_subid6_addr", + "SELECT h.host_id, h.dhcp_identifier, " + " h.dhcp_identifier_type, h.dhcp4_subnet_id, " + " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " + " h.dhcp4_client_classes, h.dhcp6_client_classes, " + " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " + " o.option_id, o.code, o.value, o.formatted_value, o.space, " + " o.persistent, " + " r.reservation_id, r.address, r.prefix_len, r.type, " + " r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " + "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " + "WHERE h.dhcp6_subnet_id = $1 AND r.address = $2 " + "ORDER BY h.host_id, o.option_id, r.reservation_id" + }, + // PgSqlHostDataSourceImpl::GET_VERSION // Retrieves MySQL schema version. {0, @@ -1955,6 +1982,34 @@ PgSqlHostDataSource::get6(const asiolink::IOAddress& prefix, return (result); } +ConstHostPtr +PgSqlHostDataSource::get6(const SubnetID& subnet_id, + const asiolink::IOAddress& address) const { + /// @todo: Check that prefix is v6 address, not v4. + + // Set up the WHERE clause value + PsqlBindArrayPtr bind_array(new PsqlBindArray()); + + // Add the subnet id + bind_array->add(subnet_id); + + // Add the prefix + bind_array->add(address); + + ConstHostCollection collection; + impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR, + bind_array, impl_->host_ipv6_exchange_, + collection, true); + + // Return single record if present, else clear the host. + ConstHostPtr result; + if (!collection.empty()) { + result = *collection.begin(); + } + + return (result); +} + // Miscellaneous database methods. std::string PgSqlHostDataSource::getName() const { diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.h b/src/lib/dhcpsrv/pgsql_host_data_source.h index 40ad840c86..846ac0f140 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.h +++ b/src/lib/dhcpsrv/pgsql_host_data_source.h @@ -206,6 +206,16 @@ public: virtual ConstHostPtr get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const; + /// @brief Returns a host connected to the IPv6 subnet and having + /// a reservation for a specified IPv6 address or prefix. + /// + /// @param subnet_id Subnet identifier. + /// @param address reserved IPv6 address/prefix. + /// + /// @return Const @c Host object using a specified IPv6 address/prefix. + virtual ConstHostPtr + get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const; + /// @brief Adds a new host to the collection. /// /// The method will insert the given host and all of its children (v4 diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 349f3852e1..ddcb8cc520 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -328,7 +328,7 @@ public: try { addr_str_ = boost::lexical_cast - (static_cast(lease->addr_)); + (lease->addr_.toUint32()); bind_array.add(addr_str_); if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) { @@ -955,7 +955,7 @@ PgSqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { // LEASE ADDRESS std::string addr_str = boost::lexical_cast - (static_cast(addr)); + (addr.toUint32()); bind_array.add(addr_str); // Get the data @@ -1241,7 +1241,7 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { // Set up the WHERE clause and append it to the SQL_BIND array std::string addr4_ = boost::lexical_cast - (static_cast(lease->addr_)); + (lease->addr_.toUint32()); bind_array.add(addr4_); // Drop to common update code @@ -1292,7 +1292,7 @@ PgSqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) { if (addr.isV4()) { std::string addr4_str = boost::lexical_cast - (static_cast(addr)); + (addr.toUint32()); bind_array.add(addr4_str); return (deleteLeaseCommon(DELETE_LEASE4, bind_array) > 0); } diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc index 515b6757b3..ba624209ee 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc @@ -1003,6 +1003,46 @@ void GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id, EXPECT_FALSE(hdsptr_->get6(IOAddress("2001:db8::5"), len)); } +void GenericHostDataSourceTest::testGetBySubnetIPv6() { + // Make sure we have a pointer to the host data source. + ASSERT_TRUE(hdsptr_); + + // Let's create a couple of hosts... + HostPtr host1 = initializeHost6("2001:db8:1::", Host::IDENT_DUID, true); + HostPtr host2 = initializeHost6("2001:db8:2::", Host::IDENT_DUID, true); + HostPtr host3 = initializeHost6("2001:db8:3::", Host::IDENT_DUID, true); + HostPtr host4 = initializeHost6("2001:db8:4::", Host::IDENT_DUID, true); + + // ... and add them to the data source. + ASSERT_NO_THROW(hdsptr_->add(host1)); + ASSERT_NO_THROW(hdsptr_->add(host2)); + ASSERT_NO_THROW(hdsptr_->add(host3)); + ASSERT_NO_THROW(hdsptr_->add(host4)); + + // And then try to retrieve them back. + ConstHostPtr from_hds1 = hdsptr_->get6(host1->getIPv6SubnetID(), + IOAddress("2001:db8:1::")); + ConstHostPtr from_hds2 = hdsptr_->get6(host2->getIPv6SubnetID(), + IOAddress("2001:db8:2::")); + ConstHostPtr from_hds3 = hdsptr_->get6(host3->getIPv6SubnetID(), + IOAddress("2001:db8:3::")); + ConstHostPtr from_hds4 = hdsptr_->get6(host4->getIPv6SubnetID(), + IOAddress("2001:db8:4::")); + + // Make sure we got something back. + ASSERT_TRUE(from_hds1); + ASSERT_TRUE(from_hds2); + ASSERT_TRUE(from_hds3); + ASSERT_TRUE(from_hds4); + + // Then let's check that what we got seems correct. + compareHosts(host1, from_hds1); + compareHosts(host2, from_hds2); + compareHosts(host3, from_hds3); + compareHosts(host4, from_hds4); +} + + void GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h index 807ca21490..f84638bb83 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h @@ -418,6 +418,11 @@ public: /// @param prefix true - reserve IPv6 prefix, false - reserve IPv6 address void testGetByIPv6(Host::IdentifierType id, bool prefix); + /// @brief Test inserts several hosts with unique prefixes and checks + /// that the can be retrieved by subnet id and prefix value. + void testGetBySubnetIPv6(); + + /// @brief Test that hosts can be retrieved by hardware address. /// /// Uses gtest macros to report failures. diff --git a/src/lib/dhcpsrv/tests/lease_unittest.cc b/src/lib/dhcpsrv/tests/lease_unittest.cc index 979b965326..e3c3ac1b7c 100644 --- a/src/lib/dhcpsrv/tests/lease_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_unittest.cc @@ -83,7 +83,7 @@ TEST_F(Lease4Test, constructor) { current_time, SUBNET_ID, true, true, "hostname.example.com."); - EXPECT_EQ(ADDRESS[i], static_cast(lease.addr_)); + EXPECT_EQ(ADDRESS[i], lease.addr_.toUint32()); EXPECT_TRUE(util::equalValues(hwaddr_, lease.hwaddr_)); EXPECT_TRUE(util::equalValues(clientid_, lease.client_id_)); EXPECT_EQ(0, lease.t1_); diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index 60359afd89..c6dbffd684 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -335,6 +335,12 @@ TEST_F(MySqlHostDataSourceTest, get6PrefixWithHWaddr) { testGetByIPv6(Host::IDENT_HWADDR, true); } +// Test verifies that host with IPv6 prefix reservation can be retrieved +// by subnet id and prefix value. +TEST_F(MySqlHostDataSourceTest, get6SubnetPrefix) { + testGetBySubnetIPv6(); +} + // Test verifies if a host reservation can be added and later retrieved by // hardware address. TEST_F(MySqlHostDataSourceTest, get6ByHWaddr) { diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index b5456bfb8e..4f7b794887 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -292,6 +292,12 @@ TEST_F(PgSqlHostDataSourceTest, get6PrefixWithHWaddr) { testGetByIPv6(Host::IDENT_HWADDR, true); } +// Test verifies that host with IPv6 prefix reservation can be retrieved +// by subnet id and prefix value. +TEST_F(PgSqlHostDataSourceTest, get6SubnetPrefix) { + testGetBySubnetIPv6(); +} + // Test verifies if a host reservation can be added and later retrieved by // hardware address. TEST_F(PgSqlHostDataSourceTest, get6ByHWaddr) { diff --git a/src/lib/dhcpsrv/writable_host_data_source.h b/src/lib/dhcpsrv/writable_host_data_source.h index e30d36ef8c..2304a5370b 100644 --- a/src/lib/dhcpsrv/writable_host_data_source.h +++ b/src/lib/dhcpsrv/writable_host_data_source.h @@ -141,6 +141,15 @@ public: virtual HostPtr get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) = 0; + /// @brief Returns a host connected to the IPv6 subnet and having + /// a reservation for a specified IPv6 address or prefix. + /// + /// @param subnet_id Subnet identifier. + /// @param address reserved IPv6 address/prefix. + /// + /// @return @c Host object using a specified IPv6 address/prefix. + virtual HostPtr + get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) = 0; }; }