From: Thomas Markwalder Date: Wed, 25 Apr 2018 18:47:21 +0000 (-0400) Subject: [5535] dhcpsrv now supports multiple relay addresses in RelayInfo X-Git-Tag: trac5549_base~1^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e362be0644a58f873176343ce1f016a4b0fd58a;p=thirdparty%2Fkea.git [5535] dhcpsrv now supports multiple relay addresses in RelayInfo src/lib/dhcpsrv/network.* Network::RelayInfo - modified to support a list of IP addresses - added methods: addAddress(const asiolink::IOAddress& addr) bool hasAddresses() bool containsAddress(const asiolink::IOAddress& addr) +const IOAddressList& getAddresses() Network - added wrapper methods for convenience: addRelayAddress(const asiolink::IOAddress& addr) bool hasRelays() bool hasRelayAddress(const asiolink::IOAddress& addr) const IOAddressList& getRelayAddresses() - toElement() - modified to output ip-addresses list Updated the following accordingly: src/lib/dhcpsrv/cfg_subnets4.cc src/lib/dhcpsrv/cfg_subnets6.cc src/lib/dhcpsrv/parsers/dhcp_parsers.cc src/lib/dhcpsrv/subnet.cc src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc src/lib/dhcpsrv/tests/shared_network_unittest.cc src/lib/dhcpsrv/tests/subnet_unittest.cc --- diff --git a/src/lib/dhcpsrv/cfg_subnets4.cc b/src/lib/dhcpsrv/cfg_subnets4.cc index 0e47c6d0fc..21c188ae30 100644 --- a/src/lib/dhcpsrv/cfg_subnets4.cc +++ b/src/lib/dhcpsrv/cfg_subnets4.cc @@ -137,17 +137,16 @@ CfgSubnets4::selectSubnet(const SubnetSelector& selector) const { // If relay information is specified for this subnet, it must match. // Otherwise, we ignore this subnet. - if (!(*subnet)->getRelayInfo().addr_.isV4Zero()) { - if (selector.giaddr_ != (*subnet)->getRelayInfo().addr_) { + if ((*subnet)->hasRelays()) { + if (!(*subnet)->hasRelayAddress(selector.giaddr_)) { continue; } - } else { // Relay information is not specified on the subnet level, // so let's try matching on the shared network level. SharedNetwork4Ptr network; (*subnet)->getSharedNetwork(network); - if (!network || (selector.giaddr_ != network->getRelayInfo().addr_)) { + if (!network || !(network->hasRelayAddress(selector.giaddr_))) { continue; } } diff --git a/src/lib/dhcpsrv/cfg_subnets6.cc b/src/lib/dhcpsrv/cfg_subnets6.cc index e35b3773d4..9db6aa4fee 100644 --- a/src/lib/dhcpsrv/cfg_subnets6.cc +++ b/src/lib/dhcpsrv/cfg_subnets6.cc @@ -116,16 +116,17 @@ CfgSubnets6::selectSubnet(const asiolink::IOAddress& address, for (Subnet6Collection::const_iterator subnet = subnets_.begin(); subnet != subnets_.end(); ++subnet) { - // If the specified address matches the relay address, return this + // If the specified address matches a relay address, return this // subnet. if (is_relay_address && - ((*subnet)->getRelayInfo().addr_ == address) && + ((*subnet)->hasRelayAddress(address)) && (*subnet)->clientSupported(client_classes)) { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_SUBNET6_RELAY) .arg((*subnet)->toText()).arg(address.toText()); return (*subnet); } + } } diff --git a/src/lib/dhcpsrv/network.cc b/src/lib/dhcpsrv/network.cc index 1071ec3096..7493b046d6 100644 --- a/src/lib/dhcpsrv/network.cc +++ b/src/lib/dhcpsrv/network.cc @@ -16,8 +16,56 @@ using namespace isc::data; namespace isc { namespace dhcp { -Network::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr) - :addr_(addr) { +void +Network::RelayInfo::addAddress(const asiolink::IOAddress& addr) { + if (containsAddress(addr)) { + isc_throw (BadValue, "RelayInfo already contains address: " + << addr.toText()); + } + + addresses_.push_back(addr); +} + +bool +Network::RelayInfo::hasAddresses() const { + return (addresses_.size() > 0); +} + +bool +Network::RelayInfo::containsAddress(const asiolink::IOAddress& addr) const { + for (auto address = addresses_.begin(); address != addresses_.end(); + ++address) { + if ((*address) == addr) { + return (true); + } + } + + return (false); +} + +const IOAddressList& +Network::RelayInfo::getAddresses() const { + return (addresses_); +} + +void +Network::addRelayAddress(const asiolink::IOAddress& addr) { + relay_.addAddress(addr); +} + +bool +Network::hasRelays() const { + return (relay_.hasAddresses()); +} + +bool +Network::hasRelayAddress(const asiolink::IOAddress& addr) const { + return (relay_.containsAddress(addr)); +} + +const IOAddressList& +Network::getRelayAddresses() const { + return (relay_.getAddresses()); } bool @@ -61,11 +109,15 @@ Network::toElement() const { map->set("interface", Element::create(iface)); } - // Set relay info - const RelayInfo& relay_info = getRelayInfo(); - ElementPtr relay = Element::createMap(); - relay->set("ip-address", Element::create(relay_info.addr_.toText())); - map->set("relay", relay); + ElementPtr relay_map = Element::createMap(); + ElementPtr address_list = Element::createList(); + const IOAddressList addresses = getRelayAddresses(); + for (auto address = addresses.begin(); address != addresses.end(); ++address) { + address_list->add(Element::create((*address).toText())); + } + + relay_map->set("ip-addresses", address_list); + map->set("relay", relay_map); // Set client-class const ClientClass& cclass = getClientClass(); diff --git a/src/lib/dhcpsrv/network.h b/src/lib/dhcpsrv/network.h index 815826a0e7..161afedc45 100644 --- a/src/lib/dhcpsrv/network.h +++ b/src/lib/dhcpsrv/network.h @@ -24,6 +24,9 @@ namespace isc { namespace dhcp { +/// List of IOAddresses +typedef std::vector IOAddressList; + /// @brief Common interface representing a network to which the DHCP clients /// are connected. /// @@ -44,24 +47,42 @@ namespace dhcp { /// derived classes. class Network : public virtual UserContext, public data::CfgToElement { public: - /// @brief Holds optional information about relay. /// /// In some cases it is beneficial to have additional information about /// a relay configured in the subnet. For now, the structure holds only - /// IP address, but there may potentially be additional parameters added + /// IP addresses, but there may potentially be additional parameters added /// later, e.g. relay interface-id or relay-id. - struct RelayInfo { + class RelayInfo { + public: - /// @brief default and the only constructor + /// @brief Adds an address to the list of addresses /// - /// @param addr an IP address of the relay (may be :: or 0.0.0.0) - RelayInfo(const isc::asiolink::IOAddress& addr); + /// @param addr address to add + /// @throw BadValue if the address is already in the list + void addAddress(const asiolink::IOAddress& addr); - /// @brief IP address of the relay - isc::asiolink::IOAddress addr_; + /// @brief Returns const reference to the list of addresses + /// + /// @return const reference to the list of addresses + const IOAddressList& getAddresses() const; + + /// @brief Indicates whether or not the address list has entries + /// + /// @return True if the address list is not empty + bool hasAddresses() const; + + /// @brief Checks the address list for the given address + /// + /// @return True if the address is found in the address list + bool containsAddress(const asiolink::IOAddress& addr) const; + + private: + /// @brief List of relay IP addresses + IOAddressList addresses_; }; + /// @brief Specifies allowed host reservation mode. /// typedef enum { @@ -88,8 +109,7 @@ public: /// @brief Constructor. Network() - : iface_name_(), relay_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()), - client_class_(""), t1_(0), t2_(0), valid_(0), + : iface_name_(), client_class_(""), t1_(0), t2_(0), valid_(0), host_reservation_mode_(HR_ALL), cfg_option_(new CfgOption()) { } @@ -151,6 +171,28 @@ public: return (relay_); } + /// @brief Adds an address to the list addresses in the network's relay info + /// + /// @param addr address of the relay + /// @throw BadValue if the address is already in the list + void addRelayAddress(const asiolink::IOAddress& addr); + + /// @brief Returns the list of relay addresses from the network's relay info + /// + /// @return const reference to the list of addresses + const IOAddressList& getRelayAddresses() const; + + /// @brief Indicates if network's relay info has relay addresses + /// + /// @return True the relay list is not empty, false otherwise + bool hasRelays() const; + + /// @brief Tests if the network's relay info contains the given address + /// + /// @param address address to search for in the relay list + /// @return True if a relay with the given address is found, false otherwise + bool hasRelayAddress(const asiolink::IOAddress& address) const; + /// @brief Checks whether this network supports client that belongs to /// specified classes. /// @@ -363,7 +405,6 @@ public: /// @brief Constructor. Network6() : Network(), preferred_(0), interface_id_(), rapid_commit_(false) { - setRelayInfo(asiolink::IOAddress::IPV6_ZERO_ADDRESS()); } /// @brief Returns preferred lifetime (in seconds) diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 8b3f2efdcd..961a5334a5 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -249,7 +249,8 @@ RelayInfoParser::parse(const isc::dhcp::Network::RelayInfoPtr& cfg, // Ok, we're done with parsing. Let's store the result in the structure // we were given as configuration storage. - *cfg = isc::dhcp::Network::RelayInfo(ip); + *cfg = isc::dhcp::Network::RelayInfo(); + cfg->addAddress(ip); } //****************************** PoolParser ******************************** @@ -431,8 +432,7 @@ SubnetConfigParser::SubnetConfigParser(uint16_t family) : pools_(new PoolStorage()), address_family_(family), options_(new CfgOption()) { - string addr = family == AF_INET ? "0.0.0.0" : "::"; - relay_info_.reset(new isc::dhcp::Network::RelayInfo(IOAddress(addr))); + relay_info_.reset(new isc::dhcp::Network::RelayInfo()); } SubnetPtr @@ -991,7 +991,6 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) { sn6ptr->setRelayInfo(*relay_info_); } - // Parse Host Reservations for this subnet if any. ConstElementPtr reservations = subnet->get("reservations"); if (reservations) { diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc index 1e25f15714..ae4aefe306 100644 --- a/src/lib/dhcpsrv/subnet.cc +++ b/src/lib/dhcpsrv/subnet.cc @@ -231,8 +231,7 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length, isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText() << " specified in subnet4"); } - // Relay info. - setRelayInfo(IOAddress::IPV4_ZERO_ADDRESS()); + // Timers. setT1(t1); setT2(t2); @@ -602,8 +601,6 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length, << " specified in subnet6"); } - // Relay info. - setRelayInfo(RelayInfo(IOAddress::IPV6_ZERO_ADDRESS())); // Timers. setT1(t1); setT2(t2); diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc index cd82ab3797..80896223ec 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc @@ -111,6 +111,9 @@ TEST(CfgSharedNetworks4Test, unparse) { SharedNetwork4Ptr network2(new SharedNetwork4("dog")); network1->setIface("eth0"); + network1->addRelayAddress(IOAddress("198.16.1.1")); + network1->addRelayAddress(IOAddress("198.16.1.2")); + network2->setIface("eth1"); CfgSharedNetworks4 cfg; @@ -125,9 +128,7 @@ TEST(CfgSharedNetworks4Test, unparse) { " \"name\": \"dog\",\n" " \"option-data\": [ ],\n" " \"rebind-timer\": 0,\n" - " \"relay\": {\n" - " \"ip-address\": \"0.0.0.0\"\n" - " },\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"renew-timer\": 0,\n" " \"reservation-mode\": \"all\"," " \"subnet4\": [ ],\n" @@ -139,9 +140,7 @@ TEST(CfgSharedNetworks4Test, unparse) { " \"name\": \"frog\",\n" " \"option-data\": [ ],\n" " \"rebind-timer\": 0,\n" - " \"relay\": {\n" - " \"ip-address\": \"0.0.0.0\"\n" - " },\n" + " \"relay\": { \"ip-addresses\": [ \"198.16.1.1\", \"198.16.1.2\" ] },\n" " \"renew-timer\": 0,\n" " \"reservation-mode\": \"all\"," " \"subnet4\": [ ],\n" diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc index 92e84ad3d9..f24069c744 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc @@ -111,6 +111,8 @@ TEST(CfgSharedNetworks6Test, unparse) { SharedNetwork6Ptr network2(new SharedNetwork6("dog")); network1->setIface("eth0"); + network1->addRelayAddress(IOAddress("2001:db8:1::1")); + network1->addRelayAddress(IOAddress("2001:db8:1::2")); network2->setIface("eth1"); CfgSharedNetworks6 cfg; @@ -126,9 +128,7 @@ TEST(CfgSharedNetworks6Test, unparse) { " \"preferred-lifetime\": 0,\n" " \"rapid-commit\": false,\n" " \"rebind-timer\": 0,\n" - " \"relay\": {\n" - " \"ip-address\": \"::\"\n" - " },\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"renew-timer\": 0,\n" " \"reservation-mode\": \"all\"," " \"subnet6\": [ ],\n" @@ -141,9 +141,7 @@ TEST(CfgSharedNetworks6Test, unparse) { " \"preferred-lifetime\": 0,\n" " \"rapid-commit\": false,\n" " \"rebind-timer\": 0,\n" - " \"relay\": {\n" - " \"ip-address\": \"::\"\n" - " },\n" + " \"relay\": { \"ip-addresses\": [ \"2001:db8:1::1\", \"2001:db8:1::2\" ] },\n" " \"renew-timer\": 0,\n" " \"reservation-mode\": \"all\"," " \"subnet6\": [ ],\n" diff --git a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc index 6cd404aed5..c02b4f5247 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc @@ -414,7 +414,7 @@ TEST(CfgSubnets4Test, selectSubnetByOptionSelect) { // Over relay-info too selector.giaddr_ = IOAddress("10.0.0.1"); - subnet2->setRelayInfo(IOAddress("10.0.0.1")); + subnet2->addRelayAddress(IOAddress("10.0.0.1")); EXPECT_EQ(subnet3, cfg.selectSubnet(selector)); selector.option_select_ = IOAddress("0.0.0.0"); EXPECT_EQ(subnet2, cfg.selectSubnet(selector)); @@ -450,9 +450,9 @@ TEST(CfgSubnets4Test, selectSubnetByRelayAddress) { EXPECT_FALSE(cfg.selectSubnet(selector)); // Now specify relay info - subnet1->setRelayInfo(IOAddress("10.0.0.1")); - subnet2->setRelayInfo(IOAddress("10.0.0.2")); - subnet3->setRelayInfo(IOAddress("10.0.0.3")); + subnet1->addRelayAddress(IOAddress("10.0.0.1")); + subnet2->addRelayAddress(IOAddress("10.0.0.2")); + subnet3->addRelayAddress(IOAddress("10.0.0.3")); // And try again. This time relay-info is there and should match. selector.giaddr_ = IOAddress("10.0.0.1"); @@ -485,9 +485,9 @@ TEST(CfgSubnets4Test, selectSharedNetworkByRelayAddressNetworkLevel) { // Now specify relay info. Note that for the second subnet we specify // relay info on the network level. - subnet1->setRelayInfo(IOAddress("10.0.0.1")); - network->setRelayInfo(IOAddress("10.0.0.2")); - subnet3->setRelayInfo(IOAddress("10.0.0.3")); + subnet1->addRelayAddress(IOAddress("10.0.0.1")); + network->addRelayAddress(IOAddress("10.0.0.2")); + subnet3->addRelayAddress(IOAddress("10.0.0.3")); // And try again. This time relay-info is there and should match. selector.giaddr_ = IOAddress("10.0.0.1"); @@ -524,9 +524,9 @@ TEST(CfgSubnets4Test, selectSharedNetworkByRelayAddressSubnetLevel) { // Now specify relay info. Note that for the second subnet we specify // relay info on the network level. - subnet1->setRelayInfo(IOAddress("10.0.0.1")); - subnet2->setRelayInfo(IOAddress("10.0.0.2")); - subnet3->setRelayInfo(IOAddress("10.0.0.3")); + subnet1->addRelayAddress(IOAddress("10.0.0.1")); + subnet2->addRelayAddress(IOAddress("10.0.0.2")); + subnet3->addRelayAddress(IOAddress("10.0.0.3")); // And try again. This time relay-info is there and should match. selector.giaddr_ = IOAddress("10.0.0.1"); @@ -737,7 +737,7 @@ TEST(CfgSubnets4Test, unparseSubnet) { Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3, 125)); subnet1->allowClientClass("foo"); subnet2->setIface("lo"); - subnet2->setRelayInfo(IOAddress("10.0.0.1")); + subnet2->addRelayAddress(IOAddress("10.0.0.1")); subnet3->setIface("eth1"); subnet3->requireClientClass("foo"); subnet3->requireClientClass("bar"); @@ -757,13 +757,13 @@ TEST(CfgSubnets4Test, unparseSubnet) { " \"comment\": \"foo\",\n" " \"id\": 123,\n" " \"subnet\": \"192.0.2.0/26\",\n" - " \"relay\": { \"ip-address\": \"0.0.0.0\" },\n" " \"match-client-id\": true,\n" " \"next-server\": \"0.0.0.0\",\n" " \"server-hostname\": \"\",\n" " \"boot-file-name\": \"\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"valid-lifetime\": 3,\n" " \"client-class\": \"foo\",\n" " \"4o6-interface\": \"\",\n" @@ -775,7 +775,6 @@ TEST(CfgSubnets4Test, unparseSubnet) { "},{\n" " \"id\": 124,\n" " \"subnet\": \"192.0.2.64/26\",\n" - " \"relay\": { \"ip-address\": \"10.0.0.1\" },\n" " \"interface\": \"lo\",\n" " \"match-client-id\": true,\n" " \"next-server\": \"0.0.0.0\",\n" @@ -783,6 +782,7 @@ TEST(CfgSubnets4Test, unparseSubnet) { " \"boot-file-name\": \"\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ \"10.0.0.1\" ] },\n" " \"valid-lifetime\": 3,\n" " \"4o6-interface\": \"\",\n" " \"4o6-interface-id\": \"\",\n" @@ -794,7 +794,6 @@ TEST(CfgSubnets4Test, unparseSubnet) { "},{\n" " \"id\": 125,\n" " \"subnet\": \"192.0.2.128/26\",\n" - " \"relay\": { \"ip-address\": \"0.0.0.0\" },\n" " \"interface\": \"eth1\",\n" " \"match-client-id\": true,\n" " \"next-server\": \"0.0.0.0\",\n" @@ -802,6 +801,7 @@ TEST(CfgSubnets4Test, unparseSubnet) { " \"boot-file-name\": \"\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"valid-lifetime\": 3,\n" " \"4o6-interface\": \"\",\n" " \"4o6-interface-id\": \"\",\n" @@ -840,13 +840,13 @@ TEST(CfgSubnets4Test, unparsePool) { "{\n" " \"id\": 123,\n" " \"subnet\": \"192.0.2.0/24\",\n" - " \"relay\": { \"ip-address\": \"0.0.0.0\" },\n" " \"match-client-id\": true,\n" " \"next-server\": \"0.0.0.0\",\n" " \"server-hostname\": \"\",\n" " \"boot-file-name\": \"\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"valid-lifetime\": 3,\n" " \"4o6-interface\": \"\",\n" " \"4o6-interface-id\": \"\",\n" diff --git a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc index c9dd4b0fd0..f640299b5e 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc @@ -132,9 +132,9 @@ TEST(CfgSubnets6Test, selectSubnetByRelayAddress) { EXPECT_FALSE(cfg.selectSubnet(selector)); // Now specify relay information. - subnet1->setRelayInfo(IOAddress("2001:db8:ff::1")); - subnet2->setRelayInfo(IOAddress("2001:db8:ff::2")); - subnet3->setRelayInfo(IOAddress("2001:db8:ff::3")); + subnet1->addRelayAddress(IOAddress("2001:db8:ff::1")); + subnet2->addRelayAddress(IOAddress("2001:db8:ff::2")); + subnet3->addRelayAddress(IOAddress("2001:db8:ff::3")); // And try again. This time relay-info is there and should match. selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::1"); @@ -436,7 +436,7 @@ TEST(CfgSubnets6Test, unparseSubnet) { subnet1->setInterfaceId(ifaceid); subnet1->allowClientClass("foo"); subnet2->setIface("lo"); - subnet2->setRelayInfo(IOAddress("2001:db8:ff::2")); + subnet2->addRelayAddress(IOAddress("2001:db8:ff::2")); subnet3->setIface("eth1"); subnet3->requireClientClass("foo"); subnet3->requireClientClass("bar"); @@ -456,10 +456,10 @@ TEST(CfgSubnets6Test, unparseSubnet) { " \"comment\": \"foo\",\n" " \"id\": 123,\n" " \"subnet\": \"2001:db8:1::/48\",\n" - " \"relay\": { \"ip-address\": \"::\" },\n" " \"interface-id\": \"relay.eth0\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"preferred-lifetime\": 3,\n" " \"valid-lifetime\": 4,\n" " \"rapid-commit\": false,\n" @@ -471,10 +471,10 @@ TEST(CfgSubnets6Test, unparseSubnet) { "},{\n" " \"id\": 124,\n" " \"subnet\": \"2001:db8:2::/48\",\n" - " \"relay\": { \"ip-address\": \"2001:db8:ff::2\" },\n" " \"interface\": \"lo\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ \"2001:db8:ff::2\" ] },\n" " \"preferred-lifetime\": 3,\n" " \"valid-lifetime\": 4,\n" " \"rapid-commit\": false,\n" @@ -486,10 +486,10 @@ TEST(CfgSubnets6Test, unparseSubnet) { "},{\n" " \"id\": 125,\n" " \"subnet\": \"2001:db8:3::/48\",\n" - " \"relay\": { \"ip-address\": \"::\" },\n" " \"interface\": \"eth1\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"preferred-lifetime\": 3,\n" " \"valid-lifetime\": 4,\n" " \"rapid-commit\": false,\n" @@ -531,9 +531,9 @@ TEST(CfgSubnets6Test, unparsePool) { "{\n" " \"id\": 123,\n" " \"subnet\": \"2001:db8:1::/48\",\n" - " \"relay\": { \"ip-address\": \"::\" },\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"preferred-lifetime\": 3,\n" " \"valid-lifetime\": 4,\n" " \"rapid-commit\": false,\n" @@ -586,9 +586,9 @@ TEST(CfgSubnets6Test, unparsePdPool) { "{\n" " \"id\": 123,\n" " \"subnet\": \"2001:db8:1::/48\",\n" - " \"relay\": { \"ip-address\": \"::\" },\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" " \"preferred-lifetime\": 3,\n" " \"valid-lifetime\": 4,\n" " \"rapid-commit\": false,\n" diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc index d79d6d2877..4651d504bb 100644 --- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc @@ -2220,14 +2220,13 @@ TEST_F(ParseConfigTest, validRelayInfo4) { " }"; ElementPtr json = Element::fromJSON(config_str); - // We need to set the default ip-address to something. - Network::RelayInfoPtr result(new Network::RelayInfo(asiolink::IOAddress("0.0.0.0"))); + // Create an "empty" RelayInfo to hold the parsed result. + Network::RelayInfoPtr result(new Network::RelayInfo()); RelayInfoParser parser(Option::V4); - // Subnet4 parser will pass 0.0.0.0 to the RelayInfoParser EXPECT_NO_THROW(parser.parse(result, json)); - EXPECT_EQ("192.0.2.1", result->addr_.toText()); + EXPECT_TRUE(result->containsAddress(IOAddress("192.0.2.1"))); } /// @brief Checks that a bogus relay info structure for IPv4 is rejected. @@ -2253,8 +2252,8 @@ TEST_F(ParseConfigTest, bogusRelayInfo4) { " }"; ElementPtr json_bogus3 = Element::fromJSON(config_str_bogus3); - // We need to set the default ip-address to something. - Network::RelayInfoPtr result(new Network::RelayInfo(IOAddress::IPV4_ZERO_ADDRESS())); + // Create an "empty" RelayInfo to hold the parsed result. + Network::RelayInfoPtr result(new Network::RelayInfo()); RelayInfoParser parser(Option::V4); @@ -2278,13 +2277,13 @@ TEST_F(ParseConfigTest, validRelayInfo6) { " }"; ElementPtr json = Element::fromJSON(config_str); - // We need to set the default ip-address to something. - Network::RelayInfoPtr result(new Network::RelayInfo(asiolink::IOAddress("::"))); + // Create an "empty" RelayInfo to hold the parsed result. + Network::RelayInfoPtr result(new Network::RelayInfo()); RelayInfoParser parser(Option::V6); - // Subnet4 parser will pass :: to the RelayInfoParser + EXPECT_NO_THROW(parser.parse(result, json)); - EXPECT_EQ("2001:db8::1", result->addr_.toText()); + EXPECT_TRUE(result->containsAddress(IOAddress("2001:db8::1"))); } /// @brief Checks that a valid relay info structure for IPv6 can be handled @@ -2310,8 +2309,8 @@ TEST_F(ParseConfigTest, bogusRelayInfo6) { " }"; ElementPtr json_bogus3 = Element::fromJSON(config_str_bogus3); - // We need to set the default ip-address to something. - Network::RelayInfoPtr result(new Network::RelayInfo(asiolink::IOAddress("::"))); + // Create an "empty" RelayInfo to hold the parsed result. + Network::RelayInfoPtr result(new Network::RelayInfo()); RelayInfoParser parser(Option::V6); diff --git a/src/lib/dhcpsrv/tests/shared_network_unittest.cc b/src/lib/dhcpsrv/tests/shared_network_unittest.cc index 2649289b8f..77159241a6 100644 --- a/src/lib/dhcpsrv/tests/shared_network_unittest.cc +++ b/src/lib/dhcpsrv/tests/shared_network_unittest.cc @@ -265,6 +265,26 @@ TEST(SharedNetwork4Test, getPreferredSubnet) { EXPECT_EQ(subnet3->getID(), preferred->getID()); } +// This test verifies operations on the network's relay list +TEST(SharedNetwork4Test, relayInfoList) { + SharedNetwork4Ptr network(new SharedNetwork4("frog")); + + EXPECT_FALSE(network->hasRelays()); + EXPECT_FALSE(network->hasRelayAddress(IOAddress("192.168.2.1"))); + + // Add relay addresses to the network. + network->addRelayAddress(IOAddress("192.168.2.1")); + network->addRelayAddress(IOAddress("192.168.2.2")); + network->addRelayAddress(IOAddress("192.168.2.3")); + + // Verify we believe we have relays and we can match them accordingly. + EXPECT_TRUE(network->hasRelays()); + EXPECT_TRUE(network->hasRelayAddress(IOAddress("192.168.2.1"))); + EXPECT_TRUE(network->hasRelayAddress(IOAddress("192.168.2.2"))); + EXPECT_TRUE(network->hasRelayAddress(IOAddress("192.168.2.3"))); + EXPECT_FALSE(network->hasRelayAddress(IOAddress("192.168.2.4"))); +} + // This test verifies that unparsing shared network returns valid structure. TEST(SharedNetwork4Test, unparse) { SharedNetwork4Ptr network(new SharedNetwork4("frog")); @@ -281,10 +301,14 @@ TEST(SharedNetwork4Test, unparse) { data::ElementPtr ctx = data::Element::fromJSON(uc); network->setContext(ctx); network->requireClientClass("foo"); + network->addRelayAddress(IOAddress("192.168.2.1")); // Add several subnets. Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30, SubnetID(1))); + subnet1->addRelayAddress(IOAddress("10.0.0.1")); + subnet1->addRelayAddress(IOAddress("10.0.0.2")); + Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"), 24, 10, 20, 30, SubnetID(2))); network->add(subnet1); @@ -298,7 +322,7 @@ TEST(SharedNetwork4Test, unparse) { " \"option-data\": [ ],\n" " \"rebind-timer\": 150,\n" " \"relay\": {\n" - " \"ip-address\": \"0.0.0.0\"\n" + " \"ip-addresses\": [ \"192.168.2.1\" ]\n" " },\n" " \"renew-timer\": 100,\n" " \"require-client-classes\": [ \"foo\" ],\n" @@ -317,7 +341,7 @@ TEST(SharedNetwork4Test, unparse) { " \"pools\": [ ],\n" " \"rebind-timer\": 20,\n" " \"relay\": {\n" - " \"ip-address\": \"0.0.0.0\"\n" + " \"ip-addresses\": [ \"10.0.0.1\", \"10.0.0.2\" ]\n" " },\n" " \"renew-timer\": 10,\n" " \"reservation-mode\": \"all\",\n" @@ -337,7 +361,7 @@ TEST(SharedNetwork4Test, unparse) { " \"pools\": [ ],\n" " \"rebind-timer\": 20,\n" " \"relay\": {\n" - " \"ip-address\": \"0.0.0.0\"\n" + " \"ip-addresses\": [ ]\n" " },\n" " \"renew-timer\": 10,\n" " \"reservation-mode\": \"all\",\n" @@ -658,6 +682,26 @@ TEST(SharedNetwork6Test, getPreferredSubnet) { EXPECT_EQ(subnet3->getID(), preferred->getID()); } +// This test verifies operations on the network's relay list +TEST(SharedNetwork6Test, relayInfoList) { + SharedNetwork6Ptr network(new SharedNetwork6("frog")); + + EXPECT_FALSE(network->hasRelays()); + EXPECT_FALSE(network->hasRelayAddress(IOAddress("2001:db8:2::1"))); + + // Add realy addresses to the network. + network->addRelayAddress(IOAddress("2001:db8:2::1")); + network->addRelayAddress(IOAddress("2001:db8:2::2")); + network->addRelayAddress(IOAddress("2001:db8:2::3")); + + // Verify we believe we have relays and we can match them accordingly. + EXPECT_TRUE(network->hasRelays()); + EXPECT_TRUE(network->hasRelayAddress(IOAddress("2001:db8:2::1"))); + EXPECT_TRUE(network->hasRelayAddress(IOAddress("2001:db8:2::2"))); + EXPECT_TRUE(network->hasRelayAddress(IOAddress("2001:db8:2::3"))); + EXPECT_FALSE(network->hasRelayAddress(IOAddress("2001:db8:2::4"))); +} + // This test verifies that unparsing shared network returns valid structure. TEST(SharedNetwork6Test, unparse) { SharedNetwork6Ptr network(new SharedNetwork6("frog")); @@ -673,11 +717,16 @@ TEST(SharedNetwork6Test, unparse) { network->setContext(ctx); network->requireClientClass("foo"); + network->addRelayAddress(IOAddress("2001:db8:1::7")); + network->addRelayAddress(IOAddress("2001:db8:1::8")); + // Add several subnets. Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 10, 20, 30, 40, SubnetID(1))); Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 16, 10, 20, 30, 40, SubnetID(2))); + subnet2->addRelayAddress(IOAddress("2001:db8:1::8")); + network->add(subnet1); network->add(subnet2); @@ -689,7 +738,7 @@ TEST(SharedNetwork6Test, unparse) { " \"rapid-commit\": true,\n" " \"rebind-timer\": 150,\n" " \"relay\": {\n" - " \"ip-address\": \"::\"\n" + " \"ip-addresses\": [ \"2001:db8:1::7\", \"2001:db8:1::8\" ]\n" " },\n" " \"renew-timer\": 100,\n" " \"require-client-classes\": [ \"foo\" ],\n" @@ -704,7 +753,7 @@ TEST(SharedNetwork6Test, unparse) { " \"rapid-commit\": false,\n" " \"rebind-timer\": 20,\n" " \"relay\": {\n" - " \"ip-address\": \"::\"\n" + " \"ip-addresses\": [ ]\n" " },\n" " \"renew-timer\": 10,\n" " \"reservation-mode\": \"all\",\n" @@ -720,7 +769,7 @@ TEST(SharedNetwork6Test, unparse) { " \"rapid-commit\": false,\n" " \"rebind-timer\": 20,\n" " \"relay\": {\n" - " \"ip-address\": \"::\"\n" + " \"ip-addresses\": [ \"2001:db8:1::8\" ]\n" " },\n" " \"renew-timer\": 10,\n" " \"reservation-mode\": \"all\",\n" diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc index 979d4e04b9..9d444be237 100644 --- a/src/lib/dhcpsrv/tests/subnet_unittest.cc +++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc @@ -76,7 +76,7 @@ TEST(Subnet4Test, inRange) { EXPECT_EQ(2000, subnet.getT2()); EXPECT_EQ(3000, subnet.getValid()); - EXPECT_EQ("0.0.0.0", subnet.getRelayInfo().addr_.toText()); + EXPECT_FALSE(subnet.hasRelays()); EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0"))); EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0"))); @@ -87,15 +87,34 @@ TEST(Subnet4Test, inRange) { EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255"))); } -// Checks whether the relay field has sane default and if it can -// be changed, stored and retrieved +// Checks whether the relay list is empty by default +// and basic operations function TEST(Subnet4Test, relay) { Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000); - EXPECT_EQ("0.0.0.0", subnet.getRelayInfo().addr_.toText()); + // Should be empty. + EXPECT_FALSE(subnet.hasRelays()); + EXPECT_EQ(0, subnet.getRelayAddresses().size()); - subnet.setRelayInfo(IOAddress("192.0.123.45")); - EXPECT_EQ("192.0.123.45", subnet.getRelayInfo().addr_.toText()); + // Matching should fail. + EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("192.0.123.45"))); + + // Should be able to add them. + subnet.addRelayAddress(IOAddress("192.0.123.45")); + subnet.addRelayAddress(IOAddress("192.0.123.46")); + + // Should not be empty. + EXPECT_TRUE(subnet.hasRelays()); + + // Should be two in the list. + EXPECT_EQ(2, subnet.getRelayAddresses().size()); + + // Should be able to match them if they are there. + EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("192.0.123.45"))); + EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("192.0.123.46"))); + + // Should not match those that are not. + EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("192.0.123.47"))); } // Checks whether siaddr field can be set and retrieved correctly. @@ -681,16 +700,34 @@ TEST(Subnet6Test, inRange) { EXPECT_FALSE(subnet.inRange(IOAddress("::"))); } -// Checks whether the relay field has sane default and if it can -// be changed, stored and retrieved +// Checks whether the relay list is empty by default +// and basic operations function TEST(Subnet6Test, relay) { Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000); - EXPECT_EQ("::", subnet.getRelayInfo().addr_.toText()); + // Should be empty. + EXPECT_FALSE(subnet.hasRelays()); + EXPECT_EQ(0, subnet.getRelayAddresses().size()); + + // Matching should fail. + EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("2001:ffff::45"))); + + // Should be able to add them. + subnet.addRelayAddress(IOAddress("2001:ffff::45")); + subnet.addRelayAddress(IOAddress("2001:ffff::46")); + + // Should not be empty. + EXPECT_TRUE(subnet.hasRelays()); + + // Should be two in the list. + EXPECT_EQ(2, subnet.getRelayAddresses().size()); - subnet.setRelayInfo(IOAddress("2001:ffff::1")); + // Should be able to match them if they are there. + EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("2001:ffff::45"))); + EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("2001:ffff::46"))); - EXPECT_EQ("2001:ffff::1", subnet.getRelayInfo().addr_.toText()); + // Should not match those that are not. + EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("2001:ffff::47"))); } // Test checks whether the number of addresses available in the pools are