]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5307] Created basic unit tests for shared networks in DHCPv6.
authorMarcin Siodelski <marcin@isc.org>
Wed, 20 Sep 2017 07:40:34 +0000 (09:40 +0200)
committerMarcin Siodelski <marcin@isc.org>
Thu, 21 Sep 2017 08:59:21 +0000 (10:59 +0200)
src/bin/dhcp6/tests/Makefile.am
src/bin/dhcp6/tests/dhcp6_client.cc
src/bin/dhcp6/tests/dhcp6_client.h
src/bin/dhcp6/tests/shared_network_unittest.cc [new file with mode: 0644]
src/lib/dhcpsrv/alloc_engine.cc

index d13b2a3792596c8c5ee057ccf744713cd2c8d8d4..f0b8d219c842b823dae2f66946b8c1f36565e076 100644 (file)
@@ -97,6 +97,7 @@ dhcp6_unittests_SOURCES += classify_unittests.cc
 dhcp6_unittests_SOURCES += parser_unittest.cc
 dhcp6_unittests_SOURCES += simple_parser6_unittest.cc
 dhcp6_unittests_SOURCES += get_config_unittest.cc get_config_unittest.h
+dhcp6_unittests_SOURCES += shared_network_unittest.cc
 
 nodist_dhcp6_unittests_SOURCES  = marker_file.h test_libraries.h
 
index 922baa28b537f5d3cb2bc5a3f96f974dcc298162..15cc6838f60ac651fabb3e3b382a347a5b0399c0 100644 (file)
@@ -474,10 +474,11 @@ Dhcp6Client::doRequest() {
     copyIAs(context_.response_, query);
     appendRequestedIAs(query);
 
+    context_.query_ = query;
+
     // Add Client FQDN if configured.
     appendFQDN();
 
-    context_.query_ = query;
     sendMsg(context_.query_);
     context_.response_ = receiveOneMsg();
 
@@ -590,6 +591,25 @@ Dhcp6Client::doDecline(const bool include_address) {
     }
 }
 
+void
+Dhcp6Client::doRelease() {
+    Pkt6Ptr query = createMsg(DHCPV6_RELEASE);
+    query->addOption(context_.response_->getOption(D6O_SERVERID));
+    copyIAsFromLeases(query);
+
+    context_.query_ = query;
+
+    sendMsg(context_.query_);
+    context_.response_ = receiveOneMsg();
+
+    // Apply configuration only if the server has responded.
+    if (context_.response_) {
+        config_.clear();
+        applyRcvdConfiguration(context_.response_);
+    }
+}
+
+
 void
 Dhcp6Client::generateIAFromLeases(const Pkt6Ptr& query,
                                   const bool include_address) {
index d2791a3977b16b29aa125bde484dac1600c3c65c..9bdde821bf896df044c7776aa3614eda1b0e48af 100644 (file)
@@ -305,6 +305,12 @@ public:
     /// way, just stores it.
     void doInfRequest();
 
+    /// @brief Sends Release to the server.
+    ///
+    /// This function simulates sending the Release message to the server
+    /// and receiving server's response.
+    void doRelease();
+
     /// @brief Removes the stateful configuration obtained from the server.
     ///
     /// It removes all leases held by the client.
@@ -503,7 +509,7 @@ public:
     }
 
     /// @brief Returns the server that the client is communicating with.
-    boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv> getServer() const {
+    boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv>& getServer() {
         return (srv_);
     }
 
diff --git a/src/bin/dhcp6/tests/shared_network_unittest.cc b/src/bin/dhcp6/tests/shared_network_unittest.cc
new file mode 100644 (file)
index 0000000..496fd33
--- /dev/null
@@ -0,0 +1,1162 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option6_client_fqdn.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp6/tests/dhcp6_client.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <stats/stats_mgr.h>
+#include <boost/pointer_cast.hpp>
+#include <vector>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::stats;
+
+namespace {
+
+/// @brief Array of server configurations used throughout the tests.
+const char* NETWORKS_CONFIG[] = {
+// Configuration #0.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ],"
+    "    \"subnet6\": ["
+    "        {"
+    "            \"subnet\": \"3000::/96\","
+    "            \"id\": 1000,"
+    "            \"interface\": \"eth0\","
+    "            \"pools\": ["
+    "                {"
+    "                    \"pool\": \"3000::1 - 3000::1\""
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #1.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"relay\": {"
+    "                \"ip-address\": \"3001::1\""
+    "            },"
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ],"
+    "    \"subnet6\": ["
+    "        {"
+    "            \"subnet\": \"2001:db8:2::/64\","
+    "            \"id\": 1000,"
+    "            \"relay\": {"
+    "                \"ip-address\": \"3001::2\""
+    "            },"
+    "            \"pools\": ["
+    "                {"
+    "                    \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #2.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"client-classes\": ["
+    "        {"
+    "            \"name\": \"a-devices\","
+    "            \"test\": \"option[1234].hex == 0x0001\""
+    "        },"
+    "        {"
+    "            \"name\": \"b-devices\","
+    "            \"test\": \"option[1234].hex == 0x0002\""
+    "        }"
+    "    ],"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ],"
+    "                    \"client-class\": \"a-devices\""
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #3.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"client-classes\": ["
+    "        {"
+    "            \"name\": \"a-devices\","
+    "            \"test\": \"option[1234].hex == 0x0001\""
+    "        },"
+    "        {"
+    "            \"name\": \"b-devices\","
+    "            \"test\": \"option[1234].hex == 0x0002\""
+    "        }"
+    "    ],"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ],"
+    "                    \"client-class\": \"a-devices\""
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ],"
+    "                    \"client-class\": \"b-devices\""
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #4.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
+    "                        }"
+    "                    ],"
+    "                    \"reservations\": ["
+    "                        {"
+    "                            \"duid\": \"00:03:00:01:aa:bb:cc:dd:ee:ff\","
+    "                            \"ip-addresses\": [ \"2001:db8:1::28\" ]"
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::1 - 2001:db8:2::64\""
+    "                        }"
+    "                    ],"
+    "                    \"reservations\": ["
+    "                        {"
+    "                            \"duid\": \"00:03:00:01:11:22:33:44:55:66\","
+    "                            \"ip-addresses\": [ \"2001:db8:2::28\" ]"
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #5.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
+    "                        }"
+    "                    ],"
+    "                    \"reservations\": ["
+    "                        {"
+    "                            \"duid\": \"00:03:00:01:11:22:33:44:55:66\","
+    "                            \"ip-addresses\": [ \"2001:db8:1::28\" ]"
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::1 - 2001:db8:2::64\""
+    "                        }"
+    "                    ],"
+    "                    \"reservations\": ["
+    "                        {"
+    "                            \"duid\": \"00:03:00:01:aa:bb:cc:dd:ee:ff\","
+    "                            \"ip-addresses\": [ \"2001:db8:2::28\" ]"
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #6.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"client-classes\": ["
+    "        {"
+    "            \"name\": \"a-devices\","
+    "            \"test\": \"option[1234].hex == 0x0001\""
+    "        }"
+    "    ],"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
+    "                        }"
+    "                    ],"
+    "                    \"client-class\": \"a-devices\","
+    "                    \"reservations\": ["
+    "                        {"
+    "                            \"duid\": \"00:03:00:01:aa:bb:cc:dd:ee:ff\","
+    "                            \"ip-addresses\": [ \"2001:db8:1::28\" ]"
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::16 - 2001:db8:2::16\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #7.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"option-data\": ["
+    "        {"
+    "            \"name\": \"nis-servers\","
+    "            \"data\": \"3000::20\""
+    "        }"
+    "    ],"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"option-data\": ["
+    "                {"
+    "                    \"name\": \"dns-servers\","
+    "                    \"data\": \"3001::21\""
+    "                },"
+    "                {"
+    "                    \"name\": \"nisp-servers\","
+    "                    \"data\": \"3002::34\""
+    "                }"
+    "            ],"
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"option-data\": ["
+    "                        {"
+    "                            \"name\": \"sntp-servers\","
+    "                            \"data\": \"4004::22\""
+    "                        },"
+    "                        {"
+    "                            \"name\": \"nisp-servers\","
+    "                            \"data\": \"3003::33\""
+    "                        }"
+    "                    ],"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ],"
+    "    \"subnet6\": ["
+    "        \{"
+    "            \"subnet\": \"3000::/96\","
+    "            \"id\": 1000,"
+    "            \"interface\": \"eth0\","
+    "            \"option-data\": ["
+    "                {"
+    "                    \"name\": \"nisp-servers\","
+    "                    \"data\": \"4000::5\""
+    "                }"
+    "            ],"
+    "            \"pools\": ["
+    "                {"
+    "                    \"pool\": \"3000::1 - 3000::1\""
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #8.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        },"
+    "        {"
+    "            \"name\": \"dog\","
+    "            \"interface\": \"eth0\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:3::/64\","
+    "                    \"id\": 1000,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:3::20 - 2001:db8:3::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:4::/64\","
+    "                    \"id\": 10000,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:4::20 - 2001:db8:4::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #9.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"relay\": {"
+    "                \"ip-address\": \"3000::1\""
+    "            },"
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        },"
+    "        {"
+    "            \"name\": \"dog\","
+    "            \"relay\": {"
+    "                \"ip-address\": \"3000::2\""
+    "            },"
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:3::/64\","
+    "                    \"id\": 1000,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:3::20 - 2001:db8:3::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:4::/64\","
+    "                    \"id\": 10000,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:4::20 - 2001:db8:4::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #10.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"client-classes\": ["
+    "        {"
+    "            \"name\": \"class-with-dns-servers\","
+    "            \"option-data\": ["
+    "                {"
+    "                    \"name\": \"dns-servers\","
+    "                    \"data\": \"2001:db8:1::50\""
+    "                }"
+    "            ]"
+    "        }"
+    "    ],"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ],"
+    "                    \"reservations\": ["
+    "                        {"
+    "                            \"duid\": \"00:03:00:01:11:22:33:44:55:66\","
+    "                            \"hostname\": \"test.example.org\","
+    "                            \"client-classes\": [ \"class-with-dns-servers\" ]"
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+// Configuration #11.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"preferred-lifetime\": 3000,"
+    "    \"rebind-timer\": 2000, "
+    "    \"renew-timer\": 1000, "
+    "    \"client-classes\": ["
+    "        {"
+    "            \"name\": \"a-devices\","
+    "            \"test\": \"option[1234].hex == 0x0001\""
+    "        },"
+    "        {"
+    "            \"name\": \"b-devices\","
+    "            \"test\": \"option[1234].hex == 0x0002\""
+    "        }"
+    "    ],"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"client-class\": \"a-devices\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:1::/64\","
+    "                    \"id\": 10,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        },"
+    "        {"
+    "            \"name\": \"dog\","
+    "            \"interface\": \"eth1\","
+    "            \"client-class\": \"b-devices\","
+    "            \"subnet6\": ["
+    "                {"
+    "                    \"subnet\": \"2001:db8:2::/64\","
+    "                    \"id\": 1000,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}"
+};
+
+/// @Brief Test fixture class for DHCPv6 server using shared networks.
+class Dhcpv6SharedNetworkTest : public Dhcpv6SrvTest {
+public:
+
+    /// @brief Constructor.
+    Dhcpv6SharedNetworkTest()
+        : Dhcpv6SrvTest(),
+          iface_mgr_test_config_(true) {
+        IfaceMgr::instance().openSockets6();
+        StatsMgr::instance().removeAll();
+    }
+
+    /// @brief Destructor.
+    virtual ~Dhcpv6SharedNetworkTest() {
+        StatsMgr::instance().removeAll();
+    }
+
+    /// @brief Interface Manager's fake configuration control.
+    IfaceMgrTestConfig iface_mgr_test_config_;
+};
+
+// Running out of addresses within a subnet in a shared network.
+TEST_F(Dhcpv6SharedNetworkTest, addressPoolInSharedNetworkShortage) {
+    // Create client #1.
+    Dhcp6Client client1;
+    client1.setInterface("eth1");
+
+    // Configure the server with one shared network including two subnets and
+    // one subnet outside of the shared network.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[0], *client1.getServer()));
+
+    // Client #1 requests an address in first subnet within a shared network.
+    ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
+    ASSERT_NO_THROW(client1.doSARR());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+
+    // Client #2 The second client will request a lease and should be assigned
+    // an address from the second subnet.
+    Dhcp6Client client2(client1.getServer());
+    client2.setInterface("eth1");
+    ASSERT_NO_THROW(client2.requestAddress(0xabca0));
+    ASSERT_NO_THROW(client2.doSARR());
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+
+    // Cient #3. It sends Solicit which should result in NoAddrsAvail status
+    // code because all addresses available for this link have been assigned.
+    Dhcp6Client client3(client1.getServer());
+    client3.setInterface("eth1");
+    ASSERT_NO_THROW(client3.requestAddress(0xabca0));
+    ASSERT_NO_THROW(client3.doSolicit(true));
+    EXPECT_EQ(0, client3.getLeaseNum());
+
+    // Client #3 should be assigned an address if subnet 3 is selected for it.
+    client3.setInterface("eth0");
+    ASSERT_NO_THROW(client3.doSolicit(true));
+    EXPECT_EQ(1, client3.getLeaseNum());
+
+    // Client #1 should be able to renew its lease.
+    ASSERT_NO_THROW(client1.doRenew());
+    EXPECT_EQ(1, client1.getLeaseNum());
+    EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+
+    // Client #2 should be able to renew its lease too.
+    ASSERT_NO_THROW(client2.doRenew());
+    EXPECT_EQ(1, client2.getLeaseNum());
+    EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+}
+
+// Shared network is selected based on relay link address.
+TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByRelay) {
+    // Create client #1. This is a relayed client which is using relay address
+    // matching configured shared network.
+    Dhcp6Client client1;
+    client1.useRelay(true, IOAddress("3001::1"));
+
+    // Configure the server with one shared network and one subnet outside of the
+    // shared network.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[1], *client1.getServer()));
+
+    // Client #1 should be assigned an address from shared network.
+    ASSERT_NO_THROW(client1.requestAddress(0xabca));
+    ASSERT_NO_THROW(client1.doSARR());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+
+    // Create client #2. This is a relayed client which is using relay
+    // address matching subnet outside of the shared network.
+    Dhcp6Client client2(client1.getServer());
+    client2.useRelay(true, IOAddress("3001::2"));
+    ASSERT_NO_THROW(client2.requestAddress(0xabca0));
+    ASSERT_NO_THROW(client2.doSARR());
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+}
+
+// Providing a hint for any address belonging to a shared network.
+TEST_F(Dhcpv6SharedNetworkTest, hintWithinSharedNetwork) {
+    // Create client #1.
+    Dhcp6Client client;
+    client.setInterface("eth1");
+
+    // Configure the server with one shared network including two subnets and
+    // one subnet outside of the shared network.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[0], *client.getServer()));
+
+    // Provide a hint to an existing address within first subnet. This address
+    // should be offered out of this subnet.
+    ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
+    ASSERT_NO_THROW(client.doSolicit(true));
+    ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+
+    // Similarly, we should be offerred an address from another subnet within
+    // the same shared network when we ask for it.
+    client.clearRequestedIAs();
+    ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:2::20")));
+    ASSERT_NO_THROW(client.doSolicit(true));
+    ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+
+    // Asking for an address that is not in address pool should result in getting
+    // an address from one of the subnets, but generally hard to tell from which one.
+    client.clearRequestedIAs();
+    ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("3002::123")));
+    ASSERT_NO_THROW(client.doSolicit(true));
+    std::vector<Lease6> leases = client.getLeasesByType(Lease::TYPE_NA);
+    ASSERT_EQ(1, leases.size());
+    if (!client.hasLeaseForAddress(IOAddress("2001:db8:1::20")) &&
+        !client.hasLeaseForAddress(IOAddress("2001:db8:2::20"))) {
+        ADD_FAILURE() << "Unexpected address advertised by the server " << leases.at(0).addr_;
+    }
+}
+
+// Shared network is selected based on the client class specified.
+TEST_F(Dhcpv6SharedNetworkTest, subnetInSharedNetworkSelectedByClass) {
+    // Create client #1.
+    Dhcp6Client client1;
+    client1.setInterface("eth1");
+
+    // Configure the server with one shared network including two subnets and
+    // one subnet outside of the shared network.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[2], *client1.getServer()));
+
+    // Client #1 requests an address in the restricted subnet but can't be assigned
+    // this address because the client doesn't belong to a certain class.
+    ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
+    ASSERT_NO_THROW(client1.doSARR());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+
+    // Release the lease that the client has got, because we'll need this address
+    // further in the test.
+    client1.doRelease();
+
+    // Add option 1234 which would cause the client to be classified as "a-devices".
+    OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001));
+    client1.addExtraOption(option1234);
+
+    // This time, the allocation of the address provided as hint should be successful.
+    ASSERT_NO_THROW(client1.doSARR());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+
+
+    // Client 2 should be assigned an address from the unrestricted subnet.
+    Dhcp6Client client2(client1.getServer());
+    client2.setInterface("eth1");
+    ASSERT_NO_THROW(client2.requestAddress(0xabca0));
+    ASSERT_NO_THROW(client2.doSARR());
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+
+    // Now, let's reconfigure the server to also apply restrictions on the
+    // subnet to which client2 now belongs.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[3], *client1.getServer()));
+
+    ASSERT_NO_THROW(client2.doRenew());
+    EXPECT_EQ(0, client2.getLeaseNum());
+
+    // If we add option 1234 with a value matching this class, the lease should
+    // get renewed.
+    OptionPtr option1234_bis(new OptionUint16(Option::V6, 1234, 0x0002));
+    client2.addExtraOption(option1234_bis);
+    ASSERT_NO_THROW(client2.doRenew());
+    EXPECT_EQ(1, client2.getLeaseNum());
+}
+
+// IPv6 address reservation exists in one of the subnets within shared network.
+TEST_F(Dhcpv6SharedNetworkTest, reservationInSharedNetwork) {
+    // Create client #1. Explicitly set client's DUID to the one that has a
+    // reservation in the second subnet within shared network.
+    Dhcp6Client client1;
+    client1.setInterface("eth1");
+    client1.setDUID("00:03:00:01:11:22:33:44:55:66");
+
+    // Create server configuration with a shared network including two subnets. There
+    // is an IP address reservation in each subnet for two respective clients.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[4], *client1.getServer()));
+
+    // Client #1 should get his reserved address from the second subnet.
+    ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
+    ASSERT_NO_THROW(client1.doSARR());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:2::28")));
+
+    // Create client #2.
+    Dhcp6Client client2;
+    client2.setInterface("eth1");
+    client2.setDUID("00:03:00:01:aa:bb:cc:dd:ee:ff");
+
+    // Client #2 should get its reserved address from the first subnet.
+    ASSERT_NO_THROW(client2.requestAddress(0xabca, IOAddress("2001:db8:1::30")));
+    ASSERT_NO_THROW(client2.doSARR());
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+
+    // Reconfigure the server. Now, the first client get's second client's
+    // reservation and vice versa.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[5], *client1.getServer()));
+
+    // The first client is trying to renew the lease but should get a different lease
+    // because its lease is now reserved for some other client. The client won't be
+    // assigned a lease for which it has a reservation because another client holds
+    // this lease.
+    ASSERT_NO_THROW(client1.doRenew());
+    ASSERT_TRUE(client1.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::28")));
+    ASSERT_FALSE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+
+    // The client should be allocated a lease from one of the dynamic pools.
+    if (!client1.hasLeaseForAddressRange(IOAddress("2001:db8:2::1"), IOAddress("2001:db8:2::64")) &&
+        !client1.hasLeaseForAddressRange(IOAddress("2001:db8:1::1"), IOAddress("2001:db8:1::64"))) {
+        ADD_FAILURE() << "unexpected lease allocated for renewing client";
+    }
+
+    // Client #2 is now renewing its lease and should get its newly reserved address.
+    ASSERT_NO_THROW(client2.doRenew());
+    ASSERT_TRUE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::28")));
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::28")));
+
+    // Same for client #1.
+    ASSERT_NO_THROW(client1.doRenew());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+}
+
+// Reserved address can't be assigned as long as access to a subnet is
+// restricted by classification.
+TEST_F(Dhcpv6SharedNetworkTest, reservationAccessRestrictedByClass) {
+    // Create client #1. Explicitly set client's DUID to the one that has a
+    // reservation in the firstsubnet within shared network.
+    Dhcp6Client client;
+    client.setInterface("eth1");
+    client.setDUID("00:03:00:01:aa:bb:cc:dd:ee:ff");
+
+    // Create server configuration with a shared network including two subnets. Access to
+    // one of the subnets is restricted by client classification.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[6], *client.getServer()));
+
+    // Assigned address should be allocated from the second subnet, because the
+    // client doesn't belong to the "a-devices" class.
+    ASSERT_NO_THROW(client.requestAddress(0xabca));
+    ASSERT_NO_THROW(client.doSARR());
+    ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::16")));
+
+    // Add option 1234 which would cause the client to be classified as "a-devices".
+    OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001));
+    client.addExtraOption(option1234);
+
+    // The client should now be assigned the reserved address from the first subnet.
+    ASSERT_NO_THROW(client.doRenew());
+    ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::16")));
+    ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+}
+
+// Some options are specified on the shared subnet level, some on the
+// subnets level.
+TEST_F(Dhcpv6SharedNetworkTest, optionsDerivation) {
+    // Client #1.
+    Dhcp6Client client1;
+    client1.setInterface("eth1");
+
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[7], *client1.getServer()));
+
+    // Client #1 belongs to shared network. By providing a hint "2001:db8:1::20 we force
+    // the server to select first subnet within the shared network for this client.
+    ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20")));
+
+    // Request all configured options.
+    ASSERT_NO_THROW(client1.requestOption(D6O_NIS_SERVERS));
+    ASSERT_NO_THROW(client1.requestOption(D6O_NISP_SERVERS));
+    ASSERT_NO_THROW(client1.requestOption(D6O_NAME_SERVERS));
+    ASSERT_NO_THROW(client1.requestOption(D6O_SNTP_SERVERS));
+
+    // Perform 4-way exchange and make sure we have been assigned address from the
+    // subnet we wanted.
+    ASSERT_NO_THROW(client1.doSARR());
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+
+    // This option is specified on the global level.
+    ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20"));
+
+    // Subnet specific value should override a value specified on the shared network level.
+    ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NISP_SERVERS, "3003::33"));
+
+    // Shared network level value should be derived to the subnet.
+    ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NAME_SERVERS, "3001::21"));
+
+    // This option is only specified in the subnet level.
+    ASSERT_TRUE(client1.hasOptionWithAddress(D6O_SNTP_SERVERS, "4004::22"));
+
+    // Client #2.
+    Dhcp6Client client2(client1.getServer());
+    client2.setInterface("eth1");
+
+    // Request an address from the second subnet within the shared network.
+    ASSERT_NO_THROW(client2.requestAddress(0xabca, IOAddress("2001:db8:2::20")));
+
+    // Request all configured options.
+    ASSERT_NO_THROW(client2.requestOption(D6O_NIS_SERVERS));
+    ASSERT_NO_THROW(client2.requestOption(D6O_NISP_SERVERS));
+    ASSERT_NO_THROW(client2.requestOption(D6O_NAME_SERVERS));
+    ASSERT_NO_THROW(client2.requestOption(D6O_SNTP_SERVERS));
+
+    // Perform 4-way exchange and make sure we have been assigned address from the
+    // subnet we wanted.
+    ASSERT_NO_THROW(client2.doSARR());
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+
+    // This option is specified on the global level.
+    ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20"));
+
+    // Shared network level value should be derived to the subnet.
+    ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NAME_SERVERS, "3001::21"));
+    ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NISP_SERVERS, "3002::34"));
+
+    // Client #3.
+    Dhcp6Client client3(client1.getServer());
+    client3.setInterface("eth0");
+
+    // Request an address from the subnet outside of the shared network.
+    ASSERT_NO_THROW(client2.requestAddress(0xabca, IOAddress("3000::1")));
+
+    // Request all configured options.
+    ASSERT_NO_THROW(client3.requestOption(D6O_NIS_SERVERS));
+    ASSERT_NO_THROW(client3.requestOption(D6O_NISP_SERVERS));
+    ASSERT_NO_THROW(client3.requestOption(D6O_NAME_SERVERS));
+    ASSERT_NO_THROW(client3.requestOption(D6O_SNTP_SERVERS));
+
+    // Perform 4-way exchange and make sure we have been assigned address from the
+    // subnet we wanted.
+    ASSERT_NO_THROW(client3.doSARR());
+    ASSERT_TRUE(client3.hasLeaseForAddress(IOAddress("3000::1")));
+
+    // This option is specified on the global level.
+    ASSERT_TRUE(client3.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20"));
+
+    // Subnet specific value should be assigned.
+    ASSERT_TRUE(client3.hasOptionWithAddress(D6O_NISP_SERVERS, "4000::5"));
+}
+
+// Different shared network is selected for different local interface.
+TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByInterface) {
+    // Create client #1. The server receives requests from this client
+    // via interface eth1 and should assign shared network "frog" for
+    // this client.
+    Dhcp6Client client1;
+    client1.setInterface("eth1");
+    client1.requestAddress(0xabca);
+
+    // Create server configuration with two shared networks selected
+    // by the local interface: eth1 and eth0.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[8], *client1.getServer()));
+
+    // Client #1 should be assigned an address from one of the two subnets
+    // belonging to the first shared network.
+    ASSERT_NO_THROW(client1.doSARR());
+    if (!client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")) &&
+        !client1.hasLeaseForAddress(IOAddress("2001:db8:2::20"))) {
+        ADD_FAILURE() << "unexpected shared network selected for the client";
+    }
+
+    // Client #2.
+    Dhcp6Client client2;
+    client2.setInterface("eth0");
+    client2.requestAddress(0xabca);
+
+    // Client #2 should be assigned an address from one of the two subnets
+    // belonging to the second shared network.
+    ASSERT_NO_THROW(client2.doSARR());
+    if (!client2.hasLeaseForAddress(IOAddress("2001:db8:3::20")) &&
+        !client2.hasLeaseForAddress(IOAddress("2001:db8:4::20"))) {
+        ADD_FAILURE() << "unexpected shared network selected for the client";
+    }
+}
+
+// Different shared network is selected for different relay address.
+TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByRelay) {
+    // Create relayed client #1.
+    Dhcp6Client client1;
+    client1.useRelay(true, IOAddress("3000::1"));
+    client1.requestAddress(0xabcd);
+
+    // Create server configuration with two shared networks selected
+    // by the relay address.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[9], *client1.getServer()));
+
+    // Client #1 should be assigned an address from one of the two subnets
+    // belonging to the first shared network.
+    ASSERT_NO_THROW(client1.doSARR());
+    if (!client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")) &&
+        !client1.hasLeaseForAddress(IOAddress("2001:db8:2::20"))) {
+        ADD_FAILURE() << "unexpected shared network selected for the client";
+    }
+
+    // Create relayed client #2.
+    Dhcp6Client client2;
+    client2.useRelay(true, IOAddress("3000::2"));
+    client2.requestAddress(0xabca);
+
+    // Client #2 should be assigned an address from one of the two subnets
+    // belonging to the second shared network.
+    ASSERT_NO_THROW(client2.doSARR());
+    if (!client2.hasLeaseForAddress(IOAddress("2001:db8:3::20")) &&
+        !client2.hasLeaseForAddress(IOAddress("2001:db8:4::20"))) {
+        ADD_FAILURE() << "unexpected shared network selected for the client";
+    }
+}
+
+// Host reservations include hostname and client class.
+TEST_F(Dhcpv6SharedNetworkTest, variousFieldsInReservation) {
+    // Create client #1.
+    Dhcp6Client client;
+    client.setInterface("eth1");
+    client.setDUID("00:03:00:01:11:22:33:44:55:66");
+    ASSERT_NO_THROW(client.requestAddress(0xabcd));
+
+    ASSERT_NO_THROW(client.useFQDN(Option6ClientFqdn::FLAG_S,
+                                   "bird.example.org",
+                                   Option6ClientFqdn::FULL));
+
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[10], *client.getServer()));
+
+    // Perform 4-way exchange.
+    ASSERT_NO_THROW(client.doSARR());
+
+    // The client should get an FQDN from the reservation, rather than
+    // the FQDN it has sent to the server. If there is a logic error,
+    // the server would use the first subnet from the shared network to
+    // assign the FQDN. This subnet has no reservation so it would
+    // return the same FQDN that the client has sent. We expect
+    // that the FQDN being sent is the one that is included in the
+    // reservations.
+    ASSERT_TRUE(client.getContext().response_);
+    OptionPtr opt_fqdn = client.getContext().response_->getOption(D6O_CLIENT_FQDN);
+    ASSERT_TRUE(opt_fqdn);
+    Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<Option6ClientFqdn>(opt_fqdn);
+    ASSERT_TRUE(fqdn);
+    ASSERT_EQ("test.example.org.", fqdn->getDomainName());
+
+    // The DNS servers option should be derived from the client class based on the
+    // static class reservations.
+    ASSERT_TRUE(client.hasOptionWithAddress(D6O_NAME_SERVERS, "2001:db8:1::50"));
+}
+
+// Shared network is selected based on the client class specified.
+TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByClass) {
+    // Create client #1.
+    Dhcp6Client client1;
+    client1.setInterface("eth1");
+    client1.requestAddress(0xabcd);
+
+    // Add option 1234 which would cause the client1 to be classified as "b-devices".
+    OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0002));
+    client1.addExtraOption(option1234);
+
+    // Configure the server with two shared networks which can be accessed
+    // by clients belonging to "a-devices" and "b-devices" classes
+    // respectively.
+    ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[11], *client1.getServer()));
+
+    // The client 1 should be offerred an address from the second subnet.
+    ASSERT_NO_THROW(client1.doSolicit(true));
+    ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:2::20")));
+
+    // Create another client which will belong to a different class.
+    Dhcp6Client client2;
+    client2.setInterface("eth1");
+    client2.requestAddress(0xabcd);
+
+    /// Add option 1234 which will cause the client 2 to be classified as "a-devices".
+    option1234.reset(new OptionUint16(Option::V6, 1234, 0x0001));
+    client2.addExtraOption(option1234);
+
+    // Client 2 should be offerred an address from the first subnet.
+    ASSERT_NO_THROW(client2.doSolicit(true));
+    ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::20")));
+}
+
+
+} // end of anonymous namespace
index 248c07797682b28fec6e516d401daf94d95e44bd..593ea6ec1bc35bc77738189e852d19d1ec7cdf36 100644 (file)
@@ -1352,9 +1352,19 @@ AllocEngine::renewLeases6(ClientContext6& ctx) {
         }
 
         // Check if there are any leases for this client.
-        Lease6Collection leases = LeaseMgrFactory::instance()
-            .getLeases6(ctx.currentIA().type_, *ctx.duid_,
-                        ctx.currentIA().iaid_, ctx.subnet_->getID());
+        Subnet6Ptr subnet = ctx.subnet_;
+        Lease6Collection leases;
+        while (subnet) {
+            Lease6Collection leases_subnet =
+                LeaseMgrFactory::instance().getLeases6(ctx.currentIA().type_,
+                                                       *ctx.duid_,
+                                                       ctx.currentIA().iaid_,
+                                                       subnet->getID());
+            leases.insert(leases.end(), leases_subnet.begin(), leases_subnet.end());
+
+            subnet = subnet->getNextSubnet(ctx.subnet_);
+        }
+
 
         if (!leases.empty()) {
             LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
@@ -1366,7 +1376,7 @@ AllocEngine::renewLeases6(ClientContext6& ctx) {
             removeNonmatchingReservedLeases6(ctx, leases);
         }
 
-        if (ctx.currentHost()) {
+        if (!ctx.hosts_.empty()) {
 
             LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
                       ALLOC_ENGINE_V6_RENEW_HR)