Commit 042c5348 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac4105' (4o6 configuration parameters)

parents 5df470d0 7e2a3760
......@@ -200,6 +200,12 @@ protected:
parser = new OptionDataListParser(config_id, options_, AF_INET);
} else if (config_id.compare("match-client-id") == 0) {
parser = new BooleanParser(config_id, boolean_values_);
} else if (config_id.compare("4o6-subnet") == 0) {
parser = new StringParser(config_id, string_values_);
} else if (config_id.compare("4o6-interface") == 0) {
parser = new StringParser(config_id, string_values_);
} else if (config_id.compare("4o6-interface-id") == 0) {
parser = new StringParser(config_id, string_values_);
} else {
isc_throw(NotImplemented, "unsupported parameter: " << config_id);
}
......@@ -305,6 +311,43 @@ protected:
<< ")");
}
// Try 4o6 specific parameter: 4o6-interface
string iface4o6 = string_values_->getOptionalParam("4o6-interface", "");
if (!iface4o6.empty()) {
subnet4->get4o6().setIface4o6(iface4o6);
subnet4->get4o6().enabled(true);
}
// Try 4o6 specific parameter: 4o6-subnet
string subnet4o6 = string_values_->getOptionalParam("4o6-subnet", "");
if (!subnet4o6.empty()) {
size_t slash = subnet4o6.find("/");
if (slash == std::string::npos) {
isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
+ subnet4o6 +", expected format: prefix6/length");
}
string prefix = subnet4o6.substr(0, slash);
string lenstr = subnet4o6.substr(slash + 1);
uint8_t len = 128;
try {
len = boost::lexical_cast<unsigned int>(lenstr.c_str());
} catch (const boost::bad_lexical_cast &) {
isc_throw(DhcpConfigError, "Invalid prefix length specified in "
"4o6-subnet parameter: " + subnet4o6 + ", expected 0..128 value");
}
subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
subnet4->get4o6().enabled(true);
}
// Try 4o6 specific paramter: 4o6-interface-id
std::string ifaceid = string_values_->getOptionalParam("4o6-interface-id", "");
if (!ifaceid.empty()) {
OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
subnet4->get4o6().setInterfaceId(opt);
subnet4->get4o6().enabled(true);
}
// Try setting up client class (if specified)
try {
......
......@@ -3782,4 +3782,245 @@ TEST_F(Dhcp4ParserTest, expiredLeasesProcessingError) {
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
}
// Checks if the DHCPv4 is able to parse the configuration without 4o6 parameters
// and does not set 4o6 fields at all.
TEST_F(Dhcp4ParserTest, 4o6default) {
ConstElementPtr status;
// Just a plain v4 config (no 4o6 parameters)
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// check if returned status is OK
checkResult(status, 0);
// Now check if the configuration was indeed handled and we have
// expected pool configured.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
Cfg4o6& dhcp4o6 = subnet->get4o6();
EXPECT_FALSE(dhcp4o6.enabled());
}
// Checks if the DHCPv4 is able to parse the configuration with 4o6 subnet
// defined.
TEST_F(Dhcp4ParserTest, 4o6subnet) {
ConstElementPtr status;
// Just a plain v4 config (no 4o6 parameters)
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-subnet\": \"2001:db8::123/45\" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// check if returned status is OK
checkResult(status, 0);
// Now check if the configuration was indeed handled and we have
// expected pool configured.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
Cfg4o6& dhcp4o6 = subnet->get4o6();
EXPECT_TRUE(dhcp4o6.enabled());
EXPECT_EQ(IOAddress("2001:db8::123"), dhcp4o6.getSubnet4o6().first);
EXPECT_EQ(45, dhcp4o6.getSubnet4o6().second);
}
// Checks if the DHCPv4 is able to parse the configuration with 4o6 subnet
// defined.
TEST_F(Dhcp4ParserTest, 4o6subnetBogus) {
ConstElementPtr status;
// Just a plain v4 config (no 4o6 parameters)
string config[] = {
// Bogus configuration 1: missing / in subnet
"{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-subnet\": \"2001:db8::123\" } ],"
"\"valid-lifetime\": 4000 }",
// Bogus configuration 2: incorrect address
"{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-subnet\": \"2001:db8:bogus/45\" } ],"
"\"valid-lifetime\": 4000 }",
// Bogus configuration 3: incorrect prefix lenght
"{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-subnet\": \"2001:db8::123/200\" } ],"
"\"valid-lifetime\": 4000 }"
};
ElementPtr json1 = Element::fromJSON(config[0]);
ElementPtr json2 = Element::fromJSON(config[0]);
ElementPtr json3 = Element::fromJSON(config[0]);
// Check that the first config is rejected.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json1));
checkResult(status, 1);
// Check that the second config is rejected.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json2));
checkResult(status, 1);
// Check that the third config is rejected.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json3));
checkResult(status, 1);
}
// Checks if the DHCPv4 is able to parse the configuration with 4o6 network
// interface defined.
TEST_F(Dhcp4ParserTest, 4o6iface) {
ConstElementPtr status;
// Just a plain v4 config (no 4o6 parameters)
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-interface\": \"ethX\" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// check if returned status is OK
checkResult(status, 0);
// Now check if the configuration was indeed handled and we have
// expected pool configured.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
Cfg4o6& dhcp4o6 = subnet->get4o6();
EXPECT_TRUE(dhcp4o6.enabled());
EXPECT_EQ("ethX", dhcp4o6.getIface4o6());
}
// Checks if the DHCPv4 is able to parse the configuration with both 4o6 network
// interface and v6 subnet defined.
TEST_F(Dhcp4ParserTest, 4o6subnetIface) {
ConstElementPtr status;
// Just a plain v4 config (no 4o6 parameters)
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-subnet\": \"2001:db8::543/21\","
" \"4o6-interface\": \"ethX\" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// check if returned status is OK
checkResult(status, 0);
// Now check if the configuration was indeed handled and we have
// expected subnet configured...
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
// ... and that subnet has 4o6 network interface specified.
Cfg4o6& dhcp4o6 = subnet->get4o6();
EXPECT_TRUE(dhcp4o6.enabled());
EXPECT_EQ(IOAddress("2001:db8::543"), dhcp4o6.getSubnet4o6().first);
EXPECT_EQ(21, dhcp4o6.getSubnet4o6().second);
EXPECT_EQ("ethX", dhcp4o6.getIface4o6());
}
// Checks if the DHCPv4 is able to parse the configuration with 4o6 network
// interface-id.
TEST_F(Dhcp4ParserTest, 4o6subnetInterfaceId) {
ConstElementPtr status;
// Just a plain v4 config (no 4o6 parameters)
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"4o6-interface-id\": \"vlan123\" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// check if returned status is OK
checkResult(status, 0);
// Now check if the configuration was indeed handled and we have
// expected 4o6-interface-id configured.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
Cfg4o6& dhcp4o6 = subnet->get4o6();
EXPECT_TRUE(dhcp4o6.enabled());
OptionPtr ifaceid = dhcp4o6.getInterfaceId();
ASSERT_TRUE(ifaceid);
vector<uint8_t> data = ifaceid->getData();
const char *exp_data = "vlan123";
// Let's convert vlan123 to vector<uint8_t> format.
// We need to skip the last \0 byte, thuse sizeof() - 1.
vector<uint8_t> exp(exp_data, exp_data + sizeof(exp_data) - 1);
EXPECT_TRUE(exp == data);
}
}
......@@ -507,6 +507,83 @@ private:
/// @brief A generic pointer to either Subnet4 or Subnet6 object
typedef boost::shared_ptr<Subnet> SubnetPtr;
/// @brief This structure contains information about DHCP4o6 (RFC7341)
///
/// DHCP4o6 is completely optional. If it is not enabled, this structure
/// does not contain any information.
struct Cfg4o6 {
/// the default constructor.
///
/// Initializes fields to their default value.
Cfg4o6()
:enabled_(false), subnet4o6_(std::make_pair(asiolink::IOAddress("::"), 128u)) {
}
/// @brief Returns whether the DHCP4o6 is enabled or not.
/// @return true if enabled
bool enabled() const {
return (enabled_);
}
/// @brief Sets the DHCP4o6 enabled status.
/// @param enabled specifies if the DHCP4o6 should be enabled or not
void enabled(bool enabled) {
enabled_ = enabled;
}
/// @brief Returns the DHCP4o6 interface.
/// @return value of the 4o6-interface parameter.
std::string getIface4o6() const {
return (iface4o6_);
}
/// @brief Sets the 4o6-interface.
/// @param iface name of the network interface the 4o6 traffic is received on
void setIface4o6(const std::string& iface) {
iface4o6_ = iface;
}
/// @brief Returns prefix/len for the IPv6 subnet.
/// @return prefix/length pair
std::pair<asiolink::IOAddress, uint8_t> getSubnet4o6() const {
return (subnet4o6_);
}
/// @brief Sets the prefix/length information (content of the 4o6-subnet).
/// @param subnet IOAddress that represents a prefix
/// @param prefix specifies prefix length
void setSubnet4o6(const asiolink::IOAddress& subnet, uint8_t prefix) {
subnet4o6_ = std::make_pair(subnet, prefix);
}
/// @brief Returns the interface-id.
/// @return the option representing interface-id (or NULL)
OptionPtr getInterfaceId() const {
return (interface_id_);
}
/// @brief Sets the interface-id
/// @param opt option to be used as interface-id match
void setInterfaceId(const OptionPtr& opt) {
interface_id_ = opt;
}
private:
/// Specifies if 4o6 is enabled on this subnet.
bool enabled_;
/// Specifies the network interface used as v4 subnet selector.
std::string iface4o6_;
/// Specifies the IPv6 subnet used for v4 subnet selection.
std::pair<asiolink::IOAddress, uint8_t> subnet4o6_;
/// Specifies the v6 interface-id used for v4 subnet selection.
OptionPtr interface_id_;
};
/// @brief A configuration holder for IPv4 subnet.
///
/// This class represents an IPv4 subnet.
......@@ -559,6 +636,14 @@ public:
return (match_client_id_);
}
/// @brief Returns DHCP4o6 configuration parameters.
///
/// This structure is always available. If the 4o6 is not enabled, its
/// enabled_ field will be set to false.
Cfg4o6& get4o6() {
return (dhcp4o6_);
}
private:
/// @brief Returns default address for pool selection
......@@ -581,6 +666,9 @@ private:
/// @brief Should server use client identifiers for client lease
/// lookup.
bool match_client_id_;
/// @brief All the information related to DHCP4o6
Cfg4o6 dhcp4o6_;
};
/// @brief A pointer to a @c Subnet4 object
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment