\"user-context\" {
switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::POOLS:
return isc::dhcp::Dhcp4Parser::make_USER_CONTEXT(driver.loc_);
default:
| subnet_4o6_interface
| subnet_4o6_interface_id
| subnet_4o6_subnet
+ | user_context
| unknown_map_entry
;
" \"always-send\": true"
" }"
" ]"
- "}" };
+ "}",
+
+ // Configuration 3:
+ // - one subnet, with one pool
+ // - user-contexts defined in both subnet and pool
+ "{"
+ " \"subnet4\": [ { "
+ " \"pools\": [ { \"pool\": \"10.254.226.0/25\","
+ " \"user-context\": { \"value\": 42 } } ],"
+ " \"subnet\": \"10.254.226.0/24\", "
+ " \"user-context\": {"
+ " \"secure\": false"
+ " }"
+ " } ],"
+ "\"valid-lifetime\": 4000 }",
+};
// This test verifies that the destination address of the response
// message is set to giaddr, when giaddr is set to non-zero address
EXPECT_NO_THROW(client.doDORA());
}
+// Checks if user-contexts are parsed properly.
+TEST_F(Dhcpv4SrvTest, userContext) {
+
+ IfaceMgrTestConfig test_config(true);
+
+ NakedDhcpv4Srv srv(0);
+
+ // This config has one subnet with user-context with one
+ // pool (also with context). Make sure the configuration could be accepted.
+ cout << CONFIGS[3] << endl;
+ EXPECT_NO_THROW(configure(CONFIGS[3]));
+
+ // Now make sure the data was not lost.
+ ConstSrvConfigPtr cfg = CfgMgr::instance().getCurrentCfg();
+ const Subnet4Collection* subnets = cfg->getCfgSubnets4()->getAll();
+ ASSERT_TRUE(subnets);
+ ASSERT_EQ(1, subnets->size());
+
+ // Let's get the subnet and check its context.
+ Subnet4Ptr subnet1 = (*subnets)[0];
+ ASSERT_TRUE(subnet1);
+ ASSERT_TRUE(subnet1->getContext());
+ EXPECT_EQ("{ \"secure\": false }", subnet1->getContext()->str());
+
+ // Ok, not get the sole pool in it and check its context, too.
+ PoolCollection pools = subnet1->getPools(Lease::TYPE_V4);
+ ASSERT_EQ(1, pools.size());
+ ASSERT_TRUE(pools[0]);
+ ASSERT_TRUE(pools[0]->getContext());
+ EXPECT_EQ("{ \"value\": 42 }", pools[0]->getContext()->str());
+}
/// @todo: Implement proper tests for MySQL lease/host database,
/// see ticket #4214.
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::POOLS:
case isc::dhcp::Parser6Context::PD_POOLS:
+ case isc::dhcp::Parser6Context::SUBNET6:
return isc::dhcp::Dhcp6Parser::make_USER_CONTEXT(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("user-context", driver.loc_);
| reservations
| reservation_mode
| relay
+ | user_context
| unknown_map_entry
;
" \"always-send\": true"
" }"
" ]"
+ "}",
+
+ // Configuration 3:
+ // - one subnet with one address pool and one prefix pool
+ // - user-contexts defined in subnet and each pool
+ "{"
+ " \"subnet6\": [ {"
+ " \"pools\": [ {"
+ " \"pool\": \"2001:db8:1::/64\","
+ " \"user-context\": { \"value\": 42 }"
+ " } ], "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:abcd::\","
+ " \"prefix-len\": 48,"
+ " \"delegated-len\": 64,"
+ " \"user-context\": { \"type\": \"prefixes\" }"
+ " } ],"
+ " \"subnet\": \"2001:db8:1::/48\","
+ " \"user-context\": { \"secure\": false }"
+ " } ] "
"}"
};
EXPECT_NO_THROW(client.doSARR());
}
+// Checks if user-contexts are parsed properly.
+TEST_F(Dhcpv6SrvTest, userContext) {
+
+ IfaceMgrTestConfig test_config(true);
+
+ NakedDhcpv6Srv srv(0);
+
+ // This config has one subnet with user-context with one
+ // pool (also with context). Make sure the configuration could be accepted.
+ EXPECT_NO_THROW(configure(CONFIGS[3]));
+
+ // Now make sure the data was not lost.
+ ConstSrvConfigPtr cfg = CfgMgr::instance().getCurrentCfg();
+ const Subnet6Collection* subnets = cfg->getCfgSubnets6()->getAll();
+ ASSERT_TRUE(subnets);
+ ASSERT_EQ(1, subnets->size());
+
+ // Let's get the subnet and check its context.
+ Subnet6Ptr subnet1 = (*subnets)[0];
+ ASSERT_TRUE(subnet1);
+ ASSERT_TRUE(subnet1->getContext());
+ EXPECT_EQ("{ \"secure\": false }", subnet1->getContext()->str());
+
+ // Ok, not get the address pool in it and check its context, too.
+ PoolCollection pools = subnet1->getPools(Lease::TYPE_NA);
+ ASSERT_EQ(1, pools.size());
+ ASSERT_TRUE(pools[0]);
+ ASSERT_TRUE(pools[0]->getContext());
+ EXPECT_EQ("{ \"value\": 42 }", pools[0]->getContext()->str());
+
+ // Ok, not get the prefix pool in it and check its context, too.
+ pools = subnet1->getPools(Lease::TYPE_PD);
+ ASSERT_EQ(1, pools.size());
+ ASSERT_TRUE(pools[0]);
+ ASSERT_TRUE(pools[0]->getContext());
+ EXPECT_EQ("{ \"type\": \"prefixes\" }", pools[0]->getContext()->str());
+}
+
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
<< user_context->getPosition() << ")");
}
- pool->setUserContext(user_context);
+ pool->setContext(user_context);
}
// Parser pool specific options.
subnet_->allowClientClass(client_class);
}
+ // If there's user-context specified, store it.
+ ConstElementPtr user_context = params->get("user-context");
+ if (user_context) {
+ if (user_context->getType() != Element::map) {
+ isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
+ << user_context->getPosition() << ")");
+ }
+ subnet_->setContext(user_context);
+ }
+
// Here globally defined options were merged to the subnet specific
// options but this is no longer the case (they have a different
// and not consecutive priority).
}
if (user_context_) {
- pool_->setUserContext(user_context_);
+ pool_->setContext(user_context_);
}
// Add the local pool to the external storage ptr.
/// @brief Sets user context.
/// @param ctx user context to be stored.
- void setUserContext(const data::ConstElementPtr& ctx) {
+ void setContext(const data::ConstElementPtr& ctx) {
user_context_ = ctx;
}
ConstCfgOptionPtr opts = getCfgOption();
map->set("option-data", opts->toElement());
+ // Add user-context, but only if defined. Omit if it was not.
+ ConstElementPtr ctx = getContext();
+ if (ctx) {
+ map->set("user-context", ctx);
+ }
+
return (map);
}
host_reservation_mode_ = mode;
}
+ /// @brief Sets user context.
+ /// @param ctx user context to be stored.
+ void setContext(const data::ConstElementPtr& ctx) {
+ user_context_ = ctx;
+ }
+
+ /// @brief Returns const pointer to the user context.
+ data::ConstElementPtr getContext() const {
+ return (user_context_);
+ }
+
protected:
/// @brief Returns all pools (non-const variant)
///
///
/// See @ref HRMode type for details.
HRMode host_reservation_mode_;
+
+ /// @brief Pointer to the user context (may be NULL)
+ data::ConstElementPtr user_context_;
private:
/// @brief Pointer to the option data configuration for this subnet.
#include <config.h>
#include <asiolink/io_address.h>
+#include <cc/data.h>
#include <dhcp/option6_pdexclude.h>
#include <dhcpsrv/pool.h>
using boost::scoped_ptr;
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::data;
using namespace isc::asiolink;
namespace {
EXPECT_TRUE(options->empty());
}
+// This test checks that handling for user-context is valid.
+TEST(Pool4Test, userContext) {
+ // Create a pool to add options to it.
+ Pool4Ptr pool(new Pool4(IOAddress("192.0.2.0"),
+ IOAddress("192.0.2.255")));
+
+ // Context should be empty until explicitly set.
+ EXPECT_FALSE(pool->getContext());
+
+ // When set, should be returned properly.
+ ElementPtr ctx = Element::create("{ \"comment\": \"foo\" }");
+ EXPECT_NO_THROW(pool->setContext(ctx));
+ ASSERT_TRUE(pool->getContext());
+ EXPECT_EQ(ctx->str(), pool->getContext()->str());
+}
+
TEST(Pool6Test, constructor_first_last) {
// let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
EXPECT_TRUE(options->empty());
}
+// This test checks that handling for user-context is valid.
+TEST(Pool6Test, userContext) {
+ // Create a pool to add options to it.
+ Pool6 pool(Lease::TYPE_NA, IOAddress("2001:db8::1"),
+ IOAddress("2001:db8::2"));
+
+ // Context should be empty until explicitly set.
+ EXPECT_FALSE(pool.getContext());
+
+ // When set, should be returned properly.
+ ElementPtr ctx = Element::create("{ \"comment\": \"foo\" }");
+ EXPECT_NO_THROW(pool.setContext(ctx));
+ ASSERT_TRUE(pool.getContext());
+ EXPECT_EQ(ctx->str(), pool.getContext()->str());
+}
+
}; // end of anonymous namespace