]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5535] dhcpsrv now supports multiple relay addresses in RelayInfo
authorThomas Markwalder <tmark@isc.org>
Wed, 25 Apr 2018 18:47:21 +0000 (14:47 -0400)
committerThomas Markwalder <tmark@isc.org>
Wed, 25 Apr 2018 18:47:21 +0000 (14:47 -0400)
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

13 files changed:
src/lib/dhcpsrv/cfg_subnets4.cc
src/lib/dhcpsrv/cfg_subnets6.cc
src/lib/dhcpsrv/network.cc
src/lib/dhcpsrv/network.h
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

index 0e47c6d0fc4d4bafbc8bfc28d2f0a449d6260ae6..21c188ae300231063b0055c7e1ac616eca0aa441 100644 (file)
@@ -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;
                 }
             }
index e35b3773d4179e620dff07c551a0c3722ed387be..9db6aa4fee451a78df623ea0c414b4ec915c1334 100644 (file)
@@ -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);
             }
+
         }
     }
 
index 1071ec30962c9154989d2704d390ef1a3f2622ab..7493b046d60d0ba004b645f171e43a4218449e12 100644 (file)
@@ -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();
index 815826a0e76a300a0e704d58018e3141d571e572..161afedc45087dd3d82887e3c48b8ba473057358 100644 (file)
@@ -24,6 +24,9 @@
 namespace isc {
 namespace dhcp {
 
+/// List of IOAddresses
+typedef std::vector<isc::asiolink::IOAddress> 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)
index 8b3f2efdcd79ce338a407750a3af627f25989e86..961a5334a5c7864fe022c31a46c42f1bcd34340f 100644 (file)
@@ -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) {
index 1e25f1571439c0971e92788a52973903faad998e..ae4aefe3069e83d93740c695795e76163b781410 100644 (file)
@@ -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);
index cd82ab3797f943ce2d77363d11cffe084f1c2041..80896223ec0c57f12651268e0b643475114f6647 100644 (file)
@@ -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"
index 92e84ad3d93eb70dcb56880cfc063f9337ed5d2d..f24069c744cb813812f2df3fed4f30d5f2b932ea 100644 (file)
@@ -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"
index 6cd404aed5eaffdab8a2f41c25e447b636d418c2..c02b4f52474f0b0aad7f637e7055c8e91a75493c 100644 (file)
@@ -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"
index c9dd4b0fd024c37ba2e49b804d766e11addcea03..f640299b5e9370952100912fbc3373a94e364e70 100644 (file)
@@ -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"
index d79d6d2877e8562495a3be1b78533bb4ba7029ef..4651d504bb8f1cce39dfe9bcf8262e43ffd0e469 100644 (file)
@@ -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);
 
index 2649289b8f461e5a15a2e6f18f8b81b47d3d01eb..77159241a6e044ca6c1d89775e87243b409df1ad 100644 (file)
@@ -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"
index 979d4e04b9af528094e087e6b8467f938ff4231e..9d444be237c8377e2addc438ed3b7122f7429019 100644 (file)
@@ -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