Skip to content

Commit 64c15b1

Browse files
committed
[#3583] Addressred review comments
modified: doc/sphinx/arm/classify.rst src/bin/dhcp4/dhcp4_srv.cc src/bin/dhcp4/tests/config_parser_unittest.cc src/bin/dhcp6/tests/config_parser_unittest.cc src/hooks/dhcp/mysql/mysql_cb_dhcp4.cc src/lib/dhcp/classify.cc src/lib/dhcp/classify.h src/lib/dhcp/tests/classify_unittest.cc src/lib/dhcpsrv/cfg_option.cc src/lib/dhcpsrv/cfg_option.h src/lib/dhcpsrv/parsers/option_data_parser.cc src/lib/dhcpsrv/parsers/simple_parser4.cc src/lib/dhcpsrv/parsers/simple_parser6.cc src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc src/lib/dhcpsrv/testutils/generic_backend_unittest.cc
1 parent c109b65 commit 64c15b1

File tree

15 files changed

+139
-28
lines changed

15 files changed

+139
-28
lines changed

doc/sphinx/arm/classify.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,12 @@ the same value for option "foo":
12461246
}]
12471247
}
12481248

1249+
The ``client-classes`` list is allowed in an option specification at
1250+
any scope. Option class-tagging is enforced at the time options are
1251+
being added to the response which occurs after lease assignment just
1252+
before the response is to be sent to the client.
1253+
1254+
12491255
When ``never-send`` for an option is true at any scope, all
12501256
``client-classes`` entries for that option are ignored. The
12511257
option will not included.

src/bin/dhcp4/dhcp4_srv.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,6 +2342,7 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
23422342
}
23432343
}
23442344

2345+
const auto& cclasses = query->getClasses();
23452346
for (uint32_t vendor_id : vendor_ids) {
23462347

23472348
std::set<uint8_t> cancelled_opts;
@@ -2406,7 +2407,7 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
24062407
if (!vendor_rsp->getOption(opt)) {
24072408
for (auto const& copts : co_list) {
24082409
OptionDescriptor desc = copts->get(vendor_id, opt);
2409-
if (desc.option_ && desc.allowedForClientClasses(query->getClasses())) {
2410+
if (desc.option_ && desc.allowedForClientClasses(cclasses)) {
24102411
vendor_rsp->addOption(desc.option_);
24112412
added = true;
24122413
break;
@@ -2446,6 +2447,7 @@ Dhcpv4Srv::appendBasicOptions(Dhcpv4Exchange& ex) {
24462447
}
24472448

24482449
Pkt4Ptr resp = ex.getResponse();
2450+
const auto& cclasses = ex.getQuery()->getClasses();
24492451

24502452
// Try to find all 'required' options in the outgoing
24512453
// message. Those that are not present will be added.
@@ -2456,7 +2458,7 @@ Dhcpv4Srv::appendBasicOptions(Dhcpv4Exchange& ex) {
24562458
for (auto const& copts : co_list) {
24572459
OptionDescriptor desc = copts->get(DHCP4_OPTION_SPACE, required);
24582460
/// @todo TKM - not sure if otion class-tagging should be allowed here?
2459-
if (desc.option_ && desc.allowedForClientClasses(ex.getQuery()->getClasses())) {
2461+
if (desc.option_ && desc.allowedForClientClasses(cclasses)) {
24602462
resp->addOption(desc.option_);
24612463
break;
24622464
}
@@ -3635,7 +3637,7 @@ Dhcpv4Srv::setFixedFields(Dhcpv4Exchange& ex) {
36353637

36363638
// Step 2: Try to set the values based on classes.
36373639
// Any values defined in classes will override those from subnet level.
3638-
const ClientClasses classes = query->getClasses();
3640+
const ClientClasses& classes = query->getClasses();
36393641
if (!classes.empty()) {
36403642

36413643
// Let's get class definitions

src/bin/dhcp4/tests/config_parser_unittest.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8013,4 +8013,38 @@ TEST_F(Dhcp4ParserTest, storeDdnsConflictResolutionMode) {
80138013
}
80148014
}
80158015

8016+
//This test verifies that duplicates in option-data.client-classes
8017+
// are ignored and do not affect class order.
8018+
TEST_F(Dhcp4ParserTest, optionClientClassesDuplicateCheck) {
8019+
std::string config = "{ " + genIfaceConfig() + ","
8020+
R"^(
8021+
"option-data": [{
8022+
"name": "domain-name",
8023+
"data": "example.com",
8024+
"client-classes": [ "foo", "bar", "foo", "bar" ]
8025+
}],
8026+
"rebind-timer": 2000,
8027+
"renew-timer": 1000,
8028+
"subnet4": [],
8029+
"valid-lifetime": 400
8030+
})^";
8031+
8032+
ConstElementPtr json;
8033+
ASSERT_NO_THROW(json = parseDHCP4(config));
8034+
extractConfig(config);
8035+
8036+
ConstElementPtr status;
8037+
ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
8038+
checkResult(status, 0);
8039+
8040+
CfgOptionPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgOption();
8041+
const auto desc = cfg->get(DHCP4_OPTION_SPACE, DHO_DOMAIN_NAME);
8042+
ASSERT_TRUE(desc.option_);
8043+
ASSERT_EQ(desc.client_classes_.size(), 2);
8044+
auto cclasses = desc.client_classes_.begin();
8045+
EXPECT_EQ(*cclasses, "foo");
8046+
++cclasses;
8047+
EXPECT_EQ(*cclasses, "bar");
8048+
}
8049+
80168050
} // namespace

src/bin/dhcp6/tests/config_parser_unittest.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8987,4 +8987,38 @@ TEST_F(Dhcp6ParserTest, storeDdnsConflictResolutionMode) {
89878987
}
89888988
}
89898989

8990+
// This test verifies that duplicates in option-data.client-classes
8991+
// are ignored and do not affect class order.
8992+
TEST_F(Dhcp6ParserTest, optionClientClassesDuplicateCheck) {
8993+
std::string config = "{ " + genIfaceConfig() + ","
8994+
R"^(
8995+
"option-data": [{
8996+
"name": "domain-search",
8997+
"data": "example.com",
8998+
"client-classes": [ "foo", "bar", "foo", "bar" ]
8999+
}],
9000+
"rebind-timer": 2000,
9001+
"renew-timer": 1000,
9002+
"subnet6": [],
9003+
"valid-lifetime": 400
9004+
})^";
9005+
9006+
ConstElementPtr json;
9007+
ASSERT_NO_THROW(json = parseDHCP6(config));
9008+
extractConfig(config);
9009+
9010+
ConstElementPtr status;
9011+
ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
9012+
checkResult(status, 0);
9013+
9014+
CfgOptionPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgOption();
9015+
const auto desc = cfg->get(DHCP6_OPTION_SPACE, D6O_DOMAIN_SEARCH);
9016+
ASSERT_TRUE(desc.option_);
9017+
ASSERT_EQ(desc.client_classes_.size(), 2);
9018+
auto cclasses = desc.client_classes_.begin();
9019+
EXPECT_EQ(*cclasses, "foo");
9020+
++cclasses;
9021+
EXPECT_EQ(*cclasses, "bar");
9022+
}
9023+
89909024
} // namespace

src/hooks/dhcp/mysql/mysql_cb_dhcp4.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ class MySqlConfigBackendDHCPv4Impl : public MySqlConfigBackendImpl {
18701870
cc_binding,
18711871
MySqlBinding::createString(tag),
18721872
MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
1873-
MySqlBinding::condCreateString(option->space_name_),
1873+
MySqlBinding::condCreateString(option->space_name_)
18741874
};
18751875

18761876
MySqlTransaction transaction(conn_);
@@ -2074,7 +2074,7 @@ class MySqlConfigBackendDHCPv4Impl : public MySqlConfigBackendImpl {
20742074
cc_binding,
20752075
MySqlBinding::createString(shared_network_name),
20762076
MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
2077-
MySqlBinding::condCreateString(option->space_name_),
2077+
MySqlBinding::condCreateString(option->space_name_)
20782078
};
20792079

20802080
boost::scoped_ptr<MySqlTransaction> transaction;

src/lib/dhcp/classify.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ ClientClasses::toElement() const {
8282
}
8383

8484
void
85-
ClientClasses::fromElement(isc::data::ElementPtr cc_list) {
85+
ClientClasses::fromElement(isc::data::ConstElementPtr cc_list) {
8686
if (cc_list) {
8787
clear();
8888
if (cc_list->getType() != Element::list) {
@@ -95,7 +95,7 @@ ClientClasses::fromElement(isc::data::ElementPtr cc_list) {
9595
isc_throw(BadValue, "elements of list must be valid strings");
9696
}
9797

98-
insert(cclass->stringValue());
98+
static_cast<void>(insert(cclass->stringValue()));
9999
}
100100
}
101101
}

src/lib/dhcp/classify.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,18 @@ namespace dhcp {
124124

125125
/// @brief Copy constructor.
126126
///
127-
/// @param ClientClasses object to be copied.
127+
/// @param other ClientClasses object to be copied.
128128
ClientClasses(const ClientClasses& other);
129129

130-
/// @brief Assigns the contents of on container to another
130+
/// @brief Assigns the contents of on container to another.
131131
ClientClasses& operator=(const ClientClasses& other);
132132

133133
/// @brief Compares two ClientClasses container for equality
134134
///
135135
/// @return True if the two containers are equal, false otherwise.
136136
bool equals(const ClientClasses& other) const;
137137

138-
/// @brief Compares two ClientClasses container for equality
138+
/// @brief Compares two ClientClasses containers for equality.
139139
///
140140
/// @return True if the two containers are equal, false otherwise.
141141
bool operator==(const ClientClasses& other) const {
@@ -227,9 +227,12 @@ namespace dhcp {
227227

228228
/// @brief Sets contents from a ListElement
229229
///
230+
/// @param list JSON list of classes from which to populate
231+
/// the container.
232+
///
230233
/// @throw BadValue if the element is not a list or contents
231234
/// are invalid
232-
void fromElement(isc::data::ElementPtr list);
235+
void fromElement(isc::data::ConstElementPtr list);
233236

234237
private:
235238
/// @brief container part

src/lib/dhcp/tests/classify_unittest.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,16 @@ TEST(ClassifyTest, ClientClassesFromElement) {
253253
cclasses_element = Element::createList();
254254
ASSERT_NO_THROW(classes.fromElement(cclasses_element));
255255
EXPECT_TRUE(classes.empty());
256+
257+
cclasses_element->add(Element::create("foo"));
258+
cclasses_element->add(Element::create("bar"));
259+
cclasses_element->add(Element::create("foo"));
260+
cclasses_element->add(Element::create("bar"));
261+
262+
ASSERT_NO_THROW(classes.fromElement(cclasses_element));
263+
ASSERT_EQ(classes.size(), 2);
264+
auto cclass = classes.begin();
265+
EXPECT_EQ(*cclass, "foo");
266+
++cclass;
267+
EXPECT_EQ(*cclass, "bar");
256268
}

src/lib/dhcpsrv/cfg_option.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,25 @@ OptionDescriptor::allowedForClientClasses(const ClientClasses& cclasses) const {
6464
if (client_classes_.empty()) {
6565
return (true);
6666
}
67-
68-
for (const auto& cclass : client_classes_) {
69-
if (cclasses.contains(cclass)) {
70-
return (true);
67+
68+
if (cclasses.size() > client_classes_.size()) {
69+
for (const auto& cclass : client_classes_) {
70+
if (cclasses.contains(cclass)) {
71+
return (true);
72+
}
73+
}
74+
}
75+
else {
76+
for (const auto& cclass : cclasses) {
77+
if (client_classes_.contains(cclass)) {
78+
return (true);
79+
}
7180
}
7281
}
7382

7483
return (false);
7584
}
7685

77-
7886
CfgOption::CfgOption()
7987
: encapsulated_(false) {
8088
}
@@ -108,7 +116,7 @@ CfgOption::add(const OptionDescriptor& desc, const std::string& option_space) {
108116
if (!desc.option_) {
109117
isc_throw(isc::BadValue, "option being configured must not be NULL");
110118

111-
} else if (!OptionSpace::validateName(option_space)) {
119+
} else if (!OptionSpace::validateName(option_space)) {
112120
isc_throw(isc::BadValue, "invalid option space name: '"
113121
<< option_space << "'");
114122
}

src/lib/dhcpsrv/cfg_option.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -817,8 +817,6 @@ class CfgOption : public isc::data::CfgToElement {
817817
VendorOptionSpaceCollection vendor_options_;
818818
};
819819

820-
class CfgOption; // forward declaration
821-
822820
/// @name Pointers to the @c CfgOption objects.
823821
//@{
824822

0 commit comments

Comments
 (0)