return (client_classes_.intersects(cclasses));
}
+std::set<std::string> CfgOption::multiple_encapsulating_spaces_ = {
+ V6_NTP_SERVER_SPACE
+};
+
CfgOption::CfgOption()
: encapsulated_(false) {
}
// Get encapsulated option space for the option.
const std::string& encap_space = option->getEncapsulatedSpace();
// Empty value means that no option space is encapsulated.
- if (!encap_space.empty()) {
- if (encap_space == DHCP4_OPTION_SPACE || encap_space == DHCP6_OPTION_SPACE) {
- return;
+ if (encap_space.empty()) {
+ return;
+ }
+ if (encap_space == DHCP4_OPTION_SPACE || encap_space == DHCP6_OPTION_SPACE) {
+ return;
+ }
+ // Retrieve all options from the encapsulated option space.
+ OptionContainerPtr encap_options = getAll(encap_space);
+ for (auto const& encap_opt : *encap_options) {
+ if (option.get() == encap_opt.option_.get()) {
+ // Avoid recursion by not adding options to themselves.
+ continue;
}
- // Retrieve all options from the encapsulated option space.
- OptionContainerPtr encap_options = getAll(encap_space);
- for (auto const& encap_opt : *encap_options) {
- if (option.get() == encap_opt.option_.get()) {
- // Avoid recursion by not adding options to themselves.
- continue;
- }
- // Add sub-option if there isn't one added already.
- if (!option->getOption(encap_opt.option_->getType())) {
- option->addOption(encap_opt.option_);
- }
- encapsulateInternal(encap_opt.option_);
+ // Add sub-option if there isn't one added already, or
+ // if encapsulating space is a multiple exception.
+ OptionPtr existing = option->getOption(encap_opt.option_->getType());
+ if (!existing ||
+ (multiple_encapsulating_spaces_.count(encap_space) > 0)) {
+ option->addOption(encap_opt.option_);
}
+ encapsulateInternal(encap_opt.option_);
}
}
}
}
+// This test verifies that multiple encapsulating spaces are supported,
+TEST_F(CfgOptionTest, multipleEncapsulatingSpaces) {
+ CfgOption cfg;
+
+ // Add a ntp-server option.
+ OptionPtr ntp_server(new Option(Option::V6, D6O_NTP_SERVER));
+ ntp_server->setEncapsulatedSpace(V6_NTP_SERVER_SPACE);
+ ASSERT_NO_THROW(cfg.add(ntp_server, false, false, DHCP6_OPTION_SPACE));
+
+ // Get ntp-server-address sub-option definition.
+ OptionDefinitionPtr def =
+ LibDHCP::getOptionDef(V6_NTP_SERVER_SPACE, NTP_SUBOPTION_SRV_ADDR);
+ ASSERT_TRUE(def);
+
+ // Add sub-options for 2001:db8::77 and 2001:db8::88.
+ IOAddress addr1("2001:db8::77");
+ auto const& buf1 = addr1.toBytes();
+ OptionCustomPtr sub1(new OptionCustom(*def, Option::V6, buf1));
+ ASSERT_NO_THROW(cfg.add(sub1, false, false, V6_NTP_SERVER_SPACE));
+ IOAddress addr2("2001:db8::88");
+ auto const& buf2 = addr2.toBytes();
+ OptionCustomPtr sub2(new OptionCustom(*def, Option::V6, buf2));
+ ASSERT_NO_THROW(cfg.add(sub2, false, false, V6_NTP_SERVER_SPACE));
+
+ // Encapsulate.
+ ASSERT_NO_THROW(cfg.encapsulate());
+
+ // Check we have ntp-server with 2 (not 1) sub-options.
+ OptionDescriptor desc = cfg.get(DHCP6_OPTION_SPACE, D6O_NTP_SERVER);
+ OptionPtr opt = desc.option_;
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(D6O_NTP_SERVER, opt->getType());
+ EXPECT_EQ(V6_NTP_SERVER_SPACE, opt->getEncapsulatedSpace());
+ auto const& subs = opt->getOptions();
+ ASSERT_EQ(2U, subs.size());
+ for (auto const& sub : subs) {
+ EXPECT_EQ(NTP_SUBOPTION_SRV_ADDR, sub.first);
+ }
+}
+
// This test verifies that an option can be deleted from the configuration.
TEST_F(CfgOptionTest, deleteOptions) {
CfgOption cfg;