|
@@ -36,6 +36,7 @@ using namespace std;
|
|
|
using namespace isc;
|
|
|
using namespace isc::asiolink;
|
|
|
using namespace isc::dhcp;
|
|
|
+using namespace isc::dhcp::test;
|
|
|
using boost::scoped_ptr;
|
|
|
|
|
|
namespace {
|
|
@@ -169,11 +170,21 @@ public:
|
|
|
ifaces_.clear();
|
|
|
|
|
|
// local loopback
|
|
|
- ifaces_.push_back(createIface("lo", 0, "127.0.0.1"));
|
|
|
+ Iface lo = createIface("lo", 0);
|
|
|
+ lo.addAddress(IOAddress("127.0.0.1"));
|
|
|
+ lo.addAddress(IOAddress("::1"));
|
|
|
+ ifaces_.push_back(lo);
|
|
|
// eth0
|
|
|
- ifaces_.push_back(createIface("eth0", 1, "10.0.0.1"));
|
|
|
+ Iface eth0 = createIface("eth0", 1);
|
|
|
+ eth0.addAddress(IOAddress("10.0.0.1"));
|
|
|
+ eth0.addAddress(IOAddress("fe80::3a60:77ff:fed5:cdef"));
|
|
|
+ eth0.addAddress(IOAddress("2001:db8:1::1"));
|
|
|
+ ifaces_.push_back(eth0);
|
|
|
// eth1
|
|
|
- ifaces_.push_back(createIface("eth1", 2, "192.0.2.3"));
|
|
|
+ Iface eth1 = createIface("eth1", 2);
|
|
|
+ eth1.addAddress(IOAddress("192.0.2.3"));
|
|
|
+ eth1.addAddress(IOAddress("fe80::3a60:77ff:fed5:abcd"));
|
|
|
+ ifaces_.push_back(eth1);
|
|
|
}
|
|
|
|
|
|
/// @brief Create an object representing interface.
|
|
@@ -190,13 +201,10 @@ public:
|
|
|
///
|
|
|
/// @param name A name of the interface to be created.
|
|
|
/// @param ifindex An index of the interface to be created.
|
|
|
- /// @param addr An IP address to be assigned to the interface.
|
|
|
///
|
|
|
/// @return An object representing interface.
|
|
|
- static Iface createIface(const std::string& name, const int ifindex,
|
|
|
- const std::string& addr) {
|
|
|
+ static Iface createIface(const std::string& name, const int ifindex) {
|
|
|
Iface iface(name, ifindex);
|
|
|
- iface.addAddress(IOAddress(addr));
|
|
|
if (name == "lo") {
|
|
|
iface.flag_loopback_ = true;
|
|
|
}
|
|
@@ -206,7 +214,30 @@ public:
|
|
|
return (iface);
|
|
|
}
|
|
|
|
|
|
- /// @brief Modified flags on the interface.
|
|
|
+ /// @brief Checks if the specified interface has a socket bound to a
|
|
|
+ /// specified adddress.
|
|
|
+ ///
|
|
|
+ /// @param iface_name A name of the interface.
|
|
|
+ /// @param addr An address to be checked for binding.
|
|
|
+ ///
|
|
|
+ /// @return true if there is a socket bound to the specified address.
|
|
|
+ bool isBound(const std::string& iface_name, const std::string& addr) {
|
|
|
+ Iface* iface = getIface(iface_name);
|
|
|
+ if (iface == NULL) {
|
|
|
+ ADD_FAILURE() << "the interface " << iface_name << " doesn't exist";
|
|
|
+ return (false);
|
|
|
+ }
|
|
|
+ const Iface::SocketCollection& sockets = iface->getSockets();
|
|
|
+ for (Iface::SocketCollection::const_iterator sock = sockets.begin();
|
|
|
+ sock != sockets.end(); ++sock) {
|
|
|
+ if (sock->addr_ == IOAddress(addr)) {
|
|
|
+ return (true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return (false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @brief Modify flags on the interface.
|
|
|
///
|
|
|
/// @param name A name of the interface.
|
|
|
/// @param loopback A new value of the loopback flag.
|
|
@@ -215,14 +246,16 @@ public:
|
|
|
/// @param inactive A new value of the inactive flag.
|
|
|
void setIfaceFlags(const std::string& name, const bool loopback,
|
|
|
const bool up, const bool running,
|
|
|
- const bool inactive) {
|
|
|
+ const bool inactive4,
|
|
|
+ const bool inactive6) {
|
|
|
for (IfaceMgr::IfaceCollection::iterator iface = ifaces_.begin();
|
|
|
iface != ifaces_.end(); ++iface) {
|
|
|
if (iface->getName() == name) {
|
|
|
iface->flag_loopback_ = loopback;
|
|
|
iface->flag_up_ = up;
|
|
|
iface->flag_running_ = running;
|
|
|
- iface->inactive4_ = inactive;
|
|
|
+ iface->inactive4_ = inactive4;
|
|
|
+ iface->inactive6_ = inactive6;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -245,6 +278,38 @@ public:
|
|
|
~IfaceMgrTest() {
|
|
|
}
|
|
|
|
|
|
+ /// @brief Tests the number of IPv6 sockets on interface
|
|
|
+ ///
|
|
|
+ /// This function checks the expected number of open IPv6 sockets on the
|
|
|
+ /// specified interface. On non-Linux systems, sockets are bound to a
|
|
|
+ /// link-local address and the number of unicast addresses specified.
|
|
|
+ /// On Linux systems, there is one more socket bound to a ff02::1:2
|
|
|
+ /// multicast address.
|
|
|
+ ///
|
|
|
+ /// @param iface An interface on which sockets are open.
|
|
|
+ /// @param unicast_num A number of unicast addresses bound.
|
|
|
+ void checkSocketsCount6(const Iface& iface, const int unicast_num) {
|
|
|
+ // On local-loopback interface, there should be no sockets.
|
|
|
+ if (iface.flag_loopback_) {
|
|
|
+ ASSERT_TRUE(iface.getSockets().empty())
|
|
|
+ << "expected empty socket set on loopback interface "
|
|
|
+ << iface.getName();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+#if defined OS_LINUX
|
|
|
+ // On Linux, there is an additional socket bound to ff02::1:2.
|
|
|
+ ASSERT_EQ(unicast_num + 2, iface.getSockets().size())
|
|
|
+ << "invalid number of sockets on interface "
|
|
|
+ << iface.getName();
|
|
|
+#else
|
|
|
+ // On non-Linux, there is no additional socket.
|
|
|
+ ASSERT_EQ(unicast_num + 1, iface.getSockets().size())
|
|
|
+ << "invalid number of sockets on interface "
|
|
|
+ << iface.getName();
|
|
|
+
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
// Get ther number of IPv4 or IPv6 sockets on the loopback interface
|
|
|
int getOpenSocketsCount(const Iface& iface, uint16_t family) const {
|
|
|
// Get all sockets.
|
|
@@ -1082,12 +1147,12 @@ TEST_F(IfaceMgrTest, setPacketFilter6) {
|
|
|
ASSERT_TRUE(iface_mgr);
|
|
|
|
|
|
// Try to set NULL packet filter object and make sure it is rejected.
|
|
|
- boost::shared_ptr<test::PktFilter6Stub> custom_packet_filter;
|
|
|
+ boost::shared_ptr<PktFilter6Stub> custom_packet_filter;
|
|
|
EXPECT_THROW(iface_mgr->setPacketFilter(custom_packet_filter),
|
|
|
isc::dhcp::InvalidPacketFilter);
|
|
|
|
|
|
// Create valid object and check if it can be set.
|
|
|
- custom_packet_filter.reset(new test::PktFilter6Stub());
|
|
|
+ custom_packet_filter.reset(new PktFilter6Stub());
|
|
|
ASSERT_TRUE(custom_packet_filter);
|
|
|
ASSERT_NO_THROW(iface_mgr->setPacketFilter(custom_packet_filter));
|
|
|
|
|
@@ -1295,7 +1360,7 @@ TEST_F(IfaceMgrTest, openSockets4IfaceDown) {
|
|
|
// - is "down" (not up)
|
|
|
// - is not running
|
|
|
// - is active (is not inactive)
|
|
|
- ifacemgr.setIfaceFlags("eth0", false, false, true, false);
|
|
|
+ ifacemgr.setIfaceFlags("eth0", false, false, true, false, false);
|
|
|
ASSERT_FALSE(ifacemgr.getIface("eth0")->flag_up_);
|
|
|
ASSERT_NO_THROW(ifacemgr.openSockets4(DHCP4_SERVER_PORT, true, NULL));
|
|
|
|
|
@@ -1326,7 +1391,7 @@ TEST_F(IfaceMgrTest, openSockets4IfaceInactive) {
|
|
|
// - is up
|
|
|
// - is running
|
|
|
// - is inactive
|
|
|
- ifacemgr.setIfaceFlags("eth1", false, true, true, true);
|
|
|
+ ifacemgr.setIfaceFlags("eth1", false, true, true, true, false);
|
|
|
ASSERT_TRUE(ifacemgr.getIface("eth1")->inactive4_);
|
|
|
ASSERT_NO_THROW(ifacemgr.openSockets4(DHCP4_SERVER_PORT, true, NULL));
|
|
|
|
|
@@ -1403,6 +1468,182 @@ TEST_F(IfaceMgrTest, openSocket4ErrorHandler) {
|
|
|
|
|
|
}
|
|
|
|
|
|
+// This test checks that the sockets are open and bound to link local addresses
|
|
|
+// only, if unicast addresses are not specified.
|
|
|
+TEST_F(IfaceMgrTest, openSockets6LinkLocal) {
|
|
|
+ NakedIfaceMgr ifacemgr;
|
|
|
+
|
|
|
+ // Remove all real interfaces and create a set of dummy interfaces.
|
|
|
+ ifacemgr.createIfaces();
|
|
|
+
|
|
|
+ boost::shared_ptr<PktFilter6Stub> filter(new PktFilter6Stub());
|
|
|
+ ASSERT_TRUE(filter);
|
|
|
+ ASSERT_NO_THROW(ifacemgr.setPacketFilter(filter));
|
|
|
+
|
|
|
+ // Simulate opening sockets using the dummy packet filter.
|
|
|
+ bool success;
|
|
|
+ ASSERT_NO_THROW(success = ifacemgr.openSockets6(DHCP6_SERVER_PORT));
|
|
|
+ EXPECT_TRUE(success);
|
|
|
+
|
|
|
+ // Check that the number of sockets is correct on each interface.
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("lo"), 0);
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("eth0"), 0);
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("eth1"), 0);
|
|
|
+
|
|
|
+ // Sockets on eth0 should be bound to link-local and should not be bound
|
|
|
+ // to global unicast address, even though this address is configured on
|
|
|
+ // the eth0.
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", "fe80::3a60:77ff:fed5:cdef"));
|
|
|
+ EXPECT_FALSE(ifacemgr.isBound("eth0", "2001:db8:1::1"));
|
|
|
+ // Socket on eth1 should be bound to link local only.
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth1", "fe80::3a60:77ff:fed5:abcd"));
|
|
|
+
|
|
|
+ // If we are on Linux, there is one more socket bound to ff02::1:2
|
|
|
+#if defined OS_LINUX
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth1", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+// This test checks that the sockets are opened and bound to link local
|
|
|
+// and unicast addresses which have been explicitly specified.
|
|
|
+TEST_F(IfaceMgrTest, openSockets6Unicast) {
|
|
|
+ NakedIfaceMgr ifacemgr;
|
|
|
+
|
|
|
+ // Remove all real interfaces and create a set of dummy interfaces.
|
|
|
+ ifacemgr.createIfaces();
|
|
|
+
|
|
|
+ boost::shared_ptr<PktFilter6Stub> filter(new PktFilter6Stub());
|
|
|
+ ASSERT_TRUE(filter);
|
|
|
+ ASSERT_NO_THROW(ifacemgr.setPacketFilter(filter));
|
|
|
+
|
|
|
+ // Configure the eth0 to open socket on the unicast address, apart
|
|
|
+ // from link-local address.
|
|
|
+ ifacemgr.getIface("eth0")->addUnicast(IOAddress("2001:db8:1::1"));
|
|
|
+
|
|
|
+ // Simulate opening sockets using the dummy packet filter.
|
|
|
+ bool success;
|
|
|
+ ASSERT_NO_THROW(success = ifacemgr.openSockets6(DHCP6_SERVER_PORT));
|
|
|
+ EXPECT_TRUE(success);
|
|
|
+
|
|
|
+ // Check that we have correct number of sockets on each interface.
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("lo"), 0);
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("eth0"), 1); // one unicast address.
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("eth1"), 0);
|
|
|
+
|
|
|
+ // eth0 should have two sockets, one bound to link-local, another one
|
|
|
+ // bound to unicast address.
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", "fe80::3a60:77ff:fed5:cdef"));
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", "2001:db8:1::1"));
|
|
|
+ // eth1 should have one socket, bound to link-local address.
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth1", "fe80::3a60:77ff:fed5:abcd"));
|
|
|
+
|
|
|
+ // If we are on Linux, there is one more socket bound to ff02::1:2
|
|
|
+#if defined OS_LINUX
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth1", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+#endif
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// This test checks that no sockets are open for the interface which is down.
|
|
|
+TEST_F(IfaceMgrTest, openSockets6IfaceDown) {
|
|
|
+ NakedIfaceMgr ifacemgr;
|
|
|
+
|
|
|
+ // Remove all real interfaces and create a set of dummy interfaces.
|
|
|
+ ifacemgr.createIfaces();
|
|
|
+
|
|
|
+ boost::shared_ptr<PktFilter6Stub> filter(new PktFilter6Stub());
|
|
|
+ ASSERT_TRUE(filter);
|
|
|
+ ASSERT_NO_THROW(ifacemgr.setPacketFilter(filter));
|
|
|
+
|
|
|
+ // Configure the eth0 to open socket on the unicast address, apart
|
|
|
+ // from link-local address.
|
|
|
+ ifacemgr.getIface("eth0")->addUnicast(IOAddress("2001:db8:1::1"));
|
|
|
+
|
|
|
+ // Boolean parameters specify that eth0 is:
|
|
|
+ // - not a loopback
|
|
|
+ // - is "down" (not up)
|
|
|
+ // - is not running
|
|
|
+ // - is active for both v4 and v6
|
|
|
+ ifacemgr.setIfaceFlags("eth0", false, false, false, false, false);
|
|
|
+
|
|
|
+ // Simulate opening sockets using the dummy packet filter.
|
|
|
+ bool success;
|
|
|
+ ASSERT_NO_THROW(success = ifacemgr.openSockets6(DHCP6_SERVER_PORT));
|
|
|
+ EXPECT_TRUE(success);
|
|
|
+
|
|
|
+ // Check that we have correct number of sockets on each interface.
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("lo"), 0);
|
|
|
+ // There should be no sockets on eth0 because interface is down.
|
|
|
+ ASSERT_TRUE(ifacemgr.getIface("eth0")->getSockets().empty());
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("eth1"), 0);
|
|
|
+
|
|
|
+ // eth0 should have no sockets because the interface is down.
|
|
|
+ EXPECT_FALSE(ifacemgr.isBound("eth0", "fe80::3a60:77ff:fed5:cdef"));
|
|
|
+ EXPECT_FALSE(ifacemgr.isBound("eth0", "2001:db8:1::1"));
|
|
|
+ EXPECT_FALSE(ifacemgr.isBound("eth0", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+ // eth1 should have one socket, bound to link-local address.
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth1", "fe80::3a60:77ff:fed5:abcd"));
|
|
|
+
|
|
|
+ // If we are on Linux, there is one more socket bound to ff02::1:2
|
|
|
+#if defined OS_LINUX
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth1", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+#endif
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// This test checks that no sockets are open for the interface which is
|
|
|
+// inactive.
|
|
|
+TEST_F(IfaceMgrTest, openSockets6IfaceInactive) {
|
|
|
+ NakedIfaceMgr ifacemgr;
|
|
|
+
|
|
|
+ // Remove all real interfaces and create a set of dummy interfaces.
|
|
|
+ ifacemgr.createIfaces();
|
|
|
+
|
|
|
+ boost::shared_ptr<PktFilter6Stub> filter(new PktFilter6Stub());
|
|
|
+ ASSERT_TRUE(filter);
|
|
|
+ ASSERT_NO_THROW(ifacemgr.setPacketFilter(filter));
|
|
|
+
|
|
|
+ // Configure the eth0 to open socket on the unicast address, apart
|
|
|
+ // from link-local address.
|
|
|
+ ifacemgr.getIface("eth0")->addUnicast(IOAddress("2001:db8:1::1"));
|
|
|
+
|
|
|
+ // Boolean parameters specify that eth1 is:
|
|
|
+ // - not a loopback
|
|
|
+ // - is up
|
|
|
+ // - is running
|
|
|
+ // - is active for v4
|
|
|
+ // - is inactive for v6
|
|
|
+ ifacemgr.setIfaceFlags("eth1", false, true, true, false, true);
|
|
|
+
|
|
|
+ // Simulate opening sockets using the dummy packet filter.
|
|
|
+ bool success;
|
|
|
+ ASSERT_NO_THROW(success = ifacemgr.openSockets6(DHCP6_SERVER_PORT));
|
|
|
+ EXPECT_TRUE(success);
|
|
|
+
|
|
|
+ // Check that we have correct number of sockets on each interface.
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("lo"), 0);
|
|
|
+ checkSocketsCount6(*ifacemgr.getIface("eth0"), 1); // one unicast address
|
|
|
+ // There should be no sockets on eth1 because interface is inactive
|
|
|
+ ASSERT_TRUE(ifacemgr.getIface("eth1")->getSockets().empty());
|
|
|
+
|
|
|
+ // eth0 should have one socket bound to a link-local address, another one
|
|
|
+ // bound to unicast address.
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", "fe80::3a60:77ff:fed5:cdef"));
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", "2001:db8:1::1"));
|
|
|
+
|
|
|
+ // eth1 shouldn't have a socket bound to link local address because
|
|
|
+ // interface is inactive.
|
|
|
+ EXPECT_FALSE(ifacemgr.isBound("eth1", "fe80::3a60:77ff:fed5:abcd"));
|
|
|
+ EXPECT_FALSE(ifacemgr.isBound("eth1", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+
|
|
|
+ // If we are on Linux, there is one more socket bound to ff02::1:2
|
|
|
+#if defined OS_LINUX
|
|
|
+ EXPECT_TRUE(ifacemgr.isBound("eth0", ALL_DHCP_RELAY_AGENTS_AND_SERVERS));
|
|
|
+#endif
|
|
|
+
|
|
|
+}
|
|
|
|
|
|
// Test the Iface structure itself
|
|
|
TEST_F(IfaceMgrTest, iface) {
|