BIND 10 master, updated. 5204b8af562627419798146f71f7402849bfaedc [master] Merge branch 'trac2596' (DHCPv6 subnet tied to interface)
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jan 18 15:52:53 UTC 2013
The branch, master has been updated
via 5204b8af562627419798146f71f7402849bfaedc (commit)
via a70f6172194a976b514cd7d67ce097bbca3c2798 (commit)
via 0a433790559aa0e0fe148a06bbe50d9df522312a (commit)
via f2c0ce1adf8090ecb9ed76e6f3f201d0b044e060 (commit)
via f3709cc11e26e2bb2a0cfa4f447efce885160276 (commit)
via d47e9e008a7eb572f370ab7b5527c8188bb24017 (commit)
from 79b57c7becdf6fa66812c75bf29a63f63221442f (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 5204b8af562627419798146f71f7402849bfaedc
Merge: 79b57c7 a70f617
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Fri Jan 18 16:52:38 2013 +0100
[master] Merge branch 'trac2596' (DHCPv6 subnet tied to interface)
Conflicts:
ChangeLog
src/bin/dhcp6/config_parser.cc
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 8 +-
src/bin/dhcp6/config_parser.cc | 22 +++++
src/bin/dhcp6/dhcp6.spec | 6 ++
src/bin/dhcp6/dhcp6_srv.cc | 12 ++-
src/bin/dhcp6/tests/config_parser_unittest.cc | 120 ++++++++++++++++++++++++-
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 114 +++++++++++++++++++++++
src/lib/dhcpsrv/cfgmgr.cc | 21 +++++
src/lib/dhcpsrv/cfgmgr.h | 11 ++-
src/lib/dhcpsrv/dhcpsrv_messages.mes | 6 ++
src/lib/dhcpsrv/subnet.cc | 10 +++
src/lib/dhcpsrv/subnet.h | 15 ++++
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc | 4 +
src/lib/dhcpsrv/tests/subnet_unittest.cc | 11 +++
13 files changed, 353 insertions(+), 7 deletions(-)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index c999ea6..ce45dbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,10 @@
-248. [func] vorner
+549. [func] tomek
+ b10-dhcp6: It is now possible to specify that a configured subnet
+ is reachable locally over specified interface (see "interface"
+ parameter in Subnet6 configuration).
+ (Trac #2596, git a70f6172194a976b514cd7d67ce097bbca3c2798)
+
+548. [func] vorner
The message queue daemon now appears on the bus. This has two
effects, one is it obeys logging configuration and logs to the
correct place like the rest of the modules. The other is it
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index 5c8675e..f2eb34c 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -18,6 +18,7 @@
#include <dhcp/libdhcp++.h>
#include <dhcp6/config_parser.h>
#include <dhcp6/dhcp6_log.h>
+#include <dhcp/iface_mgr.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcp_config_parser.h>
#include <dhcpsrv/pool.h>
@@ -1400,6 +1401,15 @@ private:
Triplet<uint32_t> pref = getParam("preferred-lifetime");
Triplet<uint32_t> valid = getParam("valid-lifetime");
+ // Get interface name. If it is defined, then the subnet is available
+ // directly over specified network interface.
+
+ string iface;
+ StringStorage::const_iterator iface_iter = string_values_.find("interface");
+ if (iface_iter != string_values_.end()) {
+ iface = iface_iter->second;
+ }
+
/// @todo: Convert this to logger once the parser is working reliably
stringstream tmp;
tmp << addr.toText() << "/" << (int)len
@@ -1416,6 +1426,17 @@ private:
subnet_->addPool(*it);
}
+ // Configure interface, if defined
+ if (!iface.empty()) {
+ if (!IfaceMgr::instance().getIface(iface)) {
+ isc_throw(DhcpConfigError, "Specified interface name " << iface
+ << " for subnet " << subnet_->toText() << " is not present"
+ << " in the system.");
+ }
+
+ subnet_->setIface(iface);
+ }
+
// We are going to move configured options to the Subnet object.
// Configured options reside in the container where options
// are grouped by space names. Thus we need to get all space names
@@ -1489,6 +1510,7 @@ private:
factories["subnet"] = StringParser::factory;
factories["pool"] = PoolParser::factory;
factories["option-data"] = OptionDataListParser::factory;
+ factories["interface"] = StringParser::factory;
FactoryMap::iterator f = factories.find(config_id);
if (f == factories.end()) {
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index b719ebb..7f80457 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -149,6 +149,12 @@
"item_default": ""
},
+ { "item_name": "interface",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ },
+
{ "item_name": "renew-timer",
"item_type": "integer",
"item_optional": false,
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 18acd76..8fb55ec 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -428,7 +428,17 @@ void Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
}
Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
- Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+
+ /// @todo: pass interface information only if received direct (non-relayed) message
+
+ // Try to find a subnet if received packet from a directly connected client
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getIface());
+ if (subnet) {
+ return (subnet);
+ }
+
+ // If no subnet was found, try to find it based on remote address
+ subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
return (subnet);
}
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index b6ef97f..b3fe88e 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -17,6 +17,7 @@
#include <config/ccsession.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_ia.h>
+#include <dhcp/iface_mgr.h>
#include <dhcp6/config_parser.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcpsrv/cfgmgr.h>
@@ -46,6 +47,23 @@ public:
// srv_(0) means to not open any sockets. We don't want to
// deal with sockets here, just check if configuration handling
// is sane.
+
+ const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+ // There must be some interface detected
+ if (ifaces.empty()) {
+ // We can't use ASSERT in constructor
+ ADD_FAILURE() << "No interfaces detected.";
+ }
+
+ valid_iface_ = ifaces.begin()->getName();
+ bogus_iface_ = "nonexisting0";
+
+ if (IfaceMgr::instance().getIface(bogus_iface_)) {
+ ADD_FAILURE() << "The '" << bogus_iface_ << "' exists on this system"
+ << " while the test assumes that it doesn't, to execute"
+ << " some negative scenarios. Can't continue this test.";
+ }
}
~Dhcp6ParserTest() {
@@ -261,6 +279,9 @@ public:
int rcode_;
ConstElementPtr comment_;
+
+ string valid_iface_;
+ string bogus_iface_;
};
// Goal of this test is a verification if a very simple config update
@@ -294,9 +315,8 @@ TEST_F(Dhcp6ParserTest, bogusCommand) {
EXPECT_EQ(1, rcode_);
}
-/// The goal of this test is to verify if wrongly defined subnet will
-/// be rejected. Properly defined subnet must include at least one
-/// pool definition.
+/// The goal of this test is to verify if configuration without any
+/// subnets defined can be accepted.
TEST_F(Dhcp6ParserTest, emptySubnet) {
ConstElementPtr status;
@@ -387,6 +407,99 @@ TEST_F(Dhcp6ParserTest, subnetLocal) {
EXPECT_EQ(4, subnet->getValid());
}
+// This test checks if it is possible to define a subnet with an
+// interface defined.
+TEST_F(Dhcp6ParserTest, subnetInterface) {
+
+ ConstElementPtr status;
+
+ // There should be at least one interface
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
+ " \"interface\": \"" + valid_iface_ + "\","
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+
+ // returned value should be 0 (configuration success)
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(0, rcode_);
+
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(valid_iface_, subnet->getIface());
+}
+
+// This test checks if invalid interface name will be rejected in
+// Subnet6 definition.
+TEST_F(Dhcp6ParserTest, subnetInterfaceBogus) {
+
+ ConstElementPtr status;
+
+ // There should be at least one interface
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
+ " \"interface\": \"" + bogus_iface_ + "\","
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+
+ // returned value should be 1 (configuration error)
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(1, rcode_);
+
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ EXPECT_FALSE(subnet);
+}
+
+
+// This test checks if it is not allowed to define global interface
+// parameter.
+TEST_F(Dhcp6ParserTest, interfaceGlobal) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"interface\": \"" + valid_iface_ + "\"," // Not valid. Can be defined in subnet only
+ "\"subnet6\": [ { "
+ " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+
+ // returned value should be 1 (parse error)
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(1, rcode_);
+}
+
// Test verifies that a subnet with pool values that do not belong to that
// pool are rejected.
TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
@@ -411,7 +524,6 @@ TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
// as the pool does not belong to that subnet
ASSERT_TRUE(status);
comment_ = parseAnswer(rcode_, status);
-
EXPECT_EQ(1, rcode_);
}
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index dee3de5..0ed4e85 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -1296,6 +1296,120 @@ TEST_F(Dhcpv6SrvTest, sanityCheck) {
RFCViolation);
}
+// This test verifies if selectSubnet() selects proper subnet for a given
+// source address.
+TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
+ NakedDhcpv6Srv srv(0);
+
+ Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
+ Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
+ Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
+
+ // CASE 1: We have only one subnet defined and we received local traffic.
+ // The only available subnet should be selected
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+
+ Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+ pkt->setRemoteAddr(IOAddress("fe80::abcd"));
+
+ Subnet6Ptr selected = srv.selectSubnet(pkt);
+ EXPECT_EQ(selected, subnet1);
+
+ // CASE 2: We have only one subnet defined and we received relayed traffic.
+ // We should NOT select it.
+
+ // Identical steps as in case 1, but repeated for clarity
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+ pkt->setRemoteAddr(IOAddress("2001:db8:abcd::2345"));
+ selected = srv.selectSubnet(pkt);
+ EXPECT_FALSE(selected);
+
+ // CASE 3: We have three subnets defined and we received local traffic.
+ // Nothing should be selected.
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1);
+ CfgMgr::instance().addSubnet6(subnet2);
+ CfgMgr::instance().addSubnet6(subnet3);
+ pkt->setRemoteAddr(IOAddress("fe80::abcd"));
+ selected = srv.selectSubnet(pkt);
+ EXPECT_FALSE(selected);
+
+ // CASE 4: We have three subnets defined and we received relayed traffic
+ // that came out of subnet 2. We should select subnet2 then
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1);
+ CfgMgr::instance().addSubnet6(subnet2);
+ CfgMgr::instance().addSubnet6(subnet3);
+ pkt->setRemoteAddr(IOAddress("2001:db8:2::baca"));
+ selected = srv.selectSubnet(pkt);
+ EXPECT_EQ(selected, subnet2);
+
+ // CASE 5: We have three subnets defined and we received relayed traffic
+ // that came out of undefined subnet. We should select nothing
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1);
+ CfgMgr::instance().addSubnet6(subnet2);
+ CfgMgr::instance().addSubnet6(subnet3);
+ pkt->setRemoteAddr(IOAddress("2001:db8:4::baca"));
+ selected = srv.selectSubnet(pkt);
+ EXPECT_FALSE(selected);
+
+}
+
+// This test verifies if selectSubnet() selects proper subnet for a given
+// network interface name.
+TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
+ NakedDhcpv6Srv srv(0);
+
+ Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
+ Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
+ Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
+
+ subnet1->setIface("eth0");
+ subnet3->setIface("wifi1");
+
+ // CASE 1: We have only one subnet defined and it is available via eth0.
+ // Packet came from eth0. The only available subnet should be selected
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+
+ Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+ pkt->setIface("eth0");
+
+ Subnet6Ptr selected = srv.selectSubnet(pkt);
+ EXPECT_EQ(selected, subnet1);
+
+ // CASE 2: We have only one subnet defined and it is available via eth0.
+ // Packet came from eth1. We should not select it
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
+
+ pkt->setIface("eth1");
+
+ selected = srv.selectSubnet(pkt);
+ EXPECT_FALSE(selected);
+
+ // CASE 3: We have only 3 subnets defined, one over eth0, one remote and
+ // one over wifi1.
+ // Packet came from eth1. We should not select it
+ CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().addSubnet6(subnet1);
+ CfgMgr::instance().addSubnet6(subnet2);
+ CfgMgr::instance().addSubnet6(subnet3);
+
+ pkt->setIface("eth0");
+ EXPECT_EQ(subnet1, srv.selectSubnet(pkt));
+
+ pkt->setIface("eth3"); // no such interface
+ EXPECT_EQ(Subnet6Ptr(), srv.selectSubnet(pkt)); // nothing selected
+
+ pkt->setIface("wifi1");
+ EXPECT_EQ(subnet3, srv.selectSubnet(pkt));
+
+}
+
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
index ee40130..c6a190f 100644
--- a/src/lib/dhcpsrv/cfgmgr.cc
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -123,6 +123,26 @@ CfgMgr::getOptionDef(const std::string& option_space,
}
Subnet6Ptr
+CfgMgr::getSubnet6(const std::string& iface) {
+
+ if (!iface.length()) {
+ return (Subnet6Ptr());
+ }
+
+ // If there is more than one, we need to choose the proper one
+ for (Subnet6Collection::iterator subnet = subnets6_.begin();
+ subnet != subnets6_.end(); ++subnet) {
+ if (iface == (*subnet)->getIface()) {
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+ DHCPSRV_CFGMGR_SUBNET6_IFACE)
+ .arg((*subnet)->toText()).arg(iface);
+ return (*subnet);
+ }
+ }
+ return (Subnet6Ptr());
+}
+
+Subnet6Ptr
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
// If there's only one subnet configured, let's just use it
@@ -143,6 +163,7 @@ CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
// If there is more than one, we need to choose the proper one
for (Subnet6Collection::iterator subnet = subnets6_.begin();
subnet != subnets6_.end(); ++subnet) {
+
if ((*subnet)->inRange(hint)) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
DHCPSRV_CFGMGR_SUBNET6)
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
index 9cfde9d..bc4ffde 100644
--- a/src/lib/dhcpsrv/cfgmgr.h
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -155,9 +155,18 @@ public:
///
/// @param hint an address that belongs to a searched subnet
///
- /// @return a subnet object
+ /// @return a subnet object (or NULL if no suitable match was fount)
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
+ /// @brief get IPv6 subnet by interface name
+ ///
+ /// Finds a matching local subnet, based on interface name. This
+ /// is used for selecting subnets that were explicitly marked by the
+ /// user as reachable over specified network interface.
+ /// @param iface_name interface name
+ /// @return a subnet object (or NULL if no suitable match was fount)
+ Subnet6Ptr getSubnet6(const std::string& iface_name);
+
/// @brief get IPv6 subnet by interface-id
///
/// Another possibility to find a subnet is based on interface-id.
diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes
index 27f12fc..8a7610b 100644
--- a/src/lib/dhcpsrv/dhcpsrv_messages.mes
+++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes
@@ -60,6 +60,12 @@ This is a debug message reporting that the DHCP configuration manager has
returned the specified IPv6 subnet when given the address hint specified
as the address is within the subnet.
+% DHCPSRV_CFGMGR_SUBNET6_IFACE selected subnet %1 for packet received over interface %2
+This is a debug message reporting that the DHCP configuration manager has
+returned the specified IPv6 subnet for a packet received over given interface.
+This particular subnet was selected, because it was specified as being directly
+reachable over given interface. (see 'interface' parameter in subnet6 definition).
+
% DHCPSRV_INVALID_ACCESS invalid database access string: %1
This is logged when an attempt has been made to parse a database access string
and the attempt ended in error. The access string in question - which
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
index 6414f88..0443a33 100644
--- a/src/lib/dhcpsrv/subnet.cc
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -184,5 +184,15 @@ Subnet6::validateOption(const OptionPtr& option) const {
}
}
+
+void Subnet6::setIface(const std::string& iface_name) {
+ iface_ = iface_name;
+}
+
+std::string Subnet6::getIface() const {
+ return (iface_);
+}
+
+
} // end of isc::dhcp namespace
} // end of isc namespace
diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h
index b864321..471fb03 100644
--- a/src/lib/dhcpsrv/subnet.h
+++ b/src/lib/dhcpsrv/subnet.h
@@ -416,6 +416,9 @@ protected:
/// fully trusted.
isc::asiolink::IOAddress last_allocated_;
+ /// @brief Name of the network interface (if connected directly)
+ std::string iface_;
+
private:
/// A collection of option spaces grouping option descriptors.
@@ -496,6 +499,18 @@ public:
return (preferred_);
}
+ /// @brief sets name of the network interface for directly attached networks
+ ///
+ /// A subnet may be reachable directly (not via relays). In DHCPv6 it is not
+ /// possible to decide that based on addresses assigned to network interfaces,
+ /// as DHCPv6 operates on link-local (and site local) addresses.
+ /// @param iface_name name of the interface
+ void setIface(const std::string& iface_name);
+
+ /// @brief network interface name used to reach subnet (or "" for remote subnets)
+ /// @return network interface name for directly attached subnets or ""
+ std::string getIface() const;
+
protected:
/// @brief Check if option is valid and can be added to a subnet.
diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
index d023a24..9b3d61b 100644
--- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
@@ -351,4 +351,8 @@ TEST_F(CfgMgrTest, optionSpace6) {
// @todo decide if a duplicate vendor space is allowed.
}
+// No specific tests for getSubnet6. That method (2 overloaded versions) is tested
+// in Dhcpv6SrvTest.selectSubnetAddr and Dhcpv6SrvTest.selectSubnetIface
+// (see src/bin/dhcp6/tests/dhcp6_srv_unittest.cc)
+
} // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc
index 689af87..9f06c89 100644
--- a/src/lib/dhcpsrv/tests/subnet_unittest.cc
+++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc
@@ -505,4 +505,15 @@ TEST(Subnet6Test, get) {
EXPECT_EQ(32, subnet.get().second);
}
+// This trivial test checks if interface name is stored properly
+// in Subnet6 objects.
+TEST(Subnet6Test, iface) {
+ Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
+
+ EXPECT_TRUE(subnet.getIface().empty());
+
+ subnet.setIface("en1");
+ EXPECT_EQ("en1", subnet.getIface());
+}
+
};
More information about the bind10-changes
mailing list