BIND 10 trac992, updated. ea709c77cdab1d2d91a923b913af869f865477bd [992] IfaceMgr moved from src/bin/dhcp6 to src/lib/dhcp

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Nov 30 14:33:00 UTC 2011


The branch, trac992 has been updated
       via  ea709c77cdab1d2d91a923b913af869f865477bd (commit)
      from  7e2204f4a69fe0f1ce24ce36152577828c8ded79 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ea709c77cdab1d2d91a923b913af869f865477bd
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Wed Nov 30 15:32:40 2011 +0100

    [992] IfaceMgr moved from src/bin/dhcp6 to src/lib/dhcp
    
    - IfaceMgr moved
    - Added new, simple test for b10-dhcp4 daemon
    - Added skeleton man page for b10-dhcp4

-----------------------------------------------------------------------

Summary of changes:
 src/bin/{dhcp6/b10-dhcp6.8 => dhcp4/b10-dhcp4.8}   |   27 +++++---
 src/bin/dhcp4/dhcp4.spec                           |    2 +-
 src/bin/dhcp4/dhcp4_srv.cc                         |    2 +-
 src/bin/{dhcp6 => dhcp4}/tests/Makefile.am         |   40 +++---------
 src/bin/dhcp4/tests/dhcp4_srv_unittest.cc          |   66 ++++++++++++++++++++
 .../tests/dhcp4_unittests.cc}                      |    2 +-
 src/bin/dhcp6/Makefile.am                          |    3 +-
 src/bin/dhcp6/dhcp6.spec                           |    4 +-
 src/bin/dhcp6/dhcp6_srv.cc                         |    6 +-
 src/bin/dhcp6/tests/Makefile.am                    |    4 +-
 src/lib/dhcp/Makefile.am                           |    1 +
 src/{bin/dhcp6 => lib/dhcp}/iface_mgr.cc           |    6 +-
 src/{bin/dhcp6 => lib/dhcp}/iface_mgr.h            |    0 
 src/lib/dhcp/tests/Makefile.am                     |    5 ++
 .../dhcp6 => lib/dhcp}/tests/iface_mgr_unittest.cc |    6 +-
 15 files changed, 117 insertions(+), 57 deletions(-)
 copy src/bin/{dhcp6/b10-dhcp6.8 => dhcp4/b10-dhcp4.8} (55%)
 copy src/bin/{dhcp6 => dhcp4}/tests/Makefile.am (51%)
 create mode 100644 src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
 copy src/bin/{dhcp6/tests/dhcp6_unittests.cc => dhcp4/tests/dhcp4_unittests.cc} (93%)
 rename src/{bin/dhcp6 => lib/dhcp}/iface_mgr.cc (99%)
 rename src/{bin/dhcp6 => lib/dhcp}/iface_mgr.h (100%)
 rename src/{bin/dhcp6 => lib/dhcp}/tests/iface_mgr_unittest.cc (99%)

-----------------------------------------------------------------------
diff --git a/src/bin/dhcp4/b10-dhcp4.8 b/src/bin/dhcp4/b10-dhcp4.8
new file mode 100644
index 0000000..97bdeb8
--- /dev/null
+++ b/src/bin/dhcp4/b10-dhcp4.8
@@ -0,0 +1,60 @@
+'\" t
+.\"     Title: b10-dhcp4
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: October 27, 2011
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-DHCP4" "8" "October 27, 2011" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-dhcp4 \- DHCPv4 server in BIND 10 architecture
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-dhcp4\fR\ 'u
+\fBb10\-dhcp4\fR [\fB\-v\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-dhcp4\fR
+daemon will provide the DHCPv4 server implementation when it becomes functional\&.
+.SH "ARGUMENTS"
+.PP
+The arguments are as follows:
+.PP
+\fB\-v\fR
+.RS 4
+Enable verbose mode\&.
+.RE
+.SH "SEE ALSO"
+.PP
+
+\fBbind10\fR(8)\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-dhcp4\fR
+daemon was first coded in November 2011 by Tomek Mrugalski\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/dhcp4/dhcp4.spec b/src/bin/dhcp4/dhcp4.spec
index c840ce1..8061fd2 100644
--- a/src/bin/dhcp4/dhcp4.spec
+++ b/src/bin/dhcp4/dhcp4.spec
@@ -1,7 +1,7 @@
 {
   "module_spec": {
     "module_name": "dhcp4",
-    "module_description": "DHCPv4 daemon",
+    "module_description": "DHCPv4 server daemon",
     "config_data": [
       { "item_name": "interface",
         "item_type": "string",
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 05d7575..85b937f 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -14,7 +14,7 @@
 
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
-#include <dhcp6/iface_mgr.h>
+#include <dhcp/iface_mgr.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <asiolink/io_address.h>
 
diff --git a/src/bin/dhcp4/tests/Makefile.am b/src/bin/dhcp4/tests/Makefile.am
new file mode 100644
index 0000000..5367c5c
--- /dev/null
+++ b/src/bin/dhcp4/tests/Makefile.am
@@ -0,0 +1,46 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$(abs_top_builddir)/src/lib/datasrc/.libs:$$$(ENV_LIBRARY_PATH)
+endif
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
+AM_CPPFLAGS += -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/dhcp6/tests\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+CLEANFILES = $(builddir)/interfaces.txt
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+TESTS =
+if HAVE_GTEST
+
+TESTS += dhcp4_unittests
+
+dhcp4_unittests_SOURCES == ../dhcp4_srv.h ../dhcp4_srv.cc
+dhcp4_unittests_SOURCES += dhcp4_unittests.cc
+dhcp4_unittests_SOURCES += dhcp4_srv_unittest.cc
+
+dhcp4_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+dhcp4_unittests_LDADD = $(GTEST_LDADD)
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
new file mode 100644
index 0000000..1d22db8
--- /dev/null
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2011  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 <config.h>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <dhcp/dhcp4.h>
+#include <dhcp4/dhcp4_srv.h>
+#include <dhcp/option.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+class NakedDhcpv4Srv: public Dhcpv4Srv {
+    // "naked" Interface Manager, exposes internal fields
+public:
+    NakedDhcpv4Srv() { }
+
+    boost::shared_ptr<Pkt4>
+    processDiscover(boost::shared_ptr<Pkt4>& discover) {
+        return Dhcpv4Srv::processDiscover(discover);
+    }
+    boost::shared_ptr<Pkt4>
+    processRequest(boost::shared_ptr<Pkt4>& request) {
+        return Dhcpv4Srv::processRequest(request);
+    }
+};
+
+class Dhcpv4SrvTest : public ::testing::Test {
+public:
+    Dhcpv4SrvTest() {
+    }
+};
+
+TEST_F(Dhcpv4SrvTest, basic) {
+    // there's almost no code now. What's there provides echo capability
+    // that is just a proof of concept and will be removed soon
+    // No need to thoroughly test it
+
+    EXPECT_NO_THROW( {
+        Dhcpv4Srv * srv = new Dhcpv4Srv();
+
+        delete srv;
+        });
+
+}
+
+} // end of anonymous namespace
diff --git a/src/bin/dhcp4/tests/dhcp4_unittests.cc b/src/bin/dhcp4/tests/dhcp4_unittests.cc
new file mode 100644
index 0000000..ebd889d
--- /dev/null
+++ b/src/bin/dhcp4/tests/dhcp4_unittests.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2011 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 <stdio.h>
+#include <gtest/gtest.h>
+#include <log/logger_support.h>
+
+int
+main(int argc, char* argv[]) {
+
+    ::testing::InitGoogleTest(&argc, argv);
+    isc::log::initLogger();
+
+    int result = RUN_ALL_TESTS();
+
+    return result;
+}
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index b0f8cd9..7967515 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -32,8 +32,7 @@ spec_config.h: spec_config.h.pre
 BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-dhcp6
 
-b10_dhcp6_SOURCES = main.cc iface_mgr.cc dhcp6_srv.cc
-b10_dhcp6_SOURCES += iface_mgr.h dhcp6_srv.h
+b10_dhcp6_SOURCES = main.cc dhcp6_srv.cc dhcp6_srv.h
 
 b10_dhcp6_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index c840ce1..05c3529 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -1,7 +1,7 @@
 {
   "module_spec": {
-    "module_name": "dhcp4",
-    "module_description": "DHCPv4 daemon",
+    "module_name": "dhcp6",
+    "module_description": "DHCPv6 server daemon",
     "config_data": [
       { "item_name": "interface",
         "item_type": "string",
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index ba5afec..9c2f500 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -12,9 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "dhcp/dhcp6.h"
-#include "dhcp/pkt6.h"
-#include "dhcp6/iface_mgr.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/iface_mgr.h>
 #include "dhcp6/dhcp6_srv.h"
 #include "dhcp/option6_ia.h"
 #include "dhcp/option6_iaaddr.h"
diff --git a/src/bin/dhcp6/iface_mgr.cc b/src/bin/dhcp6/iface_mgr.cc
deleted file mode 100644
index a96db07..0000000
--- a/src/bin/dhcp6/iface_mgr.cc
+++ /dev/null
@@ -1,542 +0,0 @@
-// Copyright (C) 2011  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 <sstream>
-#include <fstream>
-#include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "dhcp/dhcp6.h"
-#include "dhcp6/iface_mgr.h"
-#include "exceptions/exceptions.h"
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-namespace isc {
-
-/// IfaceMgr is a singleton implementation
-IfaceMgr* IfaceMgr::instance_ = 0;
-
-void
-IfaceMgr::instanceCreate() {
-    if (instance_) {
-        // no need to do anything. Instance is already created.
-        // Who called it again anyway? Uh oh. Had to be us, as
-        // this is private method.
-        return;
-    }
-    instance_ = new IfaceMgr();
-}
-
-IfaceMgr&
-IfaceMgr::instance() {
-    if (instance_ == 0) {
-        instanceCreate();
-    }
-    return (*instance_);
-}
-
-IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
-    :name_(name), ifindex_(ifindex), mac_len_(0) {
-
-    memset(mac_, 0, sizeof(mac_));
-}
-
-std::string
-IfaceMgr::Iface::getFullName() const {
-    ostringstream tmp;
-    tmp << name_ << "/" << ifindex_;
-    return (tmp.str());
-}
-
-std::string
-IfaceMgr::Iface::getPlainMac() const {
-    ostringstream tmp;
-    tmp.fill('0');
-    tmp << hex;
-    for (int i = 0; i < mac_len_; i++) {
-        tmp.width(2);
-        tmp << mac_[i];
-        if (i < mac_len_-1) {
-            tmp << ":";
-        }
-    }
-    return (tmp.str());
-}
-
-IfaceMgr::IfaceMgr()
-    :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
-     control_buf_(new char[control_buf_len_])
-{
-
-    cout << "IfaceMgr initialization." << endl;
-
-    try {
-        // required for sending/receiving packets
-        // let's keep it in front, just in case someone
-        // wants to send anything during initialization
-
-        // control_buf_ = boost::scoped_array<char>();
-
-        detectIfaces();
-
-        if (!openSockets()) {
-            isc_throw(Unexpected, "Failed to open/bind sockets.");
-        }
-    } catch (const std::exception& ex) {
-        cout << "IfaceMgr creation failed:" << ex.what() << endl;
-
-        // TODO Uncomment this (or call LOG_FATAL) once
-        // interface detection is implemented. Otherwise
-        // it is not possible to run tests in a portable
-        // way (see detectIfaces() method).
-        // throw ex;
-    }
-}
-
-IfaceMgr::~IfaceMgr() {
-    // control_buf_ is deleted automatically (scoped_ptr)
-    control_buf_len_ = 0;
-}
-
-void
-IfaceMgr::detectIfaces() {
-    string ifaceName, linkLocal;
-
-    // TODO do the actual detection. Currently interface detection is faked
-    //      by reading a text file.
-
-    cout << "Interface detection is not implemented yet. "
-         << "Reading interfaces.txt file instead." << endl;
-    cout << "Please use format: interface-name link-local-address" << endl;
-
-    try {
-        ifstream interfaces("interfaces.txt");
-
-        if (!interfaces.good()) {
-            cout << "Failed to read interfaces.txt file." << endl;
-            isc_throw(Unexpected, "Failed to read interfaces.txt");
-        }
-        interfaces >> ifaceName;
-        interfaces >> linkLocal;
-
-        cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
-
-        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
-        IOAddress addr(linkLocal);
-        iface.addrs_.push_back(addr);
-        ifaces_.push_back(iface);
-        interfaces.close();
-    } catch (const std::exception& ex) {
-        // TODO: deallocate whatever memory we used
-        // not that important, since this function is going to be
-        // thrown away as soon as we get proper interface detection
-        // implemented
-
-        // TODO Do LOG_FATAL here
-        std::cerr << "Interface detection failed." << std::endl;
-        throw ex;
-    }
-}
-
-bool
-IfaceMgr::openSockets() {
-    int sock;
-
-    for (IfaceLst::iterator iface=ifaces_.begin();
-         iface!=ifaces_.end();
-         ++iface) {
-
-        for (Addr6Lst::iterator addr=iface->addrs_.begin();
-             addr!=iface->addrs_.end();
-             ++addr) {
-
-            sock = openSocket(iface->name_, *addr,
-                              DHCP6_SERVER_PORT);
-            if (sock<0) {
-                cout << "Failed to open unicast socket." << endl;
-                return (false);
-            }
-            sendsock_ = sock;
-
-            sock = openSocket(iface->name_,
-                              IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
-                              DHCP6_SERVER_PORT);
-            if (sock<0) {
-                cout << "Failed to open multicast socket." << endl;
-                close(sendsock_);
-                return (false);
-            }
-            recvsock_ = sock;
-        }
-    }
-
-    return (true);
-}
-
-void
-IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
-    for (IfaceLst::const_iterator iface=ifaces_.begin();
-         iface!=ifaces_.end();
-         ++iface) {
-        out << "Detected interface " << iface->getFullName() << endl;
-        out << "  " << iface->addrs_.size() << " addr(s):" << endl;
-        for (Addr6Lst::const_iterator addr=iface->addrs_.begin();
-             addr != iface->addrs_.end();
-             ++addr) {
-            out << "  " << addr->toText() << endl;
-        }
-        out << "  mac: " << iface->getPlainMac() << endl;
-    }
-}
-
-IfaceMgr::Iface*
-IfaceMgr::getIface(int ifindex) {
-    for (IfaceLst::iterator iface=ifaces_.begin();
-         iface!=ifaces_.end();
-         ++iface) {
-        if (iface->ifindex_ == ifindex)
-            return (&(*iface));
-    }
-
-    return (NULL); // not found
-}
-
-IfaceMgr::Iface*
-IfaceMgr::getIface(const std::string& ifname) {
-    for (IfaceLst::iterator iface=ifaces_.begin();
-         iface!=ifaces_.end();
-         ++iface) {
-        if (iface->name_ == ifname)
-            return (&(*iface));
-    }
-
-    return (NULL); // not found
-}
-
-int
-IfaceMgr::openSocket(const std::string& ifname,
-                     const IOAddress& addr,
-                     int port) {
-    struct sockaddr_in6 addr6;
-
-    cout << "Creating socket on " << ifname << "/" << addr.toText()
-         << "/port=" << port << endl;
-
-    memset(&addr6, 0, sizeof(addr6));
-    addr6.sin6_family = AF_INET6;
-    addr6.sin6_port = htons(port);
-    addr6.sin6_scope_id = if_nametoindex(ifname.c_str());
-
-    memcpy(&addr6.sin6_addr,
-           addr.getAddress().to_v6().to_bytes().data(),
-           sizeof(addr6.sin6_addr));
-#ifdef HAVE_SA_LEN
-    addr6->sin6_len = sizeof(addr6);
-#endif
-
-    // TODO: use sockcreator once it becomes available
-
-    // make a socket
-    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
-    if (sock < 0) {
-        cout << "Failed to create UDP6 socket." << endl;
-        return (-1);
-    }
-
-    /* Set the REUSEADDR option so that we don't fail to start if
-       we're being restarted. */
-    int flag = 1;
-    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-                   (char *)&flag, sizeof(flag)) < 0) {
-        cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
-        close(sock);
-        return (-1);
-    }
-
-    if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
-        cout << "Failed to bind socket " << sock << " to " << addr.toText()
-             << "/port=" << port << endl;
-        close(sock);
-        return (-1);
-    }
-#ifdef IPV6_RECVPKTINFO
-    /* RFC3542 - a new way */
-    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
-                   &flag, sizeof(flag)) != 0) {
-        cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
-        close(sock);
-        return (-1);
-    }
-#else
-    /* RFC2292 - an old way */
-    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
-                   &flag, sizeof(flag)) != 0) {
-        cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
-        close(sock);
-        return (-1);
-    }
-#endif
-
-    // multicast stuff
-
-    if (addr.getAddress().to_v6().is_multicast()) {
-        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
-        // are link and site-scoped, so there is no sense to join those groups
-        // with global addresses.
-
-        if ( !joinMcast( sock, ifname,
-                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
-            close(sock);
-            return (-1);
-        }
-    }
-
-    cout << "Created socket " << sock << " on " << ifname << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
-    return (sock);
-}
-
-bool
-IfaceMgr::joinMcast(int sock, const std::string& ifname,
-const std::string & mcast) {
-
-    struct ipv6_mreq mreq;
-
-    if (inet_pton(AF_INET6, mcast.c_str(),
-                  &mreq.ipv6mr_multiaddr) <= 0) {
-        cout << "Failed to convert " << ifname
-             << " to IPv6 multicast address." << endl;
-        return (false);
-    }
-
-    mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
-    if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
-                   &mreq, sizeof(mreq)) < 0) {
-        cout << "Failed to join " << mcast << " multicast group." << endl;
-        return (false);
-    }
-
-    cout << "Joined multicast " << mcast << " group." << endl;
-
-    return (true);
-}
-
-bool
-IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
-    struct msghdr m;
-    struct iovec v;
-    int result;
-    struct in6_pktinfo *pktinfo;
-    struct cmsghdr *cmsg;
-    memset(&control_buf_[0], 0, control_buf_len_);
-
-    /*
-     * Initialize our message header structure.
-     */
-    memset(&m, 0, sizeof(m));
-
-    /*
-     * Set the target address we're sending to.
-     */
-    sockaddr_in6 to;
-    memset(&to, 0, sizeof(to));
-    to.sin6_family = AF_INET6;
-    to.sin6_port = htons(pkt->remote_port_);
-    memcpy(&to.sin6_addr,
-           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
-           16);
-    to.sin6_scope_id = pkt->ifindex_;
-
-    m.msg_name = &to;
-    m.msg_namelen = sizeof(to);
-
-    /*
-     * Set the data buffer we're sending. (Using this wacky
-     * "scatter-gather" stuff... we only have a single chunk
-     * of data to send, so we declare a single vector entry.)
-     */
-    v.iov_base = (char *) &pkt->data_[0];
-    v.iov_len = pkt->data_len_;
-    m.msg_iov = &v;
-    m.msg_iovlen = 1;
-
-    /*
-     * Setting the interface is a bit more involved.
-     *
-     * We have to create a "control message", and set that to
-     * define the IPv6 packet information. We could set the
-     * source address if we wanted, but we can safely let the
-     * kernel decide what that should be.
-     */
-    m.msg_control = &control_buf_[0];
-    m.msg_controllen = control_buf_len_;
-    cmsg = CMSG_FIRSTHDR(&m);
-    cmsg->cmsg_level = IPPROTO_IPV6;
-    cmsg->cmsg_type = IPV6_PKTINFO;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
-    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
-    memset(pktinfo, 0, sizeof(*pktinfo));
-    pktinfo->ipi6_ifindex = pkt->ifindex_;
-    m.msg_controllen = cmsg->cmsg_len;
-
-    result = sendmsg(sendsock_, &m, 0);
-    if (result < 0) {
-        cout << "Send packet failed." << endl;
-    }
-    cout << "Sent " << result << " bytes." << endl;
-
-    cout << "Sent " << pkt->data_len_ << " bytes over "
-         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
-         << " dst=" << pkt->remote_addr_.toText()
-         << ", src=" << pkt->local_addr_.toText()
-         << endl;
-
-    return (result);
-}
-
-boost::shared_ptr<Pkt6>
-IfaceMgr::receive() {
-    struct msghdr m;
-    struct iovec v;
-    int result;
-    struct cmsghdr* cmsg;
-    struct in6_pktinfo* pktinfo;
-    struct sockaddr_in6 from;
-    struct in6_addr to_addr;
-    boost::shared_ptr<Pkt6> pkt;
-    char addr_str[INET6_ADDRSTRLEN];
-
-    try {
-        // RFC3315 states that server responses may be
-        // fragmented if they are over MTU. There is no
-        // text whether client's packets may be larger
-        // than 1500. Nevertheless to be on the safe side
-        // we use larger buffer. This buffer limit is checked
-        // during reception (see iov_len below), so we are
-        // safe
-        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
-    } catch (const std::exception& ex) {
-        cout << "Failed to create new packet." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
-
-    memset(&control_buf_[0], 0, control_buf_len_);
-
-    memset(&from, 0, sizeof(from));
-    memset(&to_addr, 0, sizeof(to_addr));
-
-    /*
-     * Initialize our message header structure.
-     */
-    memset(&m, 0, sizeof(m));
-
-    /*
-     * Point so we can get the from address.
-     */
-    m.msg_name = &from;
-    m.msg_namelen = sizeof(from);
-
-    /*
-     * Set the data buffer we're receiving. (Using this wacky
-     * "scatter-gather" stuff... but we that doesn't really make
-     * sense for us, so we use a single vector entry.)
-     */
-    v.iov_base = (void*)&pkt->data_[0];
-    v.iov_len = pkt->data_len_;
-    m.msg_iov = &v;
-    m.msg_iovlen = 1;
-
-    /*
-     * Getting the interface is a bit more involved.
-     *
-     * We set up some space for a "control message". We have
-     * previously asked the kernel to give us packet
-     * information (when we initialized the interface), so we
-     * should get the destination address from that.
-     */
-    m.msg_control = &control_buf_[0];
-    m.msg_controllen = control_buf_len_;
-
-    result = recvmsg(recvsock_, &m, 0);
-
-    if (result >= 0) {
-        /*
-         * If we did read successfully, then we need to loop
-         * through the control messages we received and
-         * find the one with our destination address.
-         *
-         * We also keep a flag to see if we found it. If we
-         * didn't, then we consider this to be an error.
-         */
-        int found_pktinfo = 0;
-        cmsg = CMSG_FIRSTHDR(&m);
-        while (cmsg != NULL) {
-            if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
-                (cmsg->cmsg_type == IPV6_PKTINFO)) {
-                pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
-                to_addr = pktinfo->ipi6_addr;
-                pkt->ifindex_ = pktinfo->ipi6_ifindex;
-                found_pktinfo = 1;
-            }
-            cmsg = CMSG_NXTHDR(&m, cmsg);
-        }
-        if (!found_pktinfo) {
-            cout << "Unable to find pktinfo" << endl;
-            return (boost::shared_ptr<Pkt6>()); // NULL
-        }
-    } else {
-        cout << "Failed to receive data." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
-
-    // That's ugly.
-    // TODO add IOAddress constructor that will take struct in6_addr*
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
-    pkt->local_addr_ = IOAddress(string(addr_str));
-
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
-    pkt->remote_addr_ = IOAddress(string(addr_str));
-
-    pkt->remote_port_ = ntohs(from.sin6_port);
-
-    Iface* received = getIface(pkt->ifindex_);
-    if (received) {
-        pkt->iface_ = received->name_;
-    } else {
-        cout << "Received packet over unknown interface (ifindex="
-             << pkt->ifindex_ << ")." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
-
-    pkt->data_len_ = result;
-
-    // TODO Move this to LOG_DEBUG
-    cout << "Received " << pkt->data_len_ << " bytes over "
-         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
-         << " src=" << pkt->remote_addr_.toText()
-         << ", dst=" << pkt->local_addr_.toText()
-         << endl;
-
-    return (pkt);
-}
-
-}
diff --git a/src/bin/dhcp6/iface_mgr.h b/src/bin/dhcp6/iface_mgr.h
deleted file mode 100644
index 249c7ef..0000000
--- a/src/bin/dhcp6/iface_mgr.h
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright (C) 2011  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 IFACE_MGR_H
-#define IFACE_MGR_H
-
-#include <list>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_array.hpp>
-#include <boost/noncopyable.hpp>
-#include "asiolink/io_address.h"
-#include "dhcp/pkt6.h"
-
-namespace isc {
-
-namespace dhcp {
-/// @brief handles network interfaces, transmission and reception
-///
-/// IfaceMgr is an interface manager class that detects available network
-/// interfaces, configured addresses, link-local addresses, and provides
-/// API for using sockets.
-///
-class IfaceMgr : public boost::noncopyable {
-public:
-    /// type that defines list of addresses
-    typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
-
-    /// maximum MAC address length (Infiniband uses 20 bytes)
-    static const unsigned int MAX_MAC_LEN = 20;
-
-    /// @brief represents a single network interface
-    ///
-    /// Iface structure represents network interface with all useful
-    /// information, like name, interface index, MAC address and
-    /// list of assigned addresses
-    struct Iface {
-        /// constructor
-        Iface(const std::string& name, int ifindex);
-
-        /// returns full interface name in format ifname/ifindex
-        std::string getFullName() const;
-
-        /// returns link-layer address a plain text
-        std::string getPlainMac() const;
-
-        /// network interface name
-        std::string name_;
-
-        /// interface index (a value that uniquely indentifies an interface)
-        int ifindex_;
-
-        /// list of assigned addresses
-        Addr6Lst addrs_;
-
-        /// link-layer address
-        uint8_t mac_[MAX_MAC_LEN];
-
-        /// length of link-layer address (usually 6)
-        int mac_len_;
-
-        /// socket used to sending data
-        int sendsock_;
-
-        /// socket used for receiving data
-        int recvsock_;
-    };
-
-    // TODO performance improvement: we may change this into
-    //      2 maps (ifindex-indexed and name-indexed) and
-    //      also hide it (make it public make tests easier for now)
-
-    /// type that holds a list of interfaces
-    typedef std::list<Iface> IfaceLst;
-
-    /// IfaceMgr is a singleton class. This method returns reference
-    /// to its sole instance.
-    ///
-    /// @return the only existing instance of interface manager
-    static IfaceMgr& instance();
-
-    /// @brief Returns interface with specified interface index
-    ///
-    /// @param ifindex index of searched interface
-    ///
-    /// @return interface with requested index (or NULL if no such
-    ///         interface is present)
-    ///
-    Iface*
-    getIface(int ifindex);
-
-    /// @brief Returns interface with specified interface name
-    ///
-    /// @param ifname name of searched interface
-    ///
-    /// @return interface with requested name (or NULL if no such
-    ///         interface is present)
-    ///
-    Iface*
-    getIface(const std::string& ifname);
-
-    /// debugging method that prints out all available interfaces
-    ///
-    /// @param out specifies stream to print list of interfaces to
-    void
-    printIfaces(std::ostream& out = std::cout);
-
-    /// @brief Sends a packet.
-    ///
-    /// Sends a packet. All parameters for actual transmission are specified in
-    /// Pkt6 structure itself. That includes destination address, src/dst port
-    /// and interface over which data will be sent.
-    ///
-    /// @param pkt packet to be sent
-    ///
-    /// @return true if sending was successful
-    bool
-    send(boost::shared_ptr<Pkt6>& pkt);
-
-    /// @brief Tries to receive packet over open sockets.
-    ///
-    /// Attempts to receive a single packet of any of the open sockets.
-    /// If reception is successful and all information about its sender
-    /// are obtained, Pkt6 object is created and returned.
-    ///
-    /// TODO Start using select() and add timeout to be able
-    /// to not wait infinitely, but rather do something useful
-    /// (e.g. remove expired leases)
-    ///
-    /// @return Pkt6 object representing received packet (or NULL)
-    boost::shared_ptr<Pkt6> receive();
-
-    // don't use private, we need derived classes in tests
-protected:
-
-    /// @brief Protected constructor.
-    ///
-    /// Protected constructor. This is a singleton class. We don't want
-    /// anyone to create instances of IfaceMgr. Use instance() method
-    IfaceMgr();
-
-    ~IfaceMgr();
-
-    /// @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 intefaces.txt file.
-    void
-    detectIfaces();
-
-    ///
-    /// Opens UDP/IPv6 socket and binds it to address, interface and port.
-    ///
-    /// @param ifname name of the interface
-    /// @param addr address to be bound.
-    /// @param port UDP port.
-    ///
-    /// @return socket descriptor, if socket creation, binding and multicast
-    /// group join were all successful. -1 otherwise.
-    int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr,
-                   int port);
-
-    // TODO: having 2 maps (ifindex->iface and ifname->iface would)
-    //      probably be better for performance reasons
-
-    /// List of available interfaces
-    IfaceLst ifaces_;
-
-    /// a pointer to a sole instance of this class (a singleton)
-    static IfaceMgr * instance_;
-
-    // TODO: Also keep this interface on Iface once interface detection
-    // is implemented. We may need it e.g. to close all sockets on
-    // specific interface
-    int recvsock_; // TODO: should be fd_set eventually, but we have only
-    int sendsock_; // 2 sockets for now. Will do for until next release
-    // we can't use the same socket, as receiving socket
-    // is bound to multicast address. And we all know what happens
-    // to people who try to use multicast as source address.
-
-    /// length of the control_buf_ array
-    int control_buf_len_;
-
-    /// control-buffer, used in transmission and reception
-    boost::scoped_array<char> control_buf_;
-
-private:
-    /// Opens sockets on detected interfaces.
-    bool
-    openSockets();
-
-    /// creates a single instance of this class (a singleton implementation)
-    static void
-    instanceCreate();
-
-    /// @brief Joins IPv6 multicast group on a socket.
-    ///
-    /// Socket must be created and bound to an address. Note that this
-    /// address is different than the multicast address. For example DHCPv6
-    /// server should bind its socket to link-local address (fe80::1234...)
-    /// and later join ff02::1:2 multicast group.
-    ///
-    /// @param sock socket fd (socket must be bound)
-    /// @param ifname interface name (for link-scoped multicast groups)
-    /// @param mcast multicast address to join (e.g. "ff02::1:2")
-    ///
-    /// @return true if multicast join was successful
-    ///
-    bool
-    joinMcast(int sock, const std::string& ifname,
-              const std::string& mcast);
-};
-
-}; // namespace isc::dhcp
-}; // namespace isc
-
-#endif
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index 985368e..5961de6 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -45,10 +45,8 @@ if HAVE_GTEST
 
 TESTS += dhcp6_unittests
 
-dhcp6_unittests_SOURCES = ../iface_mgr.h ../iface_mgr.cc
-dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
+dhcp6_unittests_SOURCES = ../dhcp6_srv.h ../dhcp6_srv.cc
 dhcp6_unittests_SOURCES += dhcp6_unittests.cc
-dhcp6_unittests_SOURCES += iface_mgr_unittest.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
 
 dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/bin/dhcp6/tests/iface_mgr_unittest.cc b/src/bin/dhcp6/tests/iface_mgr_unittest.cc
deleted file mode 100644
index f126e6a..0000000
--- a/src/bin/dhcp6/tests/iface_mgr_unittest.cc
+++ /dev/null
@@ -1,367 +0,0 @@
-// Copyright (C) 2011  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 <config.h>
-#include <iostream>
-#include <fstream>
-#include <sstream>
-
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
-#include "io_address.h"
-#include "dhcp/pkt6.h"
-#include "dhcp6/iface_mgr.h"
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-// name of loopback interface detection
-char LOOPBACK[32] = "lo";
-
-namespace {
-const char* const INTERFACE_FILE = TEST_DATA_BUILDDIR "/interfaces.txt";
-
-class NakedIfaceMgr: public IfaceMgr {
-    // "naked" Interface Manager, exposes internal fields
-public:
-    NakedIfaceMgr() { }
-    IfaceLst & getIfacesLst() { return ifaces_; }
-    void setSendSock(int sock) { sendsock_ = sock; }
-    void setRecvSock(int sock) { recvsock_ = sock; }
-
-    int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr,
-                   int port) {
-        return IfaceMgr::openSocket(ifname, addr, port);
-    }
-
-};
-
-// dummy class for now, but this will be expanded when needed
-class IfaceMgrTest : public ::testing::Test {
-public:
-    IfaceMgrTest() {
-    }
-};
-
-// We need some known interface to work reliably. Loopback interface
-// is named lo on Linux and lo0 on BSD boxes. We need to find out
-// which is available. This is not a real test, but rather a workaround
-// that will go away when interface detection is implemented.
-
-// NOTE: At this stage of development, write access to current directory
-// during running tests is required.
-TEST_F(IfaceMgrTest, loDetect) {
-
-    // poor man's interface detection
-    // it will go away as soon as proper interface detection
-    // is implemented
-    if (if_nametoindex("lo")>0) {
-        cout << "This is Linux, using lo as loopback." << endl;
-        sprintf(LOOPBACK, "lo");
-    } else if (if_nametoindex("lo0")>0) {
-        cout << "This is BSD, using lo0 as loopback." << endl;
-        sprintf(LOOPBACK, "lo0");
-    } else {
-        cout << "Failed to detect loopback interface. Neither "
-             << "lo or lo0 worked. I give up." << endl;
-        ASSERT_TRUE(false);
-    }
-}
-
-// uncomment this test to create packet writer. It will
-// write incoming DHCPv6 packets as C arrays. That is useful
-// for generating test sequences based on actual traffic
-//
-// TODO: this potentially should be moved to a separate tool
-//
-
-#if 0
-TEST_F(IfaceMgrTest, dhcp6Sniffer) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    unlink("interfaces.txt");
-
-    ofstream interfaces("interfaces.txt", ios::ate);
-    interfaces << "eth0 fe80::21e:8cff:fe9b:7349";
-    interfaces.close();
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    Pkt6 * pkt = 0;
-    int cnt = 0;
-    cout << "---8X-----------------------------------------" << endl;
-    while (true) {
-        pkt = ifacemgr->receive();
-
-        cout << "// Received " << pkt->data_len_ << " bytes packet:" << endl;
-        cout << "Pkt6 *capture" << cnt++ << "() {" << endl;
-        cout << "    Pkt6* pkt;" << endl;
-        cout << "    pkt = new Pkt6(" << pkt->data_len_ << ");" << endl;
-        cout << "    pkt->remote_port_ = " << pkt-> remote_port_ << ";" << endl;
-        cout << "    pkt->remote_addr_ = IOAddress(\""
-             << pkt->remote_addr_.toText() << "\");" << endl;
-        cout << "    pkt->local_port_ = " << pkt-> local_port_ << ";" << endl;
-        cout << "    pkt->local_addr_ = IOAddress(\""
-             << pkt->local_addr_.toText() << "\");" << endl;
-        cout << "    pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
-        cout << "    pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
-
-        // TODO it is better to declare an array and then memcpy it to
-        // packet.
-        for (int i=0; i< pkt->data_len_; i++) {
-            cout << "    pkt->data_[" << i << "]="
-                 << (int)(unsigned char)pkt->data_[i] << "; ";
-            if (!(i%4))
-                cout << endl;
-        }
-        cout << endl;
-        cout << "    return (pkt);" << endl;
-        cout << "}" << endl << endl;
-
-        delete pkt;
-    }
-    cout << "---8X-----------------------------------------" << endl;
-
-    // never happens. Infinite loop is infinite
-    delete pkt;
-    delete ifacemgr;
-}
-#endif
-
-TEST_F(IfaceMgrTest, basic) {
-    // checks that IfaceManager can be instantiated
-
-    IfaceMgr & ifacemgr = IfaceMgr::instance();
-    ASSERT_TRUE(&ifacemgr != 0);
-}
-
-TEST_F(IfaceMgrTest, ifaceClass) {
-    // basic tests for Iface inner class
-
-    IfaceMgr::Iface * iface = new IfaceMgr::Iface("eth5", 7);
-
-    EXPECT_STREQ("eth5/7", iface->getFullName().c_str());
-
-    delete iface;
-
-}
-
-// TODO: Implement getPlainMac() test as soon as interface detection
-// is implemented.
-TEST_F(IfaceMgrTest, getIface) {
-
-    cout << "Interface checks. Please ignore socket binding errors." << endl;
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    // interface name, ifindex
-    IfaceMgr::Iface iface1("lo1", 1);
-    IfaceMgr::Iface iface2("eth5", 2);
-    IfaceMgr::Iface iface3("en3", 5);
-    IfaceMgr::Iface iface4("e1000g0", 3);
-
-    // note: real interfaces may be detected as well
-    ifacemgr->getIfacesLst().push_back(iface1);
-    ifacemgr->getIfacesLst().push_back(iface2);
-    ifacemgr->getIfacesLst().push_back(iface3);
-    ifacemgr->getIfacesLst().push_back(iface4);
-
-    cout << "There are " << ifacemgr->getIfacesLst().size()
-         << " interfaces." << endl;
-    for (IfaceMgr::IfaceLst::iterator iface=ifacemgr->getIfacesLst().begin();
-         iface != ifacemgr->getIfacesLst().end();
-         ++iface) {
-        cout << "  " << iface->name_ << "/" << iface->ifindex_ << endl;
-    }
-
-
-    // check that interface can be retrieved by ifindex
-    IfaceMgr::Iface * tmp = ifacemgr->getIface(5);
-    // ASSERT_NE(NULL, tmp); is not supported. hmmmm.
-    ASSERT_TRUE( tmp != NULL );
-
-    EXPECT_STREQ( "en3", tmp->name_.c_str() );
-    EXPECT_EQ(5, tmp->ifindex_);
-
-    // check that interface can be retrieved by name
-    tmp = ifacemgr->getIface("lo1");
-    ASSERT_TRUE( tmp != NULL );
-
-    EXPECT_STREQ( "lo1", tmp->name_.c_str() );
-    EXPECT_EQ(1, tmp->ifindex_);
-
-    // check that non-existing interfaces are not returned
-    EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi0") );
-
-    delete ifacemgr;
-}
-
-TEST_F(IfaceMgrTest, detectIfaces) {
-
-    // test detects that interfaces can be detected
-    // there is no code for that now, but interfaces are
-    // read from file
-    fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
-    fakeifaces << "eth0 fe80::1234";
-    fakeifaces.close();
-
-    // this is not usable on systems that don't have eth0
-    // interfaces. Nevertheless, this fake interface should
-    // be on list, but if_nametoindex() will fail.
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    ASSERT_TRUE( ifacemgr->getIface("eth0") != NULL );
-
-    IfaceMgr::Iface * eth0 = ifacemgr->getIface("eth0");
-
-    // there should be one address
-    EXPECT_EQ(1, eth0->addrs_.size());
-
-    IOAddress * addr = &(*eth0->addrs_.begin());
-    ASSERT_TRUE( addr != NULL );
-
-    EXPECT_STREQ( "fe80::1234", addr->toText().c_str() );
-
-    delete ifacemgr;
-}
-
-// TODO: disabled due to other naming on various systems
-// (lo in Linux, lo0 in BSD systems)
-// Fix for this is available on 1186 branch, will reenable
-// this test once 1186 is merged
-TEST_F(IfaceMgrTest, DISABLED_sockets) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    IOAddress loAddr("::1");
-
-    // bind multicast socket to port 10547
-    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
-    EXPECT_GT(socket1, 0); // socket > 0
-
-    // bind unicast socket to port 10548
-    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
-    EXPECT_GT(socket2, 0);
-
-    // expect success. This address/port is already bound, but
-    // we are using SO_REUSEADDR, so we can bind it twice
-    int socket3 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
-
-    // rebinding succeeds on Linux, fails on BSD
-    // TODO: add OS-specific defines here (or modify code to
-    // behave the same way on all OSes, but that may not be
-    // possible
-    // EXPECT_GT(socket3, 0); // socket > 0
-
-    // we now have 3 sockets open at the same time. Looks good.
-
-    close(socket1);
-    close(socket2);
-    close(socket3);
-
-    delete ifacemgr;
-}
-
-// TODO: disabled due to other naming on various systems
-// (lo in Linux, lo0 in BSD systems)
-TEST_F(IfaceMgrTest, DISABLED_socketsMcast) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    IOAddress loAddr("::1");
-    IOAddress mcastAddr("ff02::1:2");
-
-    // bind multicast socket to port 10547
-    int socket1 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
-    EXPECT_GT(socket1, 0); // socket > 0
-
-    // expect success. This address/port is already bound, but
-    // we are using SO_REUSEADDR, so we can bind it twice
-    int socket2 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
-    EXPECT_GT(socket2, 0);
-
-    // there's no good way to test negative case here.
-    // we would need non-multicast interface. We will be able
-    // to iterate thru available interfaces and check if there
-    // are interfaces without multicast-capable flag.
-
-    close(socket1);
-    close(socket2);
-
-    delete ifacemgr;
-}
-
-// TODO: disabled due to other naming on various systems
-// (lo in Linux, lo0 in BSD systems)
-// Fix for this is available on 1186 branch, will reenable
-// this test once 1186 is merged
-TEST_F(IfaceMgrTest, DISABLED_sendReceive) {
-    // testing socket operation in a portable way is tricky
-    // without interface detection implemented
-
-    fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
-    fakeifaces << LOOPBACK << " ::1";
-    fakeifaces.close();
-
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
-
-    // let's assume that every supported OS have lo interface
-    IOAddress loAddr("::1");
-    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
-    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
-
-    ifacemgr->setSendSock(socket2);
-    ifacemgr->setRecvSock(socket1);
-
-    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
-
-    // prepare dummy payload
-    for (int i=0;i<128; i++) {
-        sendPkt->data_[i] = i;
-    }
-
-    sendPkt->remote_port_ = 10547;
-    sendPkt->remote_addr_ = IOAddress("::1");
-    sendPkt->ifindex_ = 1;
-    sendPkt->iface_ = LOOPBACK;
-
-    boost::shared_ptr<Pkt6> rcvPkt;
-
-    EXPECT_EQ(true, ifacemgr->send(sendPkt));
-
-    rcvPkt = ifacemgr->receive();
-
-    ASSERT_TRUE( rcvPkt ); // received our own packet
-
-    // let's check that we received what was sent
-    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
-    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
-                        rcvPkt->data_len_) );
-
-    EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
-    EXPECT_EQ(rcvPkt->remote_port_, 10546);
-
-    delete ifacemgr;
-}
-
-}
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 64dda17..f77830b 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -10,6 +10,7 @@ CLEANFILES = *.gcno *.gcda
 lib_LTLIBRARIES = libdhcp.la
 libdhcp_la_SOURCES  =
 libdhcp_la_SOURCES += libdhcp.cc libdhcp.h
+libdhcp_la_SOURCES += iface_mgr.cc iface_mgr.h
 libdhcp_la_SOURCES += option.cc option.h
 libdhcp_la_SOURCES += option6_ia.cc option6_ia.h
 libdhcp_la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
new file mode 100644
index 0000000..d69f404
--- /dev/null
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -0,0 +1,542 @@
+// Copyright (C) 2011  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 <sstream>
+#include <fstream>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/iface_mgr.h>
+#include <exceptions/exceptions.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace isc {
+
+/// IfaceMgr is a singleton implementation
+IfaceMgr* IfaceMgr::instance_ = 0;
+
+void
+IfaceMgr::instanceCreate() {
+    if (instance_) {
+        // no need to do anything. Instance is already created.
+        // Who called it again anyway? Uh oh. Had to be us, as
+        // this is private method.
+        return;
+    }
+    instance_ = new IfaceMgr();
+}
+
+IfaceMgr&
+IfaceMgr::instance() {
+    if (instance_ == 0) {
+        instanceCreate();
+    }
+    return (*instance_);
+}
+
+IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
+    :name_(name), ifindex_(ifindex), mac_len_(0) {
+
+    memset(mac_, 0, sizeof(mac_));
+}
+
+std::string
+IfaceMgr::Iface::getFullName() const {
+    ostringstream tmp;
+    tmp << name_ << "/" << ifindex_;
+    return (tmp.str());
+}
+
+std::string
+IfaceMgr::Iface::getPlainMac() const {
+    ostringstream tmp;
+    tmp.fill('0');
+    tmp << hex;
+    for (int i = 0; i < mac_len_; i++) {
+        tmp.width(2);
+        tmp << mac_[i];
+        if (i < mac_len_-1) {
+            tmp << ":";
+        }
+    }
+    return (tmp.str());
+}
+
+IfaceMgr::IfaceMgr()
+    :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
+     control_buf_(new char[control_buf_len_])
+{
+
+    cout << "IfaceMgr initialization." << endl;
+
+    try {
+        // required for sending/receiving packets
+        // let's keep it in front, just in case someone
+        // wants to send anything during initialization
+
+        // control_buf_ = boost::scoped_array<char>();
+
+        detectIfaces();
+
+        if (!openSockets()) {
+            isc_throw(Unexpected, "Failed to open/bind sockets.");
+        }
+    } catch (const std::exception& ex) {
+        cout << "IfaceMgr creation failed:" << ex.what() << endl;
+
+        // TODO Uncomment this (or call LOG_FATAL) once
+        // interface detection is implemented. Otherwise
+        // it is not possible to run tests in a portable
+        // way (see detectIfaces() method).
+        // throw ex;
+    }
+}
+
+IfaceMgr::~IfaceMgr() {
+    // control_buf_ is deleted automatically (scoped_ptr)
+    control_buf_len_ = 0;
+}
+
+void
+IfaceMgr::detectIfaces() {
+    string ifaceName, linkLocal;
+
+    // TODO do the actual detection. Currently interface detection is faked
+    //      by reading a text file.
+
+    cout << "Interface detection is not implemented yet. "
+         << "Reading interfaces.txt file instead." << endl;
+    cout << "Please use format: interface-name link-local-address" << endl;
+
+    try {
+        ifstream interfaces("interfaces.txt");
+
+        if (!interfaces.good()) {
+            cout << "Failed to read interfaces.txt file." << endl;
+            isc_throw(Unexpected, "Failed to read interfaces.txt");
+        }
+        interfaces >> ifaceName;
+        interfaces >> linkLocal;
+
+        cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
+
+        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
+        IOAddress addr(linkLocal);
+        iface.addrs_.push_back(addr);
+        ifaces_.push_back(iface);
+        interfaces.close();
+    } catch (const std::exception& ex) {
+        // TODO: deallocate whatever memory we used
+        // not that important, since this function is going to be
+        // thrown away as soon as we get proper interface detection
+        // implemented
+
+        // TODO Do LOG_FATAL here
+        std::cerr << "Interface detection failed." << std::endl;
+        throw ex;
+    }
+}
+
+bool
+IfaceMgr::openSockets() {
+    int sock;
+
+    for (IfaceLst::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+
+        for (Addr6Lst::iterator addr=iface->addrs_.begin();
+             addr!=iface->addrs_.end();
+             ++addr) {
+
+            sock = openSocket(iface->name_, *addr,
+                              DHCP6_SERVER_PORT);
+            if (sock<0) {
+                cout << "Failed to open unicast socket." << endl;
+                return (false);
+            }
+            sendsock_ = sock;
+
+            sock = openSocket(iface->name_,
+                              IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
+                              DHCP6_SERVER_PORT);
+            if (sock<0) {
+                cout << "Failed to open multicast socket." << endl;
+                close(sendsock_);
+                return (false);
+            }
+            recvsock_ = sock;
+        }
+    }
+
+    return (true);
+}
+
+void
+IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
+    for (IfaceLst::const_iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+        out << "Detected interface " << iface->getFullName() << endl;
+        out << "  " << iface->addrs_.size() << " addr(s):" << endl;
+        for (Addr6Lst::const_iterator addr=iface->addrs_.begin();
+             addr != iface->addrs_.end();
+             ++addr) {
+            out << "  " << addr->toText() << endl;
+        }
+        out << "  mac: " << iface->getPlainMac() << endl;
+    }
+}
+
+IfaceMgr::Iface*
+IfaceMgr::getIface(int ifindex) {
+    for (IfaceLst::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+        if (iface->ifindex_ == ifindex)
+            return (&(*iface));
+    }
+
+    return (NULL); // not found
+}
+
+IfaceMgr::Iface*
+IfaceMgr::getIface(const std::string& ifname) {
+    for (IfaceLst::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+        if (iface->name_ == ifname)
+            return (&(*iface));
+    }
+
+    return (NULL); // not found
+}
+
+int
+IfaceMgr::openSocket(const std::string& ifname,
+                     const IOAddress& addr,
+                     int port) {
+    struct sockaddr_in6 addr6;
+
+    cout << "Creating socket on " << ifname << "/" << addr.toText()
+         << "/port=" << port << endl;
+
+    memset(&addr6, 0, sizeof(addr6));
+    addr6.sin6_family = AF_INET6;
+    addr6.sin6_port = htons(port);
+    addr6.sin6_scope_id = if_nametoindex(ifname.c_str());
+
+    memcpy(&addr6.sin6_addr,
+           addr.getAddress().to_v6().to_bytes().data(),
+           sizeof(addr6.sin6_addr));
+#ifdef HAVE_SA_LEN
+    addr6->sin6_len = sizeof(addr6);
+#endif
+
+    // TODO: use sockcreator once it becomes available
+
+    // make a socket
+    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        cout << "Failed to create UDP6 socket." << endl;
+        return (-1);
+    }
+
+    /* Set the REUSEADDR option so that we don't fail to start if
+       we're being restarted. */
+    int flag = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                   (char *)&flag, sizeof(flag)) < 0) {
+        cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
+        close(sock);
+        return (-1);
+    }
+
+    if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
+        cout << "Failed to bind socket " << sock << " to " << addr.toText()
+             << "/port=" << port << endl;
+        close(sock);
+        return (-1);
+    }
+#ifdef IPV6_RECVPKTINFO
+    /* RFC3542 - a new way */
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
+        close(sock);
+        return (-1);
+    }
+#else
+    /* RFC2292 - an old way */
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
+        close(sock);
+        return (-1);
+    }
+#endif
+
+    // multicast stuff
+
+    if (addr.getAddress().to_v6().is_multicast()) {
+        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
+        // are link and site-scoped, so there is no sense to join those groups
+        // with global addresses.
+
+        if ( !joinMcast( sock, ifname,
+                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
+            close(sock);
+            return (-1);
+        }
+    }
+
+    cout << "Created socket " << sock << " on " << ifname << "/" <<
+        addr.toText() << "/port=" << port << endl;
+
+    return (sock);
+}
+
+bool
+IfaceMgr::joinMcast(int sock, const std::string& ifname,
+const std::string & mcast) {
+
+    struct ipv6_mreq mreq;
+
+    if (inet_pton(AF_INET6, mcast.c_str(),
+                  &mreq.ipv6mr_multiaddr) <= 0) {
+        cout << "Failed to convert " << ifname
+             << " to IPv6 multicast address." << endl;
+        return (false);
+    }
+
+    mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                   &mreq, sizeof(mreq)) < 0) {
+        cout << "Failed to join " << mcast << " multicast group." << endl;
+        return (false);
+    }
+
+    cout << "Joined multicast " << mcast << " group." << endl;
+
+    return (true);
+}
+
+bool
+IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
+    struct msghdr m;
+    struct iovec v;
+    int result;
+    struct in6_pktinfo *pktinfo;
+    struct cmsghdr *cmsg;
+    memset(&control_buf_[0], 0, control_buf_len_);
+
+    /*
+     * Initialize our message header structure.
+     */
+    memset(&m, 0, sizeof(m));
+
+    /*
+     * Set the target address we're sending to.
+     */
+    sockaddr_in6 to;
+    memset(&to, 0, sizeof(to));
+    to.sin6_family = AF_INET6;
+    to.sin6_port = htons(pkt->remote_port_);
+    memcpy(&to.sin6_addr,
+           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
+           16);
+    to.sin6_scope_id = pkt->ifindex_;
+
+    m.msg_name = &to;
+    m.msg_namelen = sizeof(to);
+
+    /*
+     * Set the data buffer we're sending. (Using this wacky
+     * "scatter-gather" stuff... we only have a single chunk
+     * of data to send, so we declare a single vector entry.)
+     */
+    v.iov_base = (char *) &pkt->data_[0];
+    v.iov_len = pkt->data_len_;
+    m.msg_iov = &v;
+    m.msg_iovlen = 1;
+
+    /*
+     * Setting the interface is a bit more involved.
+     *
+     * We have to create a "control message", and set that to
+     * define the IPv6 packet information. We could set the
+     * source address if we wanted, but we can safely let the
+     * kernel decide what that should be.
+     */
+    m.msg_control = &control_buf_[0];
+    m.msg_controllen = control_buf_len_;
+    cmsg = CMSG_FIRSTHDR(&m);
+    cmsg->cmsg_level = IPPROTO_IPV6;
+    cmsg->cmsg_type = IPV6_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
+    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+    memset(pktinfo, 0, sizeof(*pktinfo));
+    pktinfo->ipi6_ifindex = pkt->ifindex_;
+    m.msg_controllen = cmsg->cmsg_len;
+
+    result = sendmsg(sendsock_, &m, 0);
+    if (result < 0) {
+        cout << "Send packet failed." << endl;
+    }
+    cout << "Sent " << result << " bytes." << endl;
+
+    cout << "Sent " << pkt->data_len_ << " bytes over "
+         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
+         << " dst=" << pkt->remote_addr_.toText()
+         << ", src=" << pkt->local_addr_.toText()
+         << endl;
+
+    return (result);
+}
+
+boost::shared_ptr<Pkt6>
+IfaceMgr::receive() {
+    struct msghdr m;
+    struct iovec v;
+    int result;
+    struct cmsghdr* cmsg;
+    struct in6_pktinfo* pktinfo;
+    struct sockaddr_in6 from;
+    struct in6_addr to_addr;
+    boost::shared_ptr<Pkt6> pkt;
+    char addr_str[INET6_ADDRSTRLEN];
+
+    try {
+        // RFC3315 states that server responses may be
+        // fragmented if they are over MTU. There is no
+        // text whether client's packets may be larger
+        // than 1500. Nevertheless to be on the safe side
+        // we use larger buffer. This buffer limit is checked
+        // during reception (see iov_len below), so we are
+        // safe
+        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
+    } catch (const std::exception& ex) {
+        cout << "Failed to create new packet." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    memset(&control_buf_[0], 0, control_buf_len_);
+
+    memset(&from, 0, sizeof(from));
+    memset(&to_addr, 0, sizeof(to_addr));
+
+    /*
+     * Initialize our message header structure.
+     */
+    memset(&m, 0, sizeof(m));
+
+    /*
+     * Point so we can get the from address.
+     */
+    m.msg_name = &from;
+    m.msg_namelen = sizeof(from);
+
+    /*
+     * Set the data buffer we're receiving. (Using this wacky
+     * "scatter-gather" stuff... but we that doesn't really make
+     * sense for us, so we use a single vector entry.)
+     */
+    v.iov_base = (void*)&pkt->data_[0];
+    v.iov_len = pkt->data_len_;
+    m.msg_iov = &v;
+    m.msg_iovlen = 1;
+
+    /*
+     * Getting the interface is a bit more involved.
+     *
+     * We set up some space for a "control message". We have
+     * previously asked the kernel to give us packet
+     * information (when we initialized the interface), so we
+     * should get the destination address from that.
+     */
+    m.msg_control = &control_buf_[0];
+    m.msg_controllen = control_buf_len_;
+
+    result = recvmsg(recvsock_, &m, 0);
+
+    if (result >= 0) {
+        /*
+         * If we did read successfully, then we need to loop
+         * through the control messages we received and
+         * find the one with our destination address.
+         *
+         * We also keep a flag to see if we found it. If we
+         * didn't, then we consider this to be an error.
+         */
+        int found_pktinfo = 0;
+        cmsg = CMSG_FIRSTHDR(&m);
+        while (cmsg != NULL) {
+            if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
+                (cmsg->cmsg_type == IPV6_PKTINFO)) {
+                pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+                to_addr = pktinfo->ipi6_addr;
+                pkt->ifindex_ = pktinfo->ipi6_ifindex;
+                found_pktinfo = 1;
+            }
+            cmsg = CMSG_NXTHDR(&m, cmsg);
+        }
+        if (!found_pktinfo) {
+            cout << "Unable to find pktinfo" << endl;
+            return (boost::shared_ptr<Pkt6>()); // NULL
+        }
+    } else {
+        cout << "Failed to receive data." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    // That's ugly.
+    // TODO add IOAddress constructor that will take struct in6_addr*
+    // TODO: there's from_bytes() method added in IOAddress. Use it!
+    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
+    pkt->local_addr_ = IOAddress(string(addr_str));
+
+    // TODO: there's from_bytes() method added in IOAddress. Use it!
+    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
+    pkt->remote_addr_ = IOAddress(string(addr_str));
+
+    pkt->remote_port_ = ntohs(from.sin6_port);
+
+    Iface* received = getIface(pkt->ifindex_);
+    if (received) {
+        pkt->iface_ = received->name_;
+    } else {
+        cout << "Received packet over unknown interface (ifindex="
+             << pkt->ifindex_ << ")." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    pkt->data_len_ = result;
+
+    // TODO Move this to LOG_DEBUG
+    cout << "Received " << pkt->data_len_ << " bytes over "
+         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
+         << " src=" << pkt->remote_addr_.toText()
+         << ", dst=" << pkt->local_addr_.toText()
+         << endl;
+
+    return (pkt);
+}
+
+}
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
new file mode 100644
index 0000000..249c7ef
--- /dev/null
+++ b/src/lib/dhcp/iface_mgr.h
@@ -0,0 +1,229 @@
+// Copyright (C) 2011  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 IFACE_MGR_H
+#define IFACE_MGR_H
+
+#include <list>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/noncopyable.hpp>
+#include "asiolink/io_address.h"
+#include "dhcp/pkt6.h"
+
+namespace isc {
+
+namespace dhcp {
+/// @brief handles network interfaces, transmission and reception
+///
+/// IfaceMgr is an interface manager class that detects available network
+/// interfaces, configured addresses, link-local addresses, and provides
+/// API for using sockets.
+///
+class IfaceMgr : public boost::noncopyable {
+public:
+    /// type that defines list of addresses
+    typedef std::list<isc::asiolink::IOAddress> Addr6Lst;
+
+    /// maximum MAC address length (Infiniband uses 20 bytes)
+    static const unsigned int MAX_MAC_LEN = 20;
+
+    /// @brief represents a single network interface
+    ///
+    /// Iface structure represents network interface with all useful
+    /// information, like name, interface index, MAC address and
+    /// list of assigned addresses
+    struct Iface {
+        /// constructor
+        Iface(const std::string& name, int ifindex);
+
+        /// returns full interface name in format ifname/ifindex
+        std::string getFullName() const;
+
+        /// returns link-layer address a plain text
+        std::string getPlainMac() const;
+
+        /// network interface name
+        std::string name_;
+
+        /// interface index (a value that uniquely indentifies an interface)
+        int ifindex_;
+
+        /// list of assigned addresses
+        Addr6Lst addrs_;
+
+        /// link-layer address
+        uint8_t mac_[MAX_MAC_LEN];
+
+        /// length of link-layer address (usually 6)
+        int mac_len_;
+
+        /// socket used to sending data
+        int sendsock_;
+
+        /// socket used for receiving data
+        int recvsock_;
+    };
+
+    // TODO performance improvement: we may change this into
+    //      2 maps (ifindex-indexed and name-indexed) and
+    //      also hide it (make it public make tests easier for now)
+
+    /// type that holds a list of interfaces
+    typedef std::list<Iface> IfaceLst;
+
+    /// IfaceMgr is a singleton class. This method returns reference
+    /// to its sole instance.
+    ///
+    /// @return the only existing instance of interface manager
+    static IfaceMgr& instance();
+
+    /// @brief Returns interface with specified interface index
+    ///
+    /// @param ifindex index of searched interface
+    ///
+    /// @return interface with requested index (or NULL if no such
+    ///         interface is present)
+    ///
+    Iface*
+    getIface(int ifindex);
+
+    /// @brief Returns interface with specified interface name
+    ///
+    /// @param ifname name of searched interface
+    ///
+    /// @return interface with requested name (or NULL if no such
+    ///         interface is present)
+    ///
+    Iface*
+    getIface(const std::string& ifname);
+
+    /// debugging method that prints out all available interfaces
+    ///
+    /// @param out specifies stream to print list of interfaces to
+    void
+    printIfaces(std::ostream& out = std::cout);
+
+    /// @brief Sends a packet.
+    ///
+    /// Sends a packet. All parameters for actual transmission are specified in
+    /// Pkt6 structure itself. That includes destination address, src/dst port
+    /// and interface over which data will be sent.
+    ///
+    /// @param pkt packet to be sent
+    ///
+    /// @return true if sending was successful
+    bool
+    send(boost::shared_ptr<Pkt6>& pkt);
+
+    /// @brief Tries to receive packet over open sockets.
+    ///
+    /// Attempts to receive a single packet of any of the open sockets.
+    /// If reception is successful and all information about its sender
+    /// are obtained, Pkt6 object is created and returned.
+    ///
+    /// TODO Start using select() and add timeout to be able
+    /// to not wait infinitely, but rather do something useful
+    /// (e.g. remove expired leases)
+    ///
+    /// @return Pkt6 object representing received packet (or NULL)
+    boost::shared_ptr<Pkt6> receive();
+
+    // don't use private, we need derived classes in tests
+protected:
+
+    /// @brief Protected constructor.
+    ///
+    /// Protected constructor. This is a singleton class. We don't want
+    /// anyone to create instances of IfaceMgr. Use instance() method
+    IfaceMgr();
+
+    ~IfaceMgr();
+
+    /// @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 intefaces.txt file.
+    void
+    detectIfaces();
+
+    ///
+    /// Opens UDP/IPv6 socket and binds it to address, interface and port.
+    ///
+    /// @param ifname name of the interface
+    /// @param addr address to be bound.
+    /// @param port UDP port.
+    ///
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful. -1 otherwise.
+    int openSocket(const std::string& ifname,
+                   const isc::asiolink::IOAddress& addr,
+                   int port);
+
+    // TODO: having 2 maps (ifindex->iface and ifname->iface would)
+    //      probably be better for performance reasons
+
+    /// List of available interfaces
+    IfaceLst ifaces_;
+
+    /// a pointer to a sole instance of this class (a singleton)
+    static IfaceMgr * instance_;
+
+    // TODO: Also keep this interface on Iface once interface detection
+    // is implemented. We may need it e.g. to close all sockets on
+    // specific interface
+    int recvsock_; // TODO: should be fd_set eventually, but we have only
+    int sendsock_; // 2 sockets for now. Will do for until next release
+    // we can't use the same socket, as receiving socket
+    // is bound to multicast address. And we all know what happens
+    // to people who try to use multicast as source address.
+
+    /// length of the control_buf_ array
+    int control_buf_len_;
+
+    /// control-buffer, used in transmission and reception
+    boost::scoped_array<char> control_buf_;
+
+private:
+    /// Opens sockets on detected interfaces.
+    bool
+    openSockets();
+
+    /// creates a single instance of this class (a singleton implementation)
+    static void
+    instanceCreate();
+
+    /// @brief Joins IPv6 multicast group on a socket.
+    ///
+    /// Socket must be created and bound to an address. Note that this
+    /// address is different than the multicast address. For example DHCPv6
+    /// server should bind its socket to link-local address (fe80::1234...)
+    /// and later join ff02::1:2 multicast group.
+    ///
+    /// @param sock socket fd (socket must be bound)
+    /// @param ifname interface name (for link-scoped multicast groups)
+    /// @param mcast multicast address to join (e.g. "ff02::1:2")
+    ///
+    /// @return true if multicast join was successful
+    ///
+    bool
+    joinMcast(int sock, const std::string& ifname,
+              const std::string& mcast);
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 01799da..48119ae 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -2,6 +2,10 @@ SUBDIRS = .
 
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dhcp/tests\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 if USE_STATIC_LINK
@@ -15,6 +19,7 @@ if HAVE_GTEST
 TESTS += libdhcp_unittests
 libdhcp_unittests_SOURCES  = run_unittests.cc
 libdhcp_unittests_SOURCES += ../libdhcp.h ../libdhcp.cc libdhcp_unittest.cc
+libdhcp_unittests_SOURCES += ../iface_mgr.cc ../iface_mgr.h iface_mgr_unittest.cc
 libdhcp_unittests_SOURCES += ../option6_iaaddr.h ../option6_iaaddr.cc option6_iaaddr_unittest.cc
 libdhcp_unittests_SOURCES += ../option6_ia.h ../option6_ia.cc option6_ia_unittest.cc
 libdhcp_unittests_SOURCES += ../option6_addrlst.h ../option6_addrlst.cc option6_addrlst_unittest.cc
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
new file mode 100644
index 0000000..f713ac5
--- /dev/null
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -0,0 +1,367 @@
+// Copyright (C) 2011  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 <config.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/iface_mgr.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+// name of loopback interface detection
+char LOOPBACK[32] = "lo";
+
+namespace {
+const char* const INTERFACE_FILE = TEST_DATA_BUILDDIR "/interfaces.txt";
+
+class NakedIfaceMgr: public IfaceMgr {
+    // "naked" Interface Manager, exposes internal fields
+public:
+    NakedIfaceMgr() { }
+    IfaceLst & getIfacesLst() { return ifaces_; }
+    void setSendSock(int sock) { sendsock_ = sock; }
+    void setRecvSock(int sock) { recvsock_ = sock; }
+
+    int openSocket(const std::string& ifname,
+                   const isc::asiolink::IOAddress& addr,
+                   int port) {
+        return IfaceMgr::openSocket(ifname, addr, port);
+    }
+
+};
+
+// dummy class for now, but this will be expanded when needed
+class IfaceMgrTest : public ::testing::Test {
+public:
+    IfaceMgrTest() {
+    }
+};
+
+// We need some known interface to work reliably. Loopback interface
+// is named lo on Linux and lo0 on BSD boxes. We need to find out
+// which is available. This is not a real test, but rather a workaround
+// that will go away when interface detection is implemented.
+
+// NOTE: At this stage of development, write access to current directory
+// during running tests is required.
+TEST_F(IfaceMgrTest, loDetect) {
+
+    // poor man's interface detection
+    // it will go away as soon as proper interface detection
+    // is implemented
+    if (if_nametoindex("lo")>0) {
+        cout << "This is Linux, using lo as loopback." << endl;
+        sprintf(LOOPBACK, "lo");
+    } else if (if_nametoindex("lo0")>0) {
+        cout << "This is BSD, using lo0 as loopback." << endl;
+        sprintf(LOOPBACK, "lo0");
+    } else {
+        cout << "Failed to detect loopback interface. Neither "
+             << "lo or lo0 worked. I give up." << endl;
+        ASSERT_TRUE(false);
+    }
+}
+
+// uncomment this test to create packet writer. It will
+// write incoming DHCPv6 packets as C arrays. That is useful
+// for generating test sequences based on actual traffic
+//
+// TODO: this potentially should be moved to a separate tool
+//
+
+#if 0
+TEST_F(IfaceMgrTest, dhcp6Sniffer) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    unlink("interfaces.txt");
+
+    ofstream interfaces("interfaces.txt", ios::ate);
+    interfaces << "eth0 fe80::21e:8cff:fe9b:7349";
+    interfaces.close();
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    Pkt6 * pkt = 0;
+    int cnt = 0;
+    cout << "---8X-----------------------------------------" << endl;
+    while (true) {
+        pkt = ifacemgr->receive();
+
+        cout << "// Received " << pkt->data_len_ << " bytes packet:" << endl;
+        cout << "Pkt6 *capture" << cnt++ << "() {" << endl;
+        cout << "    Pkt6* pkt;" << endl;
+        cout << "    pkt = new Pkt6(" << pkt->data_len_ << ");" << endl;
+        cout << "    pkt->remote_port_ = " << pkt-> remote_port_ << ";" << endl;
+        cout << "    pkt->remote_addr_ = IOAddress(\""
+             << pkt->remote_addr_.toText() << "\");" << endl;
+        cout << "    pkt->local_port_ = " << pkt-> local_port_ << ";" << endl;
+        cout << "    pkt->local_addr_ = IOAddress(\""
+             << pkt->local_addr_.toText() << "\");" << endl;
+        cout << "    pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
+        cout << "    pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
+
+        // TODO it is better to declare an array and then memcpy it to
+        // packet.
+        for (int i=0; i< pkt->data_len_; i++) {
+            cout << "    pkt->data_[" << i << "]="
+                 << (int)(unsigned char)pkt->data_[i] << "; ";
+            if (!(i%4))
+                cout << endl;
+        }
+        cout << endl;
+        cout << "    return (pkt);" << endl;
+        cout << "}" << endl << endl;
+
+        delete pkt;
+    }
+    cout << "---8X-----------------------------------------" << endl;
+
+    // never happens. Infinite loop is infinite
+    delete pkt;
+    delete ifacemgr;
+}
+#endif
+
+TEST_F(IfaceMgrTest, basic) {
+    // checks that IfaceManager can be instantiated
+
+    IfaceMgr & ifacemgr = IfaceMgr::instance();
+    ASSERT_TRUE(&ifacemgr != 0);
+}
+
+TEST_F(IfaceMgrTest, ifaceClass) {
+    // basic tests for Iface inner class
+
+    IfaceMgr::Iface * iface = new IfaceMgr::Iface("eth5", 7);
+
+    EXPECT_STREQ("eth5/7", iface->getFullName().c_str());
+
+    delete iface;
+
+}
+
+// TODO: Implement getPlainMac() test as soon as interface detection
+// is implemented.
+TEST_F(IfaceMgrTest, getIface) {
+
+    cout << "Interface checks. Please ignore socket binding errors." << endl;
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    // interface name, ifindex
+    IfaceMgr::Iface iface1("lo1", 1);
+    IfaceMgr::Iface iface2("eth5", 2);
+    IfaceMgr::Iface iface3("en3", 5);
+    IfaceMgr::Iface iface4("e1000g0", 3);
+
+    // note: real interfaces may be detected as well
+    ifacemgr->getIfacesLst().push_back(iface1);
+    ifacemgr->getIfacesLst().push_back(iface2);
+    ifacemgr->getIfacesLst().push_back(iface3);
+    ifacemgr->getIfacesLst().push_back(iface4);
+
+    cout << "There are " << ifacemgr->getIfacesLst().size()
+         << " interfaces." << endl;
+    for (IfaceMgr::IfaceLst::iterator iface=ifacemgr->getIfacesLst().begin();
+         iface != ifacemgr->getIfacesLst().end();
+         ++iface) {
+        cout << "  " << iface->name_ << "/" << iface->ifindex_ << endl;
+    }
+
+
+    // check that interface can be retrieved by ifindex
+    IfaceMgr::Iface * tmp = ifacemgr->getIface(5);
+    // ASSERT_NE(NULL, tmp); is not supported. hmmmm.
+    ASSERT_TRUE( tmp != NULL );
+
+    EXPECT_STREQ( "en3", tmp->name_.c_str() );
+    EXPECT_EQ(5, tmp->ifindex_);
+
+    // check that interface can be retrieved by name
+    tmp = ifacemgr->getIface("lo1");
+    ASSERT_TRUE( tmp != NULL );
+
+    EXPECT_STREQ( "lo1", tmp->name_.c_str() );
+    EXPECT_EQ(1, tmp->ifindex_);
+
+    // check that non-existing interfaces are not returned
+    EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi0") );
+
+    delete ifacemgr;
+}
+
+TEST_F(IfaceMgrTest, detectIfaces) {
+
+    // test detects that interfaces can be detected
+    // there is no code for that now, but interfaces are
+    // read from file
+    fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
+    fakeifaces << "eth0 fe80::1234";
+    fakeifaces.close();
+
+    // this is not usable on systems that don't have eth0
+    // interfaces. Nevertheless, this fake interface should
+    // be on list, but if_nametoindex() will fail.
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    ASSERT_TRUE( ifacemgr->getIface("eth0") != NULL );
+
+    IfaceMgr::Iface * eth0 = ifacemgr->getIface("eth0");
+
+    // there should be one address
+    EXPECT_EQ(1, eth0->addrs_.size());
+
+    IOAddress * addr = &(*eth0->addrs_.begin());
+    ASSERT_TRUE( addr != NULL );
+
+    EXPECT_STREQ( "fe80::1234", addr->toText().c_str() );
+
+    delete ifacemgr;
+}
+
+// TODO: disabled due to other naming on various systems
+// (lo in Linux, lo0 in BSD systems)
+// Fix for this is available on 1186 branch, will reenable
+// this test once 1186 is merged
+TEST_F(IfaceMgrTest, DISABLED_sockets) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    IOAddress loAddr("::1");
+
+    // bind multicast socket to port 10547
+    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+    EXPECT_GT(socket1, 0); // socket > 0
+
+    // bind unicast socket to port 10548
+    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10548);
+    EXPECT_GT(socket2, 0);
+
+    // expect success. This address/port is already bound, but
+    // we are using SO_REUSEADDR, so we can bind it twice
+    int socket3 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+
+    // rebinding succeeds on Linux, fails on BSD
+    // TODO: add OS-specific defines here (or modify code to
+    // behave the same way on all OSes, but that may not be
+    // possible
+    // EXPECT_GT(socket3, 0); // socket > 0
+
+    // we now have 3 sockets open at the same time. Looks good.
+
+    close(socket1);
+    close(socket2);
+    close(socket3);
+
+    delete ifacemgr;
+}
+
+// TODO: disabled due to other naming on various systems
+// (lo in Linux, lo0 in BSD systems)
+TEST_F(IfaceMgrTest, DISABLED_socketsMcast) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    IOAddress loAddr("::1");
+    IOAddress mcastAddr("ff02::1:2");
+
+    // bind multicast socket to port 10547
+    int socket1 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
+    EXPECT_GT(socket1, 0); // socket > 0
+
+    // expect success. This address/port is already bound, but
+    // we are using SO_REUSEADDR, so we can bind it twice
+    int socket2 = ifacemgr->openSocket(LOOPBACK, mcastAddr, 10547);
+    EXPECT_GT(socket2, 0);
+
+    // there's no good way to test negative case here.
+    // we would need non-multicast interface. We will be able
+    // to iterate thru available interfaces and check if there
+    // are interfaces without multicast-capable flag.
+
+    close(socket1);
+    close(socket2);
+
+    delete ifacemgr;
+}
+
+// TODO: disabled due to other naming on various systems
+// (lo in Linux, lo0 in BSD systems)
+// Fix for this is available on 1186 branch, will reenable
+// this test once 1186 is merged
+TEST_F(IfaceMgrTest, DISABLED_sendReceive) {
+    // testing socket operation in a portable way is tricky
+    // without interface detection implemented
+
+    fstream fakeifaces(INTERFACE_FILE, ios::out|ios::trunc);
+    fakeifaces << LOOPBACK << " ::1";
+    fakeifaces.close();
+
+    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+
+    // let's assume that every supported OS have lo interface
+    IOAddress loAddr("::1");
+    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
+
+    ifacemgr->setSendSock(socket2);
+    ifacemgr->setRecvSock(socket1);
+
+    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
+
+    // prepare dummy payload
+    for (int i=0;i<128; i++) {
+        sendPkt->data_[i] = i;
+    }
+
+    sendPkt->remote_port_ = 10547;
+    sendPkt->remote_addr_ = IOAddress("::1");
+    sendPkt->ifindex_ = 1;
+    sendPkt->iface_ = LOOPBACK;
+
+    boost::shared_ptr<Pkt6> rcvPkt;
+
+    EXPECT_EQ(true, ifacemgr->send(sendPkt));
+
+    rcvPkt = ifacemgr->receive();
+
+    ASSERT_TRUE( rcvPkt ); // received our own packet
+
+    // let's check that we received what was sent
+    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
+    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
+                        rcvPkt->data_len_) );
+
+    EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
+    EXPECT_EQ(rcvPkt->remote_port_, 10546);
+
+    delete ifacemgr;
+}
+
+}




More information about the bind10-changes mailing list