Browse Source

[3322] PktFilter6TestStub implemented.

Tomek Mrugalski 11 years ago
parent
commit
4a4c099967

+ 1 - 0
src/bin/dhcp6/tests/Makefile.am

@@ -92,6 +92,7 @@ dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/tests/libdhcptest.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libb10-dhcp_ddns.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/hooks/libb10-hooks.la

+ 38 - 32
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -29,6 +29,7 @@
 #include <dhcp6/config_parser.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/docsis3_option_defs.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/lease_mgr_factory.h>
@@ -52,6 +53,7 @@ using namespace isc::config;
 using namespace isc::test;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
+using namespace isc::dhcp::test;
 using namespace isc::util;
 using namespace isc::hooks;
 using namespace std;
@@ -283,6 +285,9 @@ TEST_F(Dhcpv6SrvTest, DUID) {
 // This test checks if Option Request Option (ORO) is parsed correctly
 // and the requested options are actually assigned.
 TEST_F(Dhcpv6SrvTest, advertiseOptions) {
+
+    IfaceMgrTestConfig test_config(true);
+
     ConstElementPtr x;
     string config = "{ \"interfaces\": [ \"all\" ],"
         "\"preferred-lifetime\": 3000,"
@@ -291,6 +296,7 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
         "\"subnet6\": [ { "
         "    \"pool\": [ \"2001:db8:1::/64\" ],"
         "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"eth0\", "
         "    \"option-data\": [ {"
         "          \"name\": \"dns-servers\","
         "          \"space\": \"dhcp6\","
@@ -307,25 +313,17 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
         "        } ]"
         " } ],"
         "\"valid-lifetime\": 4000 }";
-
-    ElementPtr json = Element::fromJSON(config);
-
-    NakedDhcpv6Srv srv(0);
-
-    EXPECT_NO_THROW(x = configureDhcp6Server(srv, json));
-    ASSERT_TRUE(x);
-    comment_ = parseAnswer(rcode_, x);
-
-    ASSERT_EQ(0, rcode_);
+    ASSERT_NO_THROW(configure(config));
 
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
     sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
     // Pass it to the server and get an advertise
-    Pkt6Ptr adv = srv.processSolicit(sol);
+    Pkt6Ptr adv = srv_.processSolicit(sol);
 
     // check if we get response at all
     ASSERT_TRUE(adv);
@@ -349,7 +347,7 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
     sol->addOption(option_oro);
 
     // Need to process SOLICIT again after requesting new option.
-    adv = srv.processSolicit(sol);
+    adv = srv_.processSolicit(sol);
     ASSERT_TRUE(adv);
 
     OptionPtr tmp = adv->getOption(D6O_NAME_SERVERS);
@@ -404,6 +402,7 @@ TEST_F(Dhcpv6SrvTest, SolicitBasic) {
 
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
     sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
@@ -447,6 +446,7 @@ TEST_F(Dhcpv6SrvTest, pdSolicitBasic) {
 
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
     sol->addOption(generateIA(D6O_IA_PD, 234, 1500, 3000));
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
@@ -492,6 +492,7 @@ TEST_F(Dhcpv6SrvTest, SolicitHint) {
     // Let's create a SOLICIT
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
 
     // with a valid hint
@@ -546,6 +547,7 @@ TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
     // Let's create a SOLICIT
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
     IOAddress hint("2001:db8:1::cafe:babe");
     ASSERT_FALSE(subnet_->inPool(Lease::TYPE_NA, hint));
@@ -596,6 +598,10 @@ TEST_F(Dhcpv6SrvTest, ManySolicits) {
     sol2->setRemoteAddr(IOAddress("fe80::1223"));
     sol3->setRemoteAddr(IOAddress("fe80::3467"));
 
+    sol1->setIface("eth0");
+    sol2->setIface("eth0");
+    sol3->setIface("eth0");
+
     sol1->addOption(generateIA(D6O_IA_NA, 1, 1500, 3000));
     sol2->addOption(generateIA(D6O_IA_NA, 2, 1500, 3000));
     sol3->addOption(generateIA(D6O_IA_NA, 3, 1500, 3000));
@@ -673,6 +679,7 @@ TEST_F(Dhcpv6SrvTest, RequestBasic) {
     // Let's create a REQUEST
     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
     req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
 
     // with a valid hint
@@ -737,6 +744,7 @@ TEST_F(Dhcpv6SrvTest, pdRequestBasic) {
     // Let's create a REQUEST
     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
     req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_PD, 234, 1500, 3000);
 
     // with a valid hint
@@ -800,6 +808,10 @@ TEST_F(Dhcpv6SrvTest, ManyRequests) {
     req2->setRemoteAddr(IOAddress("fe80::1223"));
     req3->setRemoteAddr(IOAddress("fe80::3467"));
 
+    req1->setIface("eth0");
+    req2->setIface("eth0");
+    req3->setIface("eth0");
+
     req1->addOption(generateIA(D6O_IA_NA, 1, 1500, 3000));
     req2->addOption(generateIA(D6O_IA_NA, 2, 1500, 3000));
     req3->addOption(generateIA(D6O_IA_NA, 3, 1500, 3000));
@@ -1122,15 +1134,16 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
 
     // CASE 1: We have only one subnet defined and we received local traffic.
-    // The only available subnet should be selected
+    // The only available subnet used to be picked, but not anymore
     CfgMgr::instance().deleteSubnets6();
     CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
 
     Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     pkt->setRemoteAddr(IOAddress("fe80::abcd"));
 
-    Subnet6Ptr selected = srv.selectSubnet(pkt);
-    EXPECT_EQ(selected, subnet1);
+    // The clause for assuming local subnet if there is only one subnet is was
+    // removed.
+    EXPECT_FALSE(srv.selectSubnet(pkt));
 
     // CASE 2: We have only one subnet defined and we received relayed traffic.
     // We should NOT select it.
@@ -1139,7 +1152,7 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     CfgMgr::instance().deleteSubnets6();
     CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
     pkt->setRemoteAddr(IOAddress("2001:db8:abcd::2345"));
-    selected = srv.selectSubnet(pkt);
+    Subnet6Ptr selected = srv.selectSubnet(pkt);
     EXPECT_FALSE(selected);
 
     // CASE 3: We have three subnets defined and we received local traffic.
@@ -1169,9 +1182,7 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
     CfgMgr::instance().addSubnet6(subnet2);
     CfgMgr::instance().addSubnet6(subnet3);
     pkt->setRemoteAddr(IOAddress("2001:db8:4::baca"));
-    selected = srv.selectSubnet(pkt);
-    EXPECT_FALSE(selected);
-
+    EXPECT_FALSE(srv.selectSubnet(pkt));
 }
 
 // This test verifies if selectSubnet() selects proper subnet for a given
@@ -1497,7 +1508,9 @@ TEST_F(Dhcpv6SrvTest, docsisVendorORO) {
 // This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
 // vendor options is parsed correctly and the requested options are actually assigned.
 TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
-    ConstElementPtr x;
+
+    IfaceMgrTestConfig test_config(true);
+
     string config = "{ \"interfaces\": [ \"all\" ],"
         "\"preferred-lifetime\": 3000,"
         "\"rebind-timer\": 2000, "
@@ -1526,28 +1539,21 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
         "    \"preferred-lifetime\": 3000,"
         "    \"valid-lifetime\": 4000,"
         "    \"interface-id\": \"\","
-        "    \"interface\": \"\""
+        "    \"interface\": \"eth0\""
         " } ],"
         "\"valid-lifetime\": 4000 }";
 
-    ElementPtr json = Element::fromJSON(config);
-
-    NakedDhcpv6Srv srv(0);
-
-    EXPECT_NO_THROW(x = configureDhcp6Server(srv, json));
-    ASSERT_TRUE(x);
-    comment_ = parseAnswer(rcode_, x);
-
-    ASSERT_EQ(0, rcode_);
+    EXPECT_NO_THROW(configure(config));
 
     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
     sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface("eth0");
     sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
     // Pass it to the server and get an advertise
-    Pkt6Ptr adv = srv.processSolicit(sol);
+    Pkt6Ptr adv = srv_.processSolicit(sol);
 
     // check if we get response at all
     ASSERT_TRUE(adv);
@@ -1566,7 +1572,7 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
     sol->addOption(vendor);
 
     // Need to process SOLICIT again after requesting new option.
-    adv = srv.processSolicit(sol);
+    adv = srv_.processSolicit(sol);
     ASSERT_TRUE(adv);
 
     // Check if thre is vendor option response

+ 40 - 0
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -14,13 +14,39 @@
 
 #include <gtest/gtest.h>
 #include <dhcp6/tests/dhcp6_test_utils.h>
+#include <dhcp6/config_parser.h>
 
+using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
 
 namespace isc {
 namespace test {
 
+Dhcpv6SrvTest::Dhcpv6SrvTest()
+:srv_(0) {
+    subnet_ = isc::dhcp::Subnet6Ptr
+        (new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
+                                48, 1000, 2000, 3000, 4000));
+    subnet_->setIface("eth0");
+
+    pool_ = isc::dhcp::Pool6Ptr
+        (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
+                              isc::asiolink::IOAddress("2001:db8:1:1::"),
+                              64));
+    subnet_->addPool(pool_);
+
+    isc::dhcp::CfgMgr::instance().deleteSubnets6();
+    isc::dhcp::CfgMgr::instance().addSubnet6(subnet_);
+
+    // configure PD pool
+    pd_pool_ = isc::dhcp::Pool6Ptr
+        (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
+                              isc::asiolink::IOAddress("2001:db8:1:2::"),
+                              64, 80));
+    subnet_->addPool(pd_pool_);
+}
+
 // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
 // It returns IAADDR option for each chaining with checkIAAddr method.
 boost::shared_ptr<Option6IAAddr>
@@ -125,6 +151,7 @@ Dhcpv6SrvTest::createMessage(uint8_t message_type, Lease::Type lease_type,
     // Let's create a RENEW
     Pkt6Ptr msg = Pkt6Ptr(new Pkt6(message_type, 1234));
     msg->setRemoteAddr(IOAddress("fe80::abcd"));
+    msg->setIface("eth0");
 
     uint16_t code;
     OptionPtr subopt;
@@ -544,6 +571,19 @@ Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
     EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
 }
 
+void
+Dhcpv6SrvTest::configure(const std::string& config) {
+    ElementPtr json = data::Element::fromJSON(config);
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+    int rcode;
+    ConstElementPtr comment = config::parseAnswer(rcode, status);
+    ASSERT_EQ(0, rcode);
+}
+
 
 // Generate IA_NA option with specified parameters
 boost::shared_ptr<Option6IA>

+ 10 - 20
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -339,26 +339,7 @@ public:
     ///
     /// Sets up a single subnet6 with one pool for addresses and second
     /// pool for prefixes.
-    Dhcpv6SrvTest() {
-        subnet_ = isc::dhcp::Subnet6Ptr
-            (new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
-                                    48, 1000, 2000, 3000, 4000));
-        pool_ = isc::dhcp::Pool6Ptr
-            (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
-                                  isc::asiolink::IOAddress("2001:db8:1:1::"),
-                                  64));
-        subnet_->addPool(pool_);
-
-        isc::dhcp::CfgMgr::instance().deleteSubnets6();
-        isc::dhcp::CfgMgr::instance().addSubnet6(subnet_);
-
-        // configure PD pool
-        pd_pool_ = isc::dhcp::Pool6Ptr
-            (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
-                                  isc::asiolink::IOAddress("2001:db8:1:2::"),
-                                  64, 80));
-        subnet_->addPool(pd_pool_);
-    }
+    Dhcpv6SrvTest();
 
     /// @brief destructor
     ///
@@ -367,6 +348,12 @@ public:
         isc::dhcp::CfgMgr::instance().deleteSubnets6();
     };
 
+    /// @brief Runs DHCPv6 configuration from the JSON string.
+    ///
+    /// @param config String holding server configuration in JSON format.
+    void
+    configure(const std::string& config);
+
     /// @brief Checks that server response (ADVERTISE or REPLY) contains proper
     ///        IA_NA option
     ///
@@ -524,6 +511,9 @@ public:
 
     /// A prefix pool used in most tests
     isc::dhcp::Pool6Ptr pd_pool_;
+
+    /// @brief Server object under test.
+    NakedDhcpv6Srv srv_;
 };
 
 }; // end of isc::test namespace

+ 2 - 0
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -98,6 +98,7 @@ public:
                             OptionPtr srvid = OptionPtr()) {
         Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
         pkt->setRemoteAddr(IOAddress("fe80::abcd"));
+        pkt->setIface("eth0");
         Option6IAPtr ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
 
         if (msg_type != DHCPV6_REPLY) {
@@ -844,6 +845,7 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestReuseExpiredLease) {
     CfgMgr::instance().deleteSubnets6();
     subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1:1::"), 56, 1, 2,
                                      3, 4));
+    subnet_->setIface("eth0");
     pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr));
     subnet_->addPool(pool_);
     CfgMgr::instance().addSubnet6(subnet_);

+ 3 - 0
src/bin/dhcp6/tests/hooks_unittest.cc

@@ -1066,6 +1066,7 @@ TEST_F(HooksDhcpv6SrvTest, basic_lease6_renew) {
     // Let's create a RENEW
     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
     req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
 
     OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
@@ -1163,6 +1164,7 @@ TEST_F(HooksDhcpv6SrvTest, leaseUpdate_lease6_renew) {
     // Let's create a RENEW
     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
     req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
 
     OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
@@ -1254,6 +1256,7 @@ TEST_F(HooksDhcpv6SrvTest, skip_lease6_renew) {
     // Let's create a RENEW
     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
     req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
     boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
 
     OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));

+ 2 - 0
src/lib/dhcp/tests/Makefile.am

@@ -36,6 +36,7 @@ noinst_LTLIBRARIES = libdhcptest.la
 
 libdhcptest_la_SOURCES  = iface_mgr_test_config.cc iface_mgr_test_config.h
 libdhcptest_la_SOURCES  += pkt_filter_test_stub.cc pkt_filter_test_stub.h
+libdhcptest_la_SOURCES  += pkt_filter6_test_stub.cc pkt_filter6_test_stub.h
 libdhcptest_la_CXXFLAGS  = $(AM_CXXFLAGS)
 libdhcptest_la_CPPFLAGS  = $(AM_CPPFLAGS)
 libdhcptest_la_LDFLAGS   = $(AM_LDFLAGS)
@@ -71,6 +72,7 @@ libdhcp___unittests_SOURCES += pkt_filter_unittest.cc
 libdhcp___unittests_SOURCES += pkt_filter_inet_unittest.cc
 libdhcp___unittests_SOURCES += pkt_filter_inet6_unittest.cc
 libdhcp___unittests_SOURCES += pkt_filter_test_stub.cc pkt_filter_test_stub.h
+libdhcp___unittests_SOURCES += pkt_filter6_test_stub.cc pkt_filter_test_stub.h
 libdhcp___unittests_SOURCES += pkt_filter_test_utils.h pkt_filter_test_utils.cc
 libdhcp___unittests_SOURCES += pkt_filter6_test_utils.h pkt_filter6_test_utils.cc
 

+ 3 - 0
src/lib/dhcp/tests/iface_mgr_test_config.cc

@@ -16,6 +16,7 @@
 #include <dhcp/pkt_filter_inet.h>
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcp/tests/pkt_filter_test_stub.h>
+#include <dhcp/tests/pkt_filter6_test_stub.h>
 
 using namespace isc::asiolink;
 
@@ -27,7 +28,9 @@ IfaceMgrTestConfig::IfaceMgrTestConfig(const bool default_config) {
     IfaceMgr::instance().closeSockets();
     IfaceMgr::instance().clearIfaces();
     packet_filter4_ = PktFilterPtr(new PktFilterTestStub());
+    packet_filter6_ = PktFilter6Ptr(new PktFilter6TestStub());
     IfaceMgr::instance().setPacketFilter(packet_filter4_);
+    IfaceMgr::instance().setPacketFilter(packet_filter6_);
 
     // Create default set of fake interfaces: lo, eth0 and eth1.
     if (default_config) {

+ 2 - 0
src/lib/dhcp/tests/iface_mgr_test_config.h

@@ -232,6 +232,8 @@ private:
     /// @brief Currently used packet filter for DHCPv4.
     PktFilterPtr packet_filter4_;
 
+    /// @brief Currently used packet filter for DHCPv6.
+    PktFilter6Ptr packet_filter6_;
 };
 
 };

+ 49 - 0
src/lib/dhcp/tests/pkt_filter6_test_stub.cc

@@ -0,0 +1,49 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcp/tests/pkt_filter6_test_stub.h>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+PktFilter6TestStub::PktFilter6TestStub() {
+}
+
+SocketInfo
+PktFilter6TestStub::openSocket(const Iface&,
+           const isc::asiolink::IOAddress& addr,
+           const uint16_t port, const bool) {
+    return (SocketInfo(addr, port, 0));
+}
+
+Pkt6Ptr
+PktFilter6TestStub::receive(const SocketInfo&) {
+    return Pkt6Ptr();
+}
+
+bool
+PktFilter6TestStub::joinMulticast(int, const std::string&,
+                                  const std::string &) {
+    return (true);
+}
+
+int
+PktFilter6TestStub::send(const Iface&, uint16_t, const Pkt6Ptr&) {
+    return (0);
+}
+
+}
+}
+}

+ 99 - 0
src/lib/dhcp/tests/pkt_filter6_test_stub.h

@@ -0,0 +1,99 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef PKT_FILTER6_TEST_STUB_H
+#define PKT_FILTER6_TEST_STUB_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcp/pkt_filter6.h>
+#include <dhcp/pkt6.h>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief A stub implementation of the PktFilter6 class.
+///
+/// This class implements abstract methods of the @c isc::dhcp::PktFilter6
+/// class. It is used by unit tests, which test protected methods of the
+/// @c isc::dhcp::test::PktFilter6 class. The implemented abstract methods are
+/// no-op.
+class PktFilter6TestStub : public PktFilter6 {
+public:
+
+    /// @brief Constructor.
+    PktFilter6TestStub();
+
+    /// @brief Simulate opening of the socket.
+    ///
+    /// This function simulates opening a primary socket. In reality, it doesn't
+    /// open a socket but the socket descriptor returned in the SocketInfo
+    /// structure is always set to 0.
+    ///
+    /// @param iface An interface descriptor.
+    /// @param addr Address on the interface to be used to send packets.
+    /// @param port Port number to bind socket to.
+    /// @param join_multicast A flag which indicates if the socket should be
+    /// configured to join multicast (if true).
+    ///
+    /// @note All parameters are ignored.
+    ///
+    /// @return A SocketInfo structure with the socket descriptor set to 0. The
+    /// fallback socket descriptor is set to a negative value.
+    virtual SocketInfo openSocket(const Iface& iface,
+                                  const isc::asiolink::IOAddress& addr,
+                                  const uint16_t port,
+                                  const bool join_multicast);
+
+    /// @brief Simulate reception of the DHCPv6 message.
+    ///
+    /// @param socket_info A structure holding socket information.
+    ///
+    /// @note All parameters are ignored.
+    ///
+    /// @return always a NULL object.
+    virtual Pkt6Ptr receive(const SocketInfo& socket_info);
+
+    /// @brief Simulates sending a DHCPv6 message.
+    ///
+    /// This function does nothing.
+    ///
+    /// @param iface An interface to be used to send DHCPv6 message.
+    /// @param port A port used to send a message.
+    /// @param pkt A DHCPv6 to be sent.
+    ///
+    /// @note All parameters are ignored.
+    ///
+    /// @return 0.
+    virtual int send(const Iface& iface, uint16_t port, const Pkt6Ptr& pkt);
+
+    /// @brief Simulate joining IPv6 multicast group on a socket.
+    ///
+    /// @note All parameters are ignored.
+    ///
+    /// @param sock A socket descriptor (socket must be bound).
+    /// @param ifname An interface name (for link-scoped multicast groups).
+    /// @param mcast A multicast address to join (e.g. "ff02::1:2").
+    ///
+    /// @return true if multicast join was successful
+    static bool joinMulticast(int sock, const std::string& ifname,
+                              const std::string & mcast);
+};
+
+} // namespace isc::dhcp::test
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif // PKT_FILTER_TEST_STUB_H

+ 0 - 15
src/lib/dhcpsrv/cfgmgr.cc

@@ -157,21 +157,6 @@ CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint,
                    const isc::dhcp::ClientClasses& classes,
                    const bool relay) {
 
-    // If there's only one subnet configured, let's just use it
-    // The idea is to keep small deployments easy. In a small network - one
-    // router that also runs DHCPv6 server. User specifies a single pool and
-    // expects it to just work. Without this, the server would complain that it
-    // doesn't have IP address on its interfaces that matches that
-    // configuration. Such requirement makes sense in IPv4, but not in IPv6.
-    // The server does not need to have a global address (using just link-local
-    // is ok for DHCPv6 server) from the pool it serves.
-    if ((subnets6_.size() == 1) && hint.isV6LinkLocal()) {
-        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
-                  DHCPSRV_CFGMGR_ONLY_SUBNET6)
-                  .arg(subnets6_[0]->toText()).arg(hint.toText());
-        return (subnets6_[0]);
-    }
-
     // If there is more than one, we need to choose the proper one
     for (Subnet6Collection::iterator subnet = subnets6_.begin();
          subnet != subnets6_.end(); ++subnet) {

+ 8 - 8
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

@@ -626,10 +626,10 @@ TEST_F(CfgMgrTest, subnet6) {
     // Now we have only one subnet, any request will be served from it
     EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
 
-    // If we have only a single subnet and the request came from a local
-    // address, let's use that subnet
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"),
-                  classify_));
+    // We used to allow getting a sole subnet if there was only one subnet
+    // configured. That is no longer true. The code should not return
+    // a subnet.
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
 
     cfg_mgr.addSubnet6(subnet2);
     cfg_mgr.addSubnet6(subnet3);
@@ -670,10 +670,10 @@ TEST_F(CfgMgrTest, subnet6Interface) {
     // only one subnet defined.
     EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
 
-    // If we have only a single subnet and the request came from a local
-    // address, let's use that subnet
-    EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"),
-                                          classify_));
+    // We used to allow getting a sole subnet if there was only one subnet
+    // configured. That is no longer true. The code should not return
+    // a subnet.
+    EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
 
     cfg_mgr.addSubnet6(subnet2);
     cfg_mgr.addSubnet6(subnet3);