Browse Source

[3231] Set fake interface for the incoming packet in DHCPv4 unit tests.

Marcin Siodelski 11 years ago
parent
commit
c56b6109a0

+ 108 - 82
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -62,53 +62,6 @@ namespace {
 /// dummy server-id file location
 const char* SRVID_FILE = "server-id-test.txt";
 
-// Sanity check. Verifies that both Dhcpv4Srv and its derived
-// class NakedDhcpv4Srv can be instantiated and destroyed.
-TEST_F(Dhcpv4SrvTest, basic) {
-
-    // Check that the base class can be instantiated
-    boost::scoped_ptr<Dhcpv4Srv> srv;
-    ASSERT_NO_THROW(srv.reset(new Dhcpv4Srv(DHCP4_SERVER_PORT + 10000, "type=memfile",
-                                            false, false)));
-    srv.reset();
-    // We have to close open sockets because further in this test we will
-    // call the Dhcpv4Srv constructor again. This constructor will try to
-    // set the appropriate packet filter class for IfaceMgr. This requires
-    // that all sockets are closed.
-    IfaceMgr::instance().closeSockets();
-
-    // Check that the derived class can be instantiated
-    boost::scoped_ptr<NakedDhcpv4Srv> naked_srv;
-    ASSERT_NO_THROW(
-        naked_srv.reset(new NakedDhcpv4Srv(DHCP4_SERVER_PORT + 10000)));
-    EXPECT_TRUE(naked_srv->getServerID());
-    // Close sockets again for the next test.
-    IfaceMgr::instance().closeSockets();
-
-    ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
-    EXPECT_TRUE(naked_srv->getServerID());
-}
-
-// This test verifies that exception is not thrown when an error occurs during
-// opening sockets. This test forces an error by adding a fictious interface
-// to the IfaceMgr. An attempt to open socket on this interface must always
-// fail. The DHCPv4 installs the error handler function to prevent exceptions
-// being thrown from the openSockets4 function.
-// @todo The server tests for socket should be extended but currently the
-// ability to unit test the sockets code is somewhat limited.
-TEST_F(Dhcpv4SrvTest, openActiveSockets) {
-    ASSERT_NO_THROW(CfgMgr::instance().activateAllIfaces());
-
-    Iface iface("bogusiface", 255);
-    iface.flag_loopback_ = false;
-    iface.flag_up_ = true;
-    iface.flag_running_ = true;
-    iface.inactive4_ = false;
-    iface.addAddress(IOAddress("192.0.0.0"));
-    IfaceMgr::instance().addInterface(iface);
-    ASSERT_NO_THROW(Dhcpv4Srv::openActiveSockets(DHCP4_SERVER_PORT, false));
-}
-
 // This test verifies that the destination address of the response
 // message is set to giaddr, when giaddr is set to non-zero address
 // in the received message.
@@ -301,6 +254,53 @@ TEST_F(Dhcpv4SrvTest, adjustRemoteAddressBroadcast) {
     EXPECT_EQ("255.255.255.255", resp->getRemoteAddr().toText());
 }
 
+// Sanity check. Verifies that both Dhcpv4Srv and its derived
+// class NakedDhcpv4Srv can be instantiated and destroyed.
+TEST_F(Dhcpv4SrvTest, basic) {
+
+    // Check that the base class can be instantiated
+    boost::scoped_ptr<Dhcpv4Srv> srv;
+    ASSERT_NO_THROW(srv.reset(new Dhcpv4Srv(DHCP4_SERVER_PORT + 10000, "type=memfile",
+                                            false, false)));
+    srv.reset();
+    // We have to close open sockets because further in this test we will
+    // call the Dhcpv4Srv constructor again. This constructor will try to
+    // set the appropriate packet filter class for IfaceMgr. This requires
+    // that all sockets are closed.
+    IfaceMgr::instance().closeSockets();
+
+    // Check that the derived class can be instantiated
+    boost::scoped_ptr<NakedDhcpv4Srv> naked_srv;
+    ASSERT_NO_THROW(
+        naked_srv.reset(new NakedDhcpv4Srv(DHCP4_SERVER_PORT + 10000)));
+    EXPECT_TRUE(naked_srv->getServerID());
+    // Close sockets again for the next test.
+    IfaceMgr::instance().closeSockets();
+
+    ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
+    EXPECT_TRUE(naked_srv->getServerID());
+}
+
+// This test verifies that exception is not thrown when an error occurs during
+// opening sockets. This test forces an error by adding a fictious interface
+// to the IfaceMgr. An attempt to open socket on this interface must always
+// fail. The DHCPv4 installs the error handler function to prevent exceptions
+// being thrown from the openSockets4 function.
+// @todo The server tests for socket should be extended but currently the
+// ability to unit test the sockets code is somewhat limited.
+TEST_F(Dhcpv4SrvTest, openActiveSockets) {
+    ASSERT_NO_THROW(CfgMgr::instance().activateAllIfaces());
+
+    Iface iface("bogusiface", 255);
+    iface.flag_loopback_ = false;
+    iface.flag_up_ = true;
+    iface.flag_running_ = true;
+    iface.inactive4_ = false;
+    iface.addAddress(IOAddress("192.0.0.0"));
+    IfaceMgr::instance().addInterface(iface);
+    ASSERT_NO_THROW(Dhcpv4Srv::openActiveSockets(DHCP4_SERVER_PORT, false));
+}
+
 // Verifies that DISCOVER message can be processed correctly,
 // that the OFFER message generated in response is valid and
 // contains necessary options.
@@ -309,7 +309,7 @@ TEST_F(Dhcpv4SrvTest, adjustRemoteAddressBroadcast) {
 // are other tests that verify correctness of the allocation
 // engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
 // and DiscoverInvalidHint.
-TEST_F(Dhcpv4SrvTest, processDiscover) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, processDiscover) {
     testDiscoverRequest(DHCPDISCOVER);
 }
 
@@ -321,11 +321,11 @@ TEST_F(Dhcpv4SrvTest, processDiscover) {
 // are other tests that verify correctness of the allocation
 // engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
 // and DiscoverInvalidHint.
-TEST_F(Dhcpv4SrvTest, processRequest) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, processRequest) {
     testDiscoverRequest(DHCPREQUEST);
 }
 
-TEST_F(Dhcpv4SrvTest, processRelease) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, processRelease) {
     NakedDhcpv4Srv srv;
     Pkt4Ptr pkt(new Pkt4(DHCPRELEASE, 1234));
 
@@ -333,7 +333,7 @@ TEST_F(Dhcpv4SrvTest, processRelease) {
     EXPECT_NO_THROW(srv.processRelease(pkt));
 }
 
-TEST_F(Dhcpv4SrvTest, processDecline) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, processDecline) {
     NakedDhcpv4Srv srv;
     Pkt4Ptr pkt(new Pkt4(DHCPDECLINE, 1234));
 
@@ -341,7 +341,7 @@ TEST_F(Dhcpv4SrvTest, processDecline) {
     EXPECT_NO_THROW(srv.processDecline(pkt));
 }
 
-TEST_F(Dhcpv4SrvTest, processInform) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, processInform) {
     NakedDhcpv4Srv srv;
     Pkt4Ptr pkt(new Pkt4(DHCPINFORM, 1234));
 
@@ -398,7 +398,7 @@ TEST_F(Dhcpv4SrvTest, serverReceivedPacketName) {
 // - copy of client-id
 // - server-id
 // - offered address
-TEST_F(Dhcpv4SrvTest, DiscoverBasic) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, DiscoverBasic) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -406,6 +406,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverBasic) {
     dis->setRemoteAddr(IOAddress("192.0.2.1"));
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
+    dis->setIface("eth0");
 
     // Pass it to the server and get an offer
     Pkt4Ptr offer = srv->processDiscover(dis);
@@ -435,7 +436,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverBasic) {
 // - copy of client-id
 // - server-id
 // - offered address
-TEST_F(Dhcpv4SrvTest, DiscoverHint) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, DiscoverHint) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
     IOAddress hint("192.0.2.107");
@@ -445,6 +446,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverHint) {
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
     dis->setYiaddr(hint);
+    dis->setIface("eth0");
 
     // Pass it to the server and get an offer
     Pkt4Ptr offer = srv->processDiscover(dis);
@@ -475,7 +477,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverHint) {
 // - copy of client-id
 // - server-id
 // - offered address
-TEST_F(Dhcpv4SrvTest, DiscoverNoClientId) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, DiscoverNoClientId) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
     IOAddress hint("192.0.2.107");
@@ -484,6 +486,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverNoClientId) {
     dis->setRemoteAddr(IOAddress("192.0.2.1"));
     dis->setYiaddr(hint);
     dis->setHWAddr(generateHWAddr(6));
+    dis->setIface("eth0");
 
     // Pass it to the server and get an offer
     Pkt4Ptr offer = srv->processDiscover(dis);
@@ -513,7 +516,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverNoClientId) {
 // - copy of client-id
 // - server-id
 // - offered address (!= hint)
-TEST_F(Dhcpv4SrvTest, DiscoverInvalidHint) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, DiscoverInvalidHint) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
     IOAddress hint("10.1.2.3");
@@ -523,6 +526,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverInvalidHint) {
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
     dis->setYiaddr(hint);
+    dis->setIface("eth0");
 
     // Pass it to the server and get an offer
     Pkt4Ptr offer = srv->processDiscover(dis);
@@ -551,7 +555,7 @@ TEST_F(Dhcpv4SrvTest, DiscoverInvalidHint) {
 // and this is a correct behavior. It is REQUEST that will fail for the third
 // client. OFFER is basically saying "if you send me a request, you will
 // probably get an address like this" (there are no guarantees).
-TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, ManyDiscovers) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -563,6 +567,11 @@ TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
     dis2->setRemoteAddr(IOAddress("192.0.2.2"));
     dis3->setRemoteAddr(IOAddress("192.0.2.3"));
 
+    // Assign interfaces
+    dis1->setIface("eth0");
+    dis2->setIface("eth0");
+    dis3->setIface("eth0");
+
     // Different client-id sizes
     OptionPtr clientid1 = generateClientId(4); // length 4
     OptionPtr clientid2 = generateClientId(5); // length 5
@@ -623,7 +632,7 @@ TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
 // - assigned address
 //
 // Test verifies that the lease is actually in the database.
-TEST_F(Dhcpv4SrvTest, RequestBasic) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, RequestBasic) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -633,6 +642,7 @@ TEST_F(Dhcpv4SrvTest, RequestBasic) {
     OptionPtr clientid = generateClientId();
     req->addOption(clientid);
     req->setYiaddr(hint);
+    req->setIface("eth0");
 
     // Pass it to the server and get an advertise
     Pkt4Ptr ack = srv->processRequest(req);
@@ -668,7 +678,7 @@ TEST_F(Dhcpv4SrvTest, RequestBasic) {
 // - copy of client-id
 // - server-id
 // - assigned address (different for each client)
-TEST_F(Dhcpv4SrvTest, ManyRequests) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, ManyRequests) {
 
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
@@ -686,6 +696,11 @@ TEST_F(Dhcpv4SrvTest, ManyRequests) {
     req2->setRemoteAddr(relay);
     req3->setRemoteAddr(relay);
 
+    // Assign interfaces
+    req1->setIface("eth0");
+    req2->setIface("eth0");
+    req3->setIface("eth0");
+
     req1->setYiaddr(req_addr1);
     req2->setYiaddr(req_addr2);
     req3->setYiaddr(req_addr3);
@@ -760,7 +775,7 @@ TEST_F(Dhcpv4SrvTest, ManyRequests) {
 // - returned REPLY message has server-id
 // - returned REPLY message has IA that includes IAADDR
 // - lease is actually renewed in LeaseMgr
-TEST_F(Dhcpv4SrvTest, RenewBasic) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, RenewBasic) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -800,6 +815,7 @@ TEST_F(Dhcpv4SrvTest, RenewBasic) {
     req->setRemoteAddr(IOAddress(addr));
     req->setYiaddr(addr);
     req->setCiaddr(addr); // client's address
+    req->setIface("eth0");
 
     req->addOption(clientid);
     req->addOption(srv->getServerID());
@@ -840,7 +856,7 @@ TEST_F(Dhcpv4SrvTest, RenewBasic) {
 // @todo: Implement tests for rejecting renewals
 
 // This test verifies if the sanityCheck() really checks options presence.
-TEST_F(Dhcpv4SrvTest, sanityCheck) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, sanityCheck) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -871,7 +887,7 @@ TEST_F(Dhcpv4SrvTest, sanityCheck) {
 // This test verifies that incoming (positive) RELEASE can be handled properly.
 // As there is no REPLY in DHCPv4, the only thing to verify here is that
 // the lease is indeed removed from the database.
-TEST_F(Dhcpv4SrvTest, ReleaseBasic) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, ReleaseBasic) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -908,6 +924,7 @@ TEST_F(Dhcpv4SrvTest, ReleaseBasic) {
     rel->addOption(clientid);
     rel->addOption(srv->getServerID());
     rel->setHWAddr(hw);
+    rel->setIface("eth0");
 
     // Pass it to the server and hope for a REPLY
     // Note: this is no response to RELEASE in DHCPv4
@@ -942,7 +959,7 @@ TEST_F(Dhcpv4SrvTest, ReleaseBasic) {
 // 1. there is no such lease at all
 // 2. there is such a lease, but it is assigned to a different IAID
 // 3. there is such a lease, but it belongs to a different client
-TEST_F(Dhcpv4SrvTest, ReleaseReject) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, ReleaseReject) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
 
@@ -971,6 +988,7 @@ TEST_F(Dhcpv4SrvTest, ReleaseReject) {
     rel->addOption(clientid);
     rel->addOption(srv->getServerID());
     rel->setHWAddr(bogus_hw);
+    rel->setIface("eth0");
 
     // Case 1: No lease known to server
     SCOPED_TRACE("CASE 1: Lease is not known to the server");
@@ -1031,7 +1049,7 @@ TEST_F(Dhcpv4SrvTest, ReleaseReject) {
 
 // This test verifies if the server-id disk operations (read, write) are
 // working properly.
-TEST_F(Dhcpv4SrvTest, ServerID) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, ServerID) {
     NakedDhcpv4Srv srv(0);
 
     string srvid_text = "192.0.2.100";
@@ -1060,7 +1078,7 @@ TEST_F(Dhcpv4SrvTest, ServerID) {
 }
 
 // Checks if received relay agent info option is echoed back to the client
-TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, relayAgentInfoEcho) {
 
     NakedDhcpv4Srv srv(0);
 
@@ -1103,7 +1121,7 @@ TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
 
 // Checks if vendor options are parsed correctly and requested vendor options
 // are echoed back.
-TEST_F(Dhcpv4SrvTest, vendorOptionsDocsis) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, vendorOptionsDocsis) {
 
     NakedDhcpv4Srv srv(0);
 
@@ -1123,7 +1141,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsDocsis) {
         "    \"rebind-timer\": 2000, "
         "    \"renew-timer\": 1000, "
         "    \"valid-lifetime\": 4000,"
-        "    \"interface\": \"" + valid_iface_ + "\" "
+        "    \"interface\": \"eth0\" "
         " } ],"
         "\"valid-lifetime\": 4000 }";
 
@@ -1297,7 +1315,7 @@ TEST_F(Dhcpv4SrvTest, unpackOptions) {
 
 // Checks whether the server uses default (0.0.0.0) siaddr value, unless
 // explicitly specified
-TEST_F(Dhcpv4SrvTest, siaddrDefault) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, siaddrDefault) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
     IOAddress hint("192.0.2.107");
@@ -1307,6 +1325,7 @@ TEST_F(Dhcpv4SrvTest, siaddrDefault) {
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
     dis->setYiaddr(hint);
+    dis->setIface("eth0");
 
     // Pass it to the server and get an offer
     Pkt4Ptr offer = srv->processDiscover(dis);
@@ -1320,13 +1339,14 @@ TEST_F(Dhcpv4SrvTest, siaddrDefault) {
 }
 
 // Checks whether the server uses specified siaddr value
-TEST_F(Dhcpv4SrvTest, siaddr) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, siaddr) {
     boost::scoped_ptr<NakedDhcpv4Srv> srv;
     ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
     subnet_->setSiaddr(IOAddress("192.0.2.123"));
 
     Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
     dis->setRemoteAddr(IOAddress("192.0.2.1"));
+    dis->setIface("eth0");
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
 
@@ -1345,7 +1365,7 @@ TEST_F(Dhcpv4SrvTest, siaddr) {
 // specific value and returned in server messages. There's also similar test for
 // checking parser only configuration, see Dhcp4ParserTest.nextServerOverride in
 // config_parser_unittest.cc.
-TEST_F(Dhcpv4SrvTest, nextServerOverride) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, nextServerOverride) {
 
     NakedDhcpv4Srv srv(0);
 
@@ -1372,6 +1392,7 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
 
     Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
     dis->setRemoteAddr(IOAddress("192.0.2.1"));
+    dis->setIface("eth0");
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
 
@@ -1387,7 +1408,7 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
 // when there is no specific value defined in subnet and returned to the client
 // properly. There's also similar test for checking parser only configuration,
 // see Dhcp4ParserTest.nextServerGlobal in config_parser_unittest.cc.
-TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, nextServerGlobal) {
 
     NakedDhcpv4Srv srv(0);
 
@@ -1413,6 +1434,7 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
 
     Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
     dis->setRemoteAddr(IOAddress("192.0.2.1"));
+    dis->setIface("eth0");
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
 
@@ -1449,7 +1471,7 @@ const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
 /// can't modify non-static members (for obvious reasons), so many
 /// fields are declared static. It is still better to keep them as
 /// one class rather than unrelated collection of global objects.
-class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
+class HooksDhcpv4SrvTest : public Dhcpv4SrvFakeIfaceTest {
 
 public:
 
@@ -1936,7 +1958,7 @@ TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
 
 // Checks if callouts installed on buffer4_receive is able to change
 // the values and the parameters are indeed used by the server.
-TEST_F(HooksDhcpv4SrvTest, buffer4RreceiveValueChange) {
+TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveValueChange) {
 
     // Install callback that modifies MAC addr of incoming packet
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -2357,7 +2379,7 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
         "\"subnet4\": [ { "
         "    \"pool\": [ \"192.0.2.0/25\" ],"
         "    \"subnet\": \"192.0.2.0/24\", "
-        "    \"interface\": \"" + valid_iface_ + "\" "
+        "    \"interface\": \"eth0\" "
         " }, {"
         "    \"pool\": [ \"192.0.3.0/25\" ],"
         "    \"subnet\": \"192.0.3.0/24\" "
@@ -2376,7 +2398,7 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
     // Prepare discover packet. Server should select first subnet for it
     Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
     sol->setRemoteAddr(IOAddress("192.0.2.1"));
-    sol->setIface(valid_iface_);
+    sol->setIface("eth0");
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
@@ -2423,7 +2445,7 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
         "\"subnet4\": [ { "
         "    \"pool\": [ \"192.0.2.0/25\" ],"
         "    \"subnet\": \"192.0.2.0/24\", "
-        "    \"interface\": \"" + valid_iface_ + "\" "
+        "    \"interface\": \"eth0\" "
         " }, {"
         "    \"pool\": [ \"192.0.3.0/25\" ],"
         "    \"subnet\": \"192.0.3.0/24\" "
@@ -2442,7 +2464,7 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
     // Prepare discover packet. Server should select first subnet for it
     Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
     sol->setRemoteAddr(IOAddress("192.0.2.1"));
-    sol->setIface(valid_iface_);
+    sol->setIface("eth0");
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
@@ -2504,6 +2526,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
     req->setRemoteAddr(IOAddress(addr));
     req->setYiaddr(addr);
     req->setCiaddr(addr); // client's address
+    req->setIface("eth0");
 
     req->addOption(clientid);
     req->addOption(srv_->getServerID());
@@ -2595,6 +2618,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
     req->setRemoteAddr(IOAddress(addr));
     req->setYiaddr(addr);
     req->setCiaddr(addr); // client's address
+    req->setIface("eth0");
 
     req->addOption(clientid);
     req->addOption(srv_->getServerID());
@@ -2766,7 +2790,7 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
 }
 
 // Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems
-TEST_F(Dhcpv4SrvTest, docsisVendorOptionsParse) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, docsisVendorOptionsParse) {
 
     // Let's get a traffic capture from DOCSIS3.0 modem
     Pkt4Ptr dis = captureRelayedDiscover();
@@ -2790,7 +2814,7 @@ TEST_F(Dhcpv4SrvTest, docsisVendorOptionsParse) {
 }
 
 // Checks if server is able to parse incoming docsis option and extract suboption 1 (docsis ORO)
-TEST_F(Dhcpv4SrvTest, docsisVendorORO) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, docsisVendorORO) {
 
     // Let's get a traffic capture from DOCSIS3.0 modem
     Pkt4Ptr dis = captureRelayedDiscover();
@@ -2812,7 +2836,7 @@ TEST_F(Dhcpv4SrvTest, 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(Dhcpv4SrvTest, vendorOptionsORO) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, vendorOptionsORO) {
 
     NakedDhcpv4Srv srv(0);
 
@@ -2833,7 +2857,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
         "    \"rebind-timer\": 2000, "
         "    \"renew-timer\": 1000, "
         "    \"valid-lifetime\": 4000,"
-        "    \"interface\": \"" + valid_iface_ + "\" "
+        "    \"interface\": \"eth0\" "
         " } ],"
         "\"valid-lifetime\": 4000 }";
 
@@ -2849,6 +2873,8 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
     dis->setGiaddr(IOAddress("192.0.2.1"));
     OptionPtr clientid = generateClientId();
     dis->addOption(clientid);
+    // Set interface. It is required by the server to generate server id.
+    dis->setIface("eth0");
 
     // Pass it to the server and get an advertise
     Pkt4Ptr offer = srv.processDiscover(dis);
@@ -2896,7 +2922,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
 
 // Test checks whether it is possible to use option definitions defined in
 // src/lib/dhcp/docsis3_option_defs.h.
-TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
+TEST_F(Dhcpv4SrvFakeIfaceTest, vendorOptionsDocsisDefinitions) {
     ConstElementPtr x;
     string config_prefix = "{ \"interfaces\": [ \"all\" ],"
         "\"rebind-timer\": 2000, "

+ 88 - 74
src/bin/dhcp4/tests/dhcp4_test_utils.cc

@@ -55,16 +55,6 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
 
     // it's ok if that fails. There should not be such a file anyway
     unlink(SRVID_FILE);
-
-    const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
-
-    // There must be some interface detected
-    if (ifaces.empty()) {
-        // We can't use ASSERT in constructor
-        ADD_FAILURE() << "No interfaces detected.";
-    }
-
-    valid_iface_ = ifaces.begin()->getName();
 }
 
 void Dhcpv4SrvTest::addPrlOption(Pkt4Ptr& pkt) {
@@ -319,9 +309,6 @@ Lease4Ptr Dhcpv4SrvTest::checkLease(const Pkt4Ptr& rsp,
     return (lease);
 }
 
-/// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id
-/// @param rsp response packet to be validated
-/// @param expected_srvid expected value of server-id
 void Dhcpv4SrvTest::checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid) {
     // Check that server included its server-id
     OptionPtr opt = rsp->getOption(DHO_DHCP_SERVER_IDENTIFIER);
@@ -381,8 +368,87 @@ Dhcpv4SrvTest::createPacketFromBuffer(const Pkt4Ptr& src_pkt,
     return (::testing::AssertionSuccess());
 }
 
+void Dhcpv4SrvTest::TearDown() {
+
+    CfgMgr::instance().deleteSubnets4();
+
+    // Let's clean up if there is such a file.
+    unlink(SRVID_FILE);
+
+    // Close all open sockets.
+    IfaceMgr::instance().closeSockets();
+
+    // Some unit tests override the default packet filtering class, used
+    // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
+    // capability to directly respond to the clients without IP address
+    // assigned. This capability is not supported by the default packet
+    // filtering class: PktFilterInet. Therefore setting the dummy class
+    // allows to test scenarios, when server responds to the broadcast address
+    // on client's request, despite having support for direct response.
+    // The following call restores the use of original packet filtering class
+    // after the test.
+    try {
+        IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));
+
+    } catch (const Exception& ex) {
+        FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
+               << " class after the test. Exception has been caught: "
+               << ex.what();
+    }
+
+}
+
+Dhcpv4SrvFakeIfaceTest::Dhcpv4SrvFakeIfaceTest()
+: Dhcpv4SrvTest() {
+    // Remove current interface configuration. Instead we want to add
+    // a couple of fake interfaces.
+    IfaceMgr& ifacemgr = IfaceMgr::instance();
+    ifacemgr.closeSockets();
+    ifacemgr.clearIfaces();
+
+    // Add fake interfaces.
+    ifacemgr.addInterface(createIface("lo", 0, "127.0.0.1"));
+    ifacemgr.addInterface(createIface("eth0", 1, "192.0.3.1"));
+    ifacemgr.addInterface(createIface("eth1", 2, "10.0.0.1"));
+
+    // In order to use fake interfaces we have to supply the custom
+    // packet filtering class, which can mimic opening sockets on
+    // fake interafaces.
+    ifacemgr.setPacketFilter(PktFilterPtr(new PktFilterTest()));
+    ifacemgr.openSockets4();
+}
+
+void
+Dhcpv4SrvFakeIfaceTest::TearDown() {
+    // The base class function restores the original packet filtering class.
+    Dhcpv4SrvTest::TearDown();
+    // The base class however, doesn't re-detect real interfaces.
+    try {
+        IfaceMgr::instance().clearIfaces();
+        IfaceMgr::instance().detectIfaces();
+
+    } catch (const Exception& ex) {
+        FAIL() << "Failed to restore interface configuration after using"
+            " fake interfaces";
+    }
+}
+
+Iface
+Dhcpv4SrvFakeIfaceTest::createIface(const std::string& name, const int ifindex,
+                                    const std::string& addr) {
+    Iface iface(name, ifindex);
+    iface.addAddress(IOAddress(addr));
+    if (name == "lo") {
+        iface.flag_loopback_ = true;
+    }
+    iface.flag_up_ = true;
+    iface.flag_running_ = true;
+    iface.inactive4_ = false;
+    return (iface);
+}
 
-void Dhcpv4SrvTest::testDiscoverRequest(const uint8_t msg_type) {
+void
+Dhcpv4SrvFakeIfaceTest::testDiscoverRequest(const uint8_t msg_type) {
     // Create an instance of the tested class.
     boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
 
@@ -431,6 +497,8 @@ void Dhcpv4SrvTest::testDiscoverRequest(const uint8_t msg_type) {
     // which was parsed from its wire format.
     Pkt4Ptr received;
     ASSERT_TRUE(createPacketFromBuffer(req, received));
+    // Set interface. It is required for the server to generate server id.
+    received->setIface("eth0");
     if (msg_type == DHCPDISCOVER) {
         ASSERT_NO_THROW(
             rsp = srv->processDiscover(received);
@@ -464,6 +532,9 @@ void Dhcpv4SrvTest::testDiscoverRequest(const uint8_t msg_type) {
     ASSERT_TRUE(createPacketFromBuffer(req, received));
     ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
 
+    // Set interface. It is required for the server to generate server id.
+    received->setIface("eth0");
+
     if (msg_type == DHCPDISCOVER) {
         ASSERT_NO_THROW(rsp = srv->processDiscover(received));
 
@@ -497,6 +568,9 @@ void Dhcpv4SrvTest::testDiscoverRequest(const uint8_t msg_type) {
     ASSERT_TRUE(createPacketFromBuffer(req, received));
     ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
 
+    // Set interface. It is required for the server to generate server id.
+    received->setIface("eth0");
+
     if (msg_type == DHCPDISCOVER) {
         ASSERT_NO_THROW(rsp = srv->processDiscover(received));
         // Should return non-NULL packet.
@@ -517,66 +591,6 @@ void Dhcpv4SrvTest::testDiscoverRequest(const uint8_t msg_type) {
     EXPECT_TRUE(noBasicOptions(rsp));
 }
 
-/// @brief This function cleans up after the test.
-void Dhcpv4SrvTest::TearDown() {
-
-    CfgMgr::instance().deleteSubnets4();
-
-    // Let's clean up if there is such a file.
-    unlink(SRVID_FILE);
-
-    // Close all open sockets.
-    IfaceMgr::instance().closeSockets();
-
-    // Some unit tests override the default packet filtering class, used
-    // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
-    // capability to directly respond to the clients without IP address
-    // assigned. This capability is not supported by the default packet
-    // filtering class: PktFilterInet. Therefore setting the dummy class
-    // allows to test scenarios, when server responds to the broadcast address
-    // on client's request, despite having support for direct response.
-    // The following call restores the use of original packet filtering class
-    // after the test.
-    try {
-        IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));
-
-    } catch (const Exception& ex) {
-        FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
-               << " class after the test. Exception has been caught: "
-               << ex.what();
-    }
-}
-
-Dhcpv4SrvFakeIfaceTest::Dhcpv4SrvFakeIfaceTest() : Dhcpv4SrvTest() {
-    IfaceMgr& ifacemgr = IfaceMgr::instance();
-    ifacemgr.clearIfaces();
-
-    ifacemgr.addInterface(createIface("lo", 0, "127.0.0.1"));
-    ifacemgr.addInterface(createIface("eth0", 0, "192.0.3.1"));
-    ifacemgr.addInterface(createIface("eth1", 0, "10.0.0.1"));
-}
-
-Dhcpv4SrvFakeIfaceTest::~Dhcpv4SrvFakeIfaceTest() {
-    IfaceMgr& ifacemgr = IfaceMgr::instance();
-    ifacemgr.setPacketFilter(PktFilterPtr(new PktFilterInet()));
-    ifacemgr.clearIfaces();
-    ifacemgr.detectIfaces();
-}
-
-Iface
-Dhcpv4SrvFakeIfaceTest::createIface(const std::string& name, const int ifindex,
-                                    const std::string& addr) {
-    Iface iface(name, ifindex);
-    iface.addAddress(IOAddress(addr));
-    if (name == "lo") {
-        iface.flag_loopback_ = true;
-    }
-    iface.flag_up_ = true;
-    iface.flag_running_ = true;
-    iface.inactive4_ = false;
-    return (iface);
-}
-
 }; // end of isc::dhcp::test namespace
 }; // end of isc::dhcp namespace
 }; // end of isc namespace

+ 18 - 20
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -237,24 +237,12 @@ public:
     createPacketFromBuffer(const Pkt4Ptr& src_pkt,
                            Pkt4Ptr& dst_pkt);
 
+
     /// @brief generates a DHCPv4 packet based on provided hex string
     ///
     /// @return created packet
     Pkt4Ptr packetFromCapture(const std::string& hex_string);
 
-    /// @brief Tests if Discover or Request message is processed correctly
-    ///
-    /// This test verifies that the Parameter Request List option is handled
-    /// correctly, i.e. it checks that certain options are present in the
-    /// server's response when they are requested and that they are not present
-    /// when they are not requested or NAK occurs.
-    ///
-    /// @todo We need an additional test for PRL option using real traffic
-    /// capture.
-    ///
-    /// @param msg_type DHCPDISCOVER or DHCPREQUEST
-    void testDiscoverRequest(const uint8_t msg_type);
-
     /// @brief This function cleans up after the test.
     virtual void TearDown();
 
@@ -271,8 +259,6 @@ public:
 
     isc::data::ConstElementPtr comment_;
 
-    // Name of a valid network interface
-    std::string valid_iface_;
 };
 
 /// @brief Test fixture class to be used for tests which require fake
@@ -299,11 +285,8 @@ public:
     /// These interfaces replace the real interfaces detected by the IfaceMgr.
     Dhcpv4SrvFakeIfaceTest();
 
-    /// @brief Destructor.
-    ///
-    /// Re-detects the network interfaces. Also, sets the default packet filter
-    /// class, in case the test has changed it.
-    virtual ~Dhcpv4SrvFakeIfaceTest();
+    /// @brief Restores the original interface configuration.
+    virtual void TearDown();
 
     /// @brief Creates an instance of the interface.
     ///
@@ -314,6 +297,20 @@ public:
     /// @return Iface Instance of the interface.
     static Iface createIface(const std::string& name, const int ifindex,
                              const std::string& addr);
+
+    /// @brief Tests if Discover or Request message is processed correctly
+    ///
+    /// This test verifies that the Parameter Request List option is handled
+    /// correctly, i.e. it checks that certain options are present in the
+    /// server's response when they are requested and that they are not present
+    /// when they are not requested or NAK occurs.
+    ///
+    /// @todo We need an additional test for PRL option using real traffic
+    /// capture.
+    ///
+    /// @param msg_type DHCPDISCOVER or DHCPREQUEST
+    void testDiscoverRequest(const uint8_t msg_type);
+
 };
 
 /// @brief "Naked" DHCPv4 server, exposes internal fields
@@ -382,6 +379,7 @@ public:
     ///
     /// See fake_received_ field for description
     void fakeReceive(const Pkt4Ptr& pkt) {
+        pkt->setIface("eth0");
         fake_received_.push_back(pkt);
     }
 

+ 15 - 3
src/bin/dhcp4/tests/fqdn_unittest.cc

@@ -30,9 +30,9 @@ using namespace isc::dhcp_ddns;
 
 namespace {
 
-class NameDhcpv4SrvTest : public Dhcpv4SrvTest {
+class NameDhcpv4SrvTest : public Dhcpv4SrvFakeIfaceTest {
 public:
-    NameDhcpv4SrvTest() : Dhcpv4SrvTest() {
+    NameDhcpv4SrvTest() : Dhcpv4SrvFakeIfaceTest() {
         srv_ = new NakedDhcpv4Srv(0);
     }
     virtual ~NameDhcpv4SrvTest() {
@@ -110,6 +110,7 @@ public:
                                 const bool include_clientid = true) {
         Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
         pkt->setRemoteAddr(IOAddress("192.0.2.3"));
+        pkt->setIface("eth0");
         // For DISCOVER we don't include server id, because client broadcasts
         // the message to all servers.
         if (msg_type != DHCPDISCOVER) {
@@ -580,7 +581,6 @@ TEST_F(NameDhcpv4SrvTest, processDiscover) {
 
     Pkt4Ptr reply;
     ASSERT_NO_THROW(reply = srv_->processDiscover(req));
-
     checkResponse(reply, DHCPOFFER, 1234);
 
     EXPECT_TRUE(srv_->name_change_reqs_.empty());
@@ -615,6 +615,9 @@ TEST_F(NameDhcpv4SrvTest, processRequestFqdnEmptyDomainName) {
 // to it when Hostname option carries the top level domain-name.
 TEST_F(NameDhcpv4SrvTest, processRequestEmptyHostname) {
     Pkt4Ptr req = generatePktWithHostname(DHCPREQUEST, ".");
+    // Set interface for the incoming packet. The server requires it to
+    // generate client id.
+    req->setIface("eth0");
 
     Pkt4Ptr reply;
     ASSERT_NO_THROW(reply = srv_->processRequest(req));
@@ -691,6 +694,11 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
 TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
     Pkt4Ptr req1 = generatePktWithHostname(DHCPREQUEST, "myhost.example.com.");
 
+    // Set interface for the incoming packet. The server requires it to
+    // generate client id.
+    req1->setIface("eth0");
+
+
     Pkt4Ptr reply;
     ASSERT_NO_THROW(reply = srv_->processRequest(req1));
 
@@ -709,6 +717,10 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
     // another one to add new entry with updated domain-name.
     Pkt4Ptr req2 = generatePktWithHostname(DHCPREQUEST, "otherhost");
 
+    // Set interface for the incoming packet. The server requires it to
+    // generate client id.
+    req2->setIface("eth0");
+
     ASSERT_NO_THROW(reply = srv_->processRequest(req2));
 
     checkResponse(reply, DHCPACK, 1234);

+ 13 - 7
src/lib/dhcp/iface_mgr.cc

@@ -293,6 +293,8 @@ void IfaceMgr::stubDetectIfaces() {
     addInterface(iface);
 }
 
+
+
 bool
 IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
                        IfaceMgrErrorMsgCallback error_handler) {
@@ -554,6 +556,11 @@ IfaceMgr::getIface(const std::string& ifname) {
     return (NULL); // not found
 }
 
+void
+IfaceMgr::clearIfaces() {
+    ifaces_.clear();
+}
+
 int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
                          const uint16_t port, const bool receive_bcast,
                          const bool send_bcast) {
@@ -925,7 +932,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt) {
 
     // Skip checking if packet filter is non-NULL because it has been
     // already checked when packet filter was set.
-    return (packet_filter_->send(*iface, getSocket(*pkt), pkt));
+    return (packet_filter_->send(*iface, getSocket(*pkt).sockfd_, pkt));
 }
 
 
@@ -1220,8 +1227,7 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
 uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
     Iface* iface = getIface(pkt.getIface());
     if (iface == NULL) {
-        isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.getIface());
+        isc_throw(BadValue, "Tried to find socket for non-existent interface");
     }
 
 
@@ -1274,18 +1280,18 @@ uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
               << " does not have any suitable IPv6 sockets open.");
 }
 
-uint16_t IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
+SocketInfo
+IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
     Iface* iface = getIface(pkt.getIface());
     if (iface == NULL) {
-        isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.getIface());
+        isc_throw(BadValue, "Tried to find socket for non-existent interface");
     }
 
     const Iface::SocketCollection& socket_collection = iface->getSockets();
     Iface::SocketCollection::const_iterator s;
     for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
         if (s->family_ == AF_INET) {
-            return (s->sockfd_);
+            return (*s);
         }
         /// TODO: Add more checks here later. If remote address is
         /// not link-local, we can't use link local bound socket

+ 20 - 14
src/lib/dhcp/iface_mgr.h

@@ -443,8 +443,7 @@ public:
     /// @return interface with requested name (or NULL if no such
     ///         interface is present)
     ///
-    Iface*
-    getIface(const std::string& ifname);
+    Iface* getIface(const std::string& ifname);
 
     /// @brief Returns container with all interfaces.
     ///
@@ -453,7 +452,22 @@ public:
     /// main() function completes, you should not worry much about this.
     ///
     /// @return container with all interfaces.
-    const IfaceCollection& getIfaces() { return ifaces_; }
+    const IfaceCollection& getIfaces() { return (ifaces_); }
+
+    /// @brief Removes detected interfaces.
+    ///
+    /// This method removes all detected interfaces. This method should be
+    /// used by unit tests to supply a custom set of interfaces. For example:
+    /// a unit test may create a pool of fake interfaces and use the custom
+    /// @c PktFilter class to mimic socket operation on these interfaces.
+    void clearIfaces();
+
+    /// @brief Detects network interfaces.
+    ///
+    /// This method will eventually detect available interfaces. For now
+    /// it offers stub implementation. First interface name and link-local
+    /// IPv6 address is read from interfaces.txt file.
+    void detectIfaces();
 
     /// @brief Return most suitable socket for transmitting specified IPv6 packet.
     ///
@@ -468,7 +482,7 @@ public:
     /// @return a socket descriptor
     uint16_t getSocket(const isc::dhcp::Pkt6& pkt);
 
-    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
+    /// @brief Return most suitable socket for transmitting specified IPv4 packet.
     ///
     /// This method takes Pkt4 (see overloaded implementation that takes
     /// Pkt6) and chooses appropriate socket to send it. This method
@@ -478,8 +492,8 @@ public:
     ///
     /// @param pkt a packet to be transmitted
     ///
-    /// @return a socket descriptor
-    uint16_t getSocket(const isc::dhcp::Pkt4& pkt);
+    /// @return A structure describing a socket.
+    SocketInfo getSocket(const isc::dhcp::Pkt4& pkt);
 
     /// Debugging method that prints out all available interfaces.
     ///
@@ -836,14 +850,6 @@ protected:
     /// @return socket descriptor
     int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, uint16_t port);
 
-    /// @brief Detects network interfaces.
-    ///
-    /// This method will eventually detect available interfaces. For now
-    /// it offers stub implementation. First interface name and link-local
-    /// IPv6 address is read from interfaces.txt file.
-    void
-    detectIfaces();
-
     /// @brief Stub implementation of network interface detection.
     ///
     /// This implementations reads a single line from interfaces.txt file

+ 21 - 2
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -496,6 +496,25 @@ TEST_F(IfaceMgrTest, getIface) {
     EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi15") );
 }
 
+TEST_F(IfaceMgrTest, clearIfaces) {
+    NakedIfaceMgr ifacemgr;
+    // Create a set of fake interfaces. At the same time, remove the actual
+    // interfaces that have been detected by the IfaceMgr.
+    ifacemgr.createIfaces();
+
+    ASSERT_GT(ifacemgr.countIfaces(), 0);
+
+    boost::shared_ptr<TestPktFilter> custom_packet_filter(new TestPktFilter());
+    ASSERT_TRUE(custom_packet_filter);
+    ASSERT_NO_THROW(ifacemgr.setPacketFilter(custom_packet_filter));
+
+    ASSERT_NO_THROW(ifacemgr.openSockets4());
+
+    ifacemgr.clearIfaces();
+
+    EXPECT_EQ(0, ifacemgr.countIfaces());
+}
+
 TEST_F(IfaceMgrTest, receiveTimeout6) {
     using namespace boost::posix_time;
     std::cout << "Testing DHCPv6 packet reception timeouts."
@@ -1204,7 +1223,7 @@ TEST_F(IfaceMgrTest, socket4) {
     pkt.setIface(LOOPBACK);
 
     // Expect that we get the socket that we just opened.
-    EXPECT_EQ(socket1, ifacemgr->getSocket(pkt));
+    EXPECT_EQ(socket1, ifacemgr->getSocket(pkt).sockfd_);
 
     close(socket1);
 }
@@ -1513,7 +1532,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
 
     // Socket info is set, packet has well defined interface. It should work.
     pkt4.setIface(LOOPBACK);
-    EXPECT_EQ(7, ifacemgr->getSocket(pkt4));
+    EXPECT_EQ(7, ifacemgr->getSocket(pkt4).sockfd_);
 
     EXPECT_NO_THROW(
         ifacemgr->getIface(LOOPBACK)->delSocket(7);