From: Francis Dupont Date: Wed, 29 Nov 2017 09:27:30 +0000 (+0100) Subject: [5351] Added client classes. Todo: update doc X-Git-Tag: trac5444_base~15 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e9198441ddbab33b630fb0f76dfdcf0a378ab001;p=thirdparty%2Fkea.git [5351] Added client classes. Todo: update doc --- diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index 02820f5383..0afa9b0b7a 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -5625,6 +5625,11 @@ TEST_F(Dhcp4ParserTest, comments) { " \"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," @@ -5683,6 +5688,23 @@ TEST_F(Dhcp4ParserTest, comments) { 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(); diff --git a/src/bin/dhcp4/tests/get_config_unittest.cc b/src/bin/dhcp4/tests/get_config_unittest.cc index adeabb72b6..c457e98b8d 100644 --- a/src/bin/dhcp4/tests/get_config_unittest.cc +++ b/src/bin/dhcp4/tests/get_config_unittest.cc @@ -1588,6 +1588,21 @@ const char* EXTRACTED_CONFIGS[] = { // 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" @@ -6262,6 +6277,18 @@ const char* UNPARSED_CONFIGS[] = { // 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" @@ -6298,7 +6325,17 @@ const char* UNPARSED_CONFIGS[] = { " \"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" diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 2d69334b6a..5962f0873e 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -6067,6 +6067,11 @@ TEST_F(Dhcp6ParserTest, comments) { " \"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," @@ -6133,6 +6138,23 @@ TEST_F(Dhcp6ParserTest, comments) { 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(); diff --git a/src/bin/dhcp6/tests/get_config_unittest.cc b/src/bin/dhcp6/tests/get_config_unittest.cc index fb0d2bde29..4ac8ae512c 100644 --- a/src/bin/dhcp6/tests/get_config_unittest.cc +++ b/src/bin/dhcp6/tests/get_config_unittest.cc @@ -1463,6 +1463,21 @@ const char* EXTRACTED_CONFIGS[] = { // 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" @@ -5873,6 +5888,14 @@ const char* UNPARSED_CONFIGS[] = { // 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" @@ -5909,7 +5932,17 @@ const char* UNPARSED_CONFIGS[] = { " \"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" diff --git a/src/lib/dhcpsrv/client_class_def.cc b/src/lib/dhcpsrv/client_class_def.cc index d07de4b717..5eb263777b 100644 --- a/src/lib/dhcpsrv/client_class_def.cc +++ b/src/lib/dhcpsrv/client_class_def.cc @@ -132,6 +132,8 @@ ElementPtr 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) @@ -185,12 +187,14 @@ ClientClassDictionary::addClass(const std::string& name, 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); diff --git a/src/lib/dhcpsrv/client_class_def.h b/src/lib/dhcpsrv/client_class_def.h index 1167aa012a..81e4a179aa 100644 --- a/src/lib/dhcpsrv/client_class_def.h +++ b/src/lib/dhcpsrv/client_class_def.h @@ -8,6 +8,7 @@ #define CLIENT_CLASS_DEF_H #include +#include #include #include #include @@ -39,7 +40,7 @@ public: }; /// @brief Embodies a single client class definition -class ClientClassDef : public isc::data::CfgToElement { +class ClientClassDef : public UserContext, public isc::data::CfgToElement { public: /// @brief Constructor /// @@ -236,6 +237,7 @@ public: /// @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) @@ -246,6 +248,7 @@ public: 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()); diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc index 5829393342..bd1ac03510 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc @@ -127,6 +127,9 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, 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")) { @@ -182,8 +185,8 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, // 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() << ")"); diff --git a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc index d7dd3ae58e..a4fb2ac007 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc @@ -386,6 +386,9 @@ TEST(ClientClassDef, unparseDef) { 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"; @@ -395,6 +398,7 @@ TEST(ClientClassDef, unparseDef) { // Unparse it std::string expected = "{\n" + "\"comment\": \"" + comment + "\",\n" "\"name\": \"" + name + "\",\n" "\"test\": \"" + test + "\",\n" "\"next-server\": \"" + next_server + "\",\n"