From: Marcin Siodelski Date: Thu, 1 Sep 2016 13:37:24 +0000 (+0200) Subject: [4765] Client classes in HR can be specified in configuration file. X-Git-Tag: trac5006_base~14^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24213920f8d60ff73eacbca213f3a5caee7aa971;p=thirdparty%2Fkea.git [4765] Client classes in HR can be specified in configuration file. --- diff --git a/src/lib/dhcpsrv/cfg_hosts.cc b/src/lib/dhcpsrv/cfg_hosts.cc index 748fd4d273..bc0c1167d2 100644 --- a/src/lib/dhcpsrv/cfg_hosts.cc +++ b/src/lib/dhcpsrv/cfg_hosts.cc @@ -580,7 +580,9 @@ CfgHosts::add4(const HostPtr& host) { host->getServerHostname().empty() && host->getBootFileName().empty() && host->getCfgOption4()->empty() && - host->getCfgOption6()->empty()) { + host->getCfgOption6()->empty() && + host->getClientClasses4().empty() && + host->getClientClasses6().empty()) { std::ostringstream s; if (hwaddr) { s << "for DUID: " << hwaddr->toText(); diff --git a/src/lib/dhcpsrv/host.cc b/src/lib/dhcpsrv/host.cc index 8b3bbb3e1e..abd8113395 100644 --- a/src/lib/dhcpsrv/host.cc +++ b/src/lib/dhcpsrv/host.cc @@ -347,6 +347,7 @@ Host::addClientClass4(const std::string& class_name) { addClientClassInternal(dhcp4_client_classes_, class_name); } + void Host::addClientClass6(const std::string& class_name) { addClientClassInternal(dhcp6_client_classes_, class_name); diff --git a/src/lib/dhcpsrv/parsers/host_reservation_parser.cc b/src/lib/dhcpsrv/parsers/host_reservation_parser.cc index f7e7a24680..7a4055ee1c 100644 --- a/src/lib/dhcpsrv/parsers/host_reservation_parser.cc +++ b/src/lib/dhcpsrv/parsers/host_reservation_parser.cc @@ -52,6 +52,7 @@ getSupportedParams4(const bool identifiers_only = false) { params_set.insert("next-server"); params_set.insert("server-hostname"); params_set.insert("boot-file-name"); + params_set.insert("client-classes"); } return (identifiers_only ? identifiers_set : params_set); } @@ -83,6 +84,7 @@ getSupportedParams6(const bool identifiers_only = false) { params_set.insert("ip-addresses"); params_set.insert("prefixes"); params_set.insert("option-data"); + params_set.insert("client-classes"); } return (identifiers_only ? identifiers_set : params_set); } @@ -102,10 +104,10 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) { std::string identifier_name; std::string hostname; - // Gather those parameters that are common for both IPv4 and IPv6 - // reservations. - BOOST_FOREACH(ConfigPair element, reservation_data->mapValue()) { - try { + try { + // Gather those parameters that are common for both IPv4 and IPv6 + // reservations. + BOOST_FOREACH(ConfigPair element, reservation_data->mapValue()) { // Check if we support this parameter. if (!isSupportedParameter(element.first)) { isc_throw(DhcpConfigError, "unsupported configuration" @@ -123,15 +125,10 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) { } else if (element.first == "hostname") { hostname = element.second->stringValue(); + } - } catch (const std::exception& ex) { - // Append line number where the error occurred. - isc_throw(DhcpConfigError, ex.what() << " (" - << element.second->getPosition() << ")"); } - } - try { // Host identifier is a must. if (identifier_name.empty()) { // If there is no identifier specified, we have to display an @@ -210,19 +207,25 @@ HostReservationParser4::build(isc::data::ConstElementPtr reservation_data) { host_->setIPv4Reservation(IOAddress(element.second-> stringValue())); } else if (element.first == "next-server") { - host_->setNextServer(IOAddress(element.second->stringValue())); + host_->setNextServer(IOAddress(element.second->stringValue())); } else if (element.first == "server-hostname") { host_->setServerHostname(element.second->stringValue()); } else if (element.first == "boot-file-name") { host_->setBootFileName(element.second->stringValue()); + + } else if (element.first == "client-classes") { + BOOST_FOREACH(ConstElementPtr class_element, + element.second->listValue()) { + host_->addClientClass4(class_element->stringValue()); + } } } catch (const std::exception& ex) { // Append line number where the error occurred. isc_throw(DhcpConfigError, ex.what() << " (" - << reservation_data->getPosition() << ")"); + << element.second->getPosition() << ")"); } } } @@ -318,6 +321,19 @@ HostReservationParser6::build(isc::data::ConstElementPtr reservation_data) { << prefix_element->getPosition() << ")"); } } + + + } else if (element.first == "client-classes") { + try { + BOOST_FOREACH(ConstElementPtr class_element, + element.second->listValue()) { + host_->addClientClass6(class_element->stringValue()); + } + } catch (const std::exception& ex) { + // Append line number where the error occurred. + isc_throw(DhcpConfigError, ex.what() << " (" + << element.second->getPosition() << ")"); + } } } diff --git a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc index f083299927..5c05dd2eb2 100644 --- a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc @@ -300,6 +300,29 @@ TEST_F(HostReservationParserTest, dhcp4NoHostname) { EXPECT_TRUE(hosts[0]->getHostname().empty()); } +// This test verifies that it is possible to specify DHCPv4 client classes +// within the host reservation. +TEST_F(HostReservationParserTest, dhcp4ClientClasses) { + std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\"," + "\"client-classes\": [ \"foo\", \"bar\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser4 parser(SubnetID(10)); + ASSERT_NO_THROW(parser.build(config_element)); + + CfgHostsPtr cfg_hosts = CfgMgr::instance().getStagingCfg()->getCfgHosts(); + HostCollection hosts; + ASSERT_NO_THROW(hosts = cfg_hosts->getAll(hwaddr_)); + + ASSERT_EQ(1, hosts.size()); + + const ClientClasses& classes = hosts[0]->getClientClasses4(); + ASSERT_EQ(2, classes.size()); + EXPECT_EQ(1, classes.count("foo")); + EXPECT_EQ(1, classes.count("bar")); +} + // This test verifies that the parser can parse reservation entry // containing next-server, server-hostname and boot-file-name values for // DHCPv4 message fields. @@ -627,6 +650,29 @@ TEST_F(HostReservationParserTest, dhcp6NoHostname) { ASSERT_EQ(0, std::distance(prefixes.first, prefixes.second)); } +// This test verifies that it is possible to specify DHCPv4 client classes +// within the host reservation. +TEST_F(HostReservationParserTest, dhcp6ClientClasses) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"client-classes\": [ \"foo\", \"bar\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(10)); + ASSERT_NO_THROW(parser.build(config_element)); + + CfgHostsPtr cfg_hosts = CfgMgr::instance().getStagingCfg()->getCfgHosts(); + HostCollection hosts; + ASSERT_NO_THROW(hosts = cfg_hosts->getAll(Host::IDENT_DUID, + &duid_->getDuid()[0], + duid_->getDuid().size())); + ASSERT_EQ(1, hosts.size()); + + const ClientClasses& classes = hosts[0]->getClientClasses6(); + ASSERT_EQ(2, classes.size()); + EXPECT_EQ(1, classes.count("foo")); + EXPECT_EQ(1, classes.count("bar")); +} // This test verifies that the configuration parser throws an exception // when IPv4 address is specified for IPv6 reservation.