" \"data\": \"ABCDEF0105\",\n"
" \"csv-format\": false\n"
" } ],\n"
+ "\"client-classes\": [ {\n"
+ " \"name\": \"all\",\n"
+ " \"comment\": \"match all\",\n"
+ " \"test\": \"'' == ''\"\n"
+ " } ],\n"
"\"shared-networks\": [ {\n"
" \"name\": \"foo\"\n,"
" \"comment\": \"A shared network\"\n,"
ASSERT_TRUE(ctx_opt_desc->get("comment"));
EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
+ // And there is a client class.
+ ClientClassDictionaryPtr dict =
+ CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
+ ASSERT_TRUE(dict);
+ EXPECT_EQ(1, dict->getClasses()->size());
+ ClientClassDefPtr cclass = dict->findClass("all");
+ ASSERT_TRUE(cclass);
+ EXPECT_EQ("all", cclass->getName());
+ EXPECT_EQ("'' == ''", cclass->getTest());
+
+ // Check client class user context.
+ ConstElementPtr ctx_class = cclass->getContext();
+ ASSERT_TRUE(ctx_class);
+ ASSERT_EQ(1, ctx_class->size());
+ ASSERT_TRUE(ctx_class->get("comment"));
+ EXPECT_EQ("\"match all\"", ctx_class->get("comment")->str());
+
// Now verify that the shared network was indeed configured.
CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
->getCfgSharedNetworks4();
// CONFIGURATION 58
"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
+" \"client-classes\": [\n"
+" {\n"
+" \"comment\": \"match all\",\n"
+" \"name\": \"all\",\n"
+" \"test\": \"'' == ''\"\n"
+" }\n"
+" ],\n"
+" \"option-data\": [\n"
+" {\n"
+" \"comment\": \"Set option value\",\n"
+" \"csv-format\": false,\n"
+" \"data\": \"ABCDEF0105\",\n"
+" \"name\": \"dhcp-message\"\n"
+" }\n"
+" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
// CONFIGURATION 58
"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
+" \"client-classes\": [\n"
+" {\n"
+" \"comment\": \"match all\",\n"
+" \"boot-file-name\": \"\",\n"
+" \"name\": \"all\",\n"
+" \"next-server\": \"0.0.0.0\",\n"
+" \"option-data\": [ ],\n"
+" \"option-def\": [ ],\n"
+" \"server-hostname\": \"\",\n"
+" \"test\": \"'' == ''\"\n"
+" }\n"
+" ],\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
-" \"option-data\": [ ],\n"
+" \"option-data\": [\n"
+" {\n"
+" \"comment\": \"Set option value\",\n"
+" \"always-send\": false,\n"
+" \"code\": 56,\n"
+" \"csv-format\": false,\n"
+" \"data\": \"ABCDEF0105\",\n"
+" \"name\": \"dhcp-message\",\n"
+" \"space\": \"dhcp4\"\n"
+" }\n"
+" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
" \"data\": \"ABCDEF0105\",\n"
" \"csv-format\": false\n"
" } ],\n"
+ "\"client-classes\": [ {\n"
+ " \"name\": \"all\",\n"
+ " \"comment\": \"match all\",\n"
+ " \"test\": \"'' == ''\"\n"
+ " } ],\n"
"\"shared-networks\": [ {\n"
" \"name\": \"foo\"\n,"
" \"comment\": \"A shared network\"\n,"
ASSERT_TRUE(ctx_opt_desc->get("comment"));
EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
+ // And there is a client class.
+ ClientClassDictionaryPtr dict =
+ CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
+ ASSERT_TRUE(dict);
+ EXPECT_EQ(1, dict->getClasses()->size());
+ ClientClassDefPtr cclass = dict->findClass("all");
+ ASSERT_TRUE(cclass);
+ EXPECT_EQ("all", cclass->getName());
+ EXPECT_EQ("'' == ''", cclass->getTest());
+
+ // Check client class user context.
+ ConstElementPtr ctx_class = cclass->getContext();
+ ASSERT_TRUE(ctx_class);
+ ASSERT_EQ(1, ctx_class->size());
+ ASSERT_TRUE(ctx_class->get("comment"));
+ EXPECT_EQ("\"match all\"", ctx_class->get("comment")->str());
+
// Now verify that the shared network was indeed configured.
CfgSharedNetworks6Ptr cfg_net = CfgMgr::instance().getStagingCfg()
->getCfgSharedNetworks6();
// CONFIGURATION 51
"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
+" \"client-classes\": [\n"
+" {\n"
+" \"comment\": \"match all\",\n"
+" \"name\": \"all\",\n"
+" \"test\": \"'' == ''\"\n"
+" }\n"
+" ],\n"
+" \"option-data\": [\n"
+" {\n"
+" \"comment\": \"Set option value\",\n"
+" \"csv-format\": false,\n"
+" \"data\": \"ABCDEF0105\",\n"
+" \"name\": \"subscriber-id\"\n"
+" }\n"
+" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
// CONFIGURATION 51
"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
+" \"client-classes\": [\n"
+" {\n"
+" \"comment\": \"match all\",\n"
+" \"name\": \"all\",\n"
+" \"option-data\": [ ],\n"
+" \"test\": \"'' == ''\"\n"
+" }\n"
+" ],\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"mac-sources\": [ \"any\" ],\n"
-" \"option-data\": [ ],\n"
+" \"option-data\": [\n"
+" {\n"
+" \"comment\": \"Set option value\",\n"
+" \"always-send\": false,\n"
+" \"code\": 38,\n"
+" \"csv-format\": false,\n"
+" \"data\": \"ABCDEF0105\",\n"
+" \"name\": \"subscriber-id\",\n"
+" \"space\": \"dhcp6\"\n"
+" }\n"
+" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
ClientClassDef:: toElement() const {
uint16_t family = CfgMgr::instance().getFamily();
ElementPtr result = Element::createMap();
+ // Set user-context
+ contextToElement(result);
// Set name
result->set("name", Element::create(name_));
// Set original match expression (empty string won't parse)
const std::string& test,
const CfgOptionPtr& cfg_option,
CfgOptionDefPtr cfg_option_def,
+ ConstElementPtr user_context,
asiolink::IOAddress next_server,
const std::string& sname,
const std::string& filename) {
ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
cclass->setTest(test);
cclass->setCfgOptionDef(cfg_option_def);
+ cclass->setContext(user_context),
cclass->setNextServer(next_server);
cclass->setSname(sname);
cclass->setFilename(filename);
#define CLIENT_CLASS_DEF_H
#include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfg_option_def.h>
#include <eval/token.h>
};
/// @brief Embodies a single client class definition
-class ClientClassDef : public isc::data::CfgToElement {
+class ClientClassDef : public UserContext, public isc::data::CfgToElement {
public:
/// @brief Constructor
///
/// @param test Original version of match_expr
/// @param options Collection of options members should be given
/// @param defs Option definitions (optional)
+ /// @param user_context User context (optional)
/// @param next_server next-server value for this class (optional)
/// @param sname server-name value for this class (optional)
/// @param filename boot-file-name value for this class (optional)
void addClass(const std::string& name, const ExpressionPtr& match_expr,
const std::string& test, const CfgOptionPtr& options,
CfgOptionDefPtr defs = CfgOptionDefPtr(),
+ isc::data::ConstElementPtr user_context = isc::data::ConstElementPtr(),
asiolink::IOAddress next_server = asiolink::IOAddress("0.0.0.0"),
const std::string& sname = std::string(),
const std::string& filename = std::string());
opts_parser.parse(options, option_data);
}
+ // Parse user context
+ ConstElementPtr user_context = class_def_cfg->get("user-context");
+
// Let's try to parse the next-server field
IOAddress next_server("0.0.0.0");
if (class_def_cfg->contains("next-server")) {
// Add the client class definition
try {
- class_dictionary->addClass(name, match_expr, test, options,
- defs, next_server, sname, filename);
+ class_dictionary->addClass(name, match_expr, test, options, defs,
+ user_context, next_server, sname, filename);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, "Can't add class: " << ex.what()
<< " (" << class_def_cfg->getPosition() << ")");
ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr)));
std::string test = "option[12].text == 'foo'";
cclass->setTest(test);
+ std::string comment = "bar";
+ std::string user_context = "{ \"comment\": \"" + comment + "\" }";
+ cclass->setContext(isc::data::Element::fromJSON(user_context));
std::string next_server = "1.2.3.4";
cclass->setNextServer(IOAddress(next_server));
std::string sname = "my-server.example.com";
// Unparse it
std::string expected = "{\n"
+ "\"comment\": \"" + comment + "\",\n"
"\"name\": \"" + name + "\",\n"
"\"test\": \"" + test + "\",\n"
"\"next-server\": \"" + next_server + "\",\n"