]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] Checkpoint: option-data ready
authorFrancis Dupont <fdupont@isc.org>
Wed, 29 Nov 2017 08:26:41 +0000 (09:26 +0100)
committerFrancis Dupont <fdupont@isc.org>
Wed, 29 Nov 2017 08:26:41 +0000 (09:26 +0100)
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/tests/config_parser_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/tests/cfg_option_unittest.cc

index 823d87f6e3911b134ddc93c42a790a0fda0aed6a..b92b166398d2370877e8e9ea41dccf7b8e582225 100644 (file)
@@ -583,6 +583,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser4Context::POOLS:
     case isc::dhcp::Parser4Context::SHARED_NETWORK:
     case isc::dhcp::Parser4Context::OPTION_DEF:
+    case isc::dhcp::Parser4Context::OPTION_DATA:
         return isc::dhcp::Dhcp4Parser::make_USER_CONTEXT(driver.loc_);
     default:
         return isc::dhcp::Dhcp4Parser::make_STRING("user-context", driver.loc_);
@@ -596,6 +597,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser4Context::POOLS:
     case isc::dhcp::Parser4Context::SHARED_NETWORK:
     case isc::dhcp::Parser4Context::OPTION_DEF:
+    case isc::dhcp::Parser4Context::OPTION_DATA:
         return isc::dhcp::Dhcp4Parser::make_COMMENT(driver.loc_);
     default:
         return isc::dhcp::Dhcp4Parser::make_STRING("comment", driver.loc_);
index 5b65a7bfa20f7b78f05e10ed8279f026fe855a99..044f0c401b304a6809f75fb1612b66939f97402a 100644 (file)
@@ -1261,6 +1261,8 @@ option_data_param: option_data_name
                  | option_data_space
                  | option_data_csv_format
                  | option_data_always_send
+                 | user_context
+                 | comment
                  | unknown_map_entry
                  ;
 
index 8f28f1ff2dd3beaeb8e25d7ef2a77b21af7822da..02820f538364f71b7d5a98860242c7638922dd93 100644 (file)
@@ -5619,6 +5619,12 @@ TEST_F(Dhcp4ParserTest, comments) {
         "    \"type\": \"ipv4-address\",\n"
         "    \"space\": \"isc\"\n"
         " } ],\n"
+        "\"option-data\": [ {\n"
+        "    \"name\": \"dhcp-message\",\n"
+        "    \"comment\": \"Set option value\",\n"
+        "    \"data\": \"ABCDEF0105\",\n"
+        "    \"csv-format\": false\n"
+        " } ],\n"
         "\"shared-networks\": [ {\n"
         "    \"name\": \"foo\"\n,"
         "    \"comment\": \"A shared network\"\n,"
@@ -5647,10 +5653,7 @@ TEST_F(Dhcp4ParserTest, comments) {
     ASSERT_TRUE(ctx->get("comment"));
     EXPECT_EQ("\"A DHCPv4 server\"", ctx->get("comment")->str());
 
-    // Make the option definition available.
-    LibDHCP::commitRuntimeOptionDefs();
-
-    // Get and verify the option definition.
+    // There is a global option definition.
     OptionDefinitionPtr opt_def = LibDHCP::getRuntimeOptionDef("isc", 100);
     ASSERT_TRUE(opt_def);
     EXPECT_EQ("foo", opt_def->getName());
@@ -5659,13 +5662,27 @@ TEST_F(Dhcp4ParserTest, comments) {
     EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, opt_def->getType());
     EXPECT_TRUE(opt_def->getEncapsulatedSpace().empty());
 
-    // Check option definition user context
+    // Check option definition user context.
     ConstElementPtr ctx_opt_def = opt_def->getContext();
     ASSERT_TRUE(ctx_opt_def);
     ASSERT_EQ(1, ctx_opt_def->size());
     ASSERT_TRUE(ctx_opt_def->get("comment"));
     EXPECT_EQ("\"An option definition\"", ctx_opt_def->get("comment")->str());
 
+    // There is an option descriptor aka option data.
+    OptionDescriptor opt_desc =
+        CfgMgr::instance().getStagingCfg()->getCfgOption()->
+            get(DHCP4_OPTION_SPACE, DHO_DHCP_MESSAGE);
+    ASSERT_TRUE(opt_desc.option_);
+    EXPECT_EQ(DHO_DHCP_MESSAGE, opt_desc.option_->getType());
+
+    // Check option descriptor user context.
+    ConstElementPtr ctx_opt_desc = opt_desc.getContext();
+    ASSERT_TRUE(ctx_opt_desc);
+    ASSERT_EQ(1, ctx_opt_desc->size());
+    ASSERT_TRUE(ctx_opt_desc->get("comment"));
+    EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
+
     // Now verify that the shared network was indeed configured.
     CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
         ->getCfgSharedNetworks4();
@@ -5676,7 +5693,7 @@ TEST_F(Dhcp4ParserTest, comments) {
     SharedNetwork4Ptr net = nets->at(0);
     ASSERT_TRUE(net);
 
-    // Check shared network user context
+    // Check shared network user context.
     ConstElementPtr ctx_net = net->getContext();
     ASSERT_TRUE(ctx_net);
     ASSERT_EQ(1, ctx_net->size());
@@ -5690,20 +5707,20 @@ TEST_F(Dhcp4ParserTest, comments) {
     Subnet4Ptr sub = subs->at(0);
     ASSERT_TRUE(sub);
 
-    // Check subnet user context
+    // Check subnet user context.
     ConstElementPtr ctx_sub = sub->getContext();
     ASSERT_TRUE(ctx_sub);
     ASSERT_EQ(1, ctx_sub->size());
     ASSERT_TRUE(ctx_sub->get("comment"));
     EXPECT_EQ("\"A subnet\"", ctx_sub->get("comment")->str());
 
-    // The subnet has a pool
+    // The subnet has a pool.
     const PoolCollection& pools = sub->getPools(Lease::TYPE_V4);
     ASSERT_EQ(1, pools.size());
     PoolPtr pool = pools.at(0);
     ASSERT_TRUE(pool);
 
-    // Check pool user context                                               
+    // Check pool user context.
     ConstElementPtr ctx_pool = pool->getContext();
     ASSERT_TRUE(ctx_pool);
     ASSERT_EQ(1, ctx_pool->size());
index 785481fa2e94af095b2484dcb35977cec654e26a..4519388d4910aa53ad682f0653347ceb4c99f4b8 100644 (file)
@@ -814,6 +814,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SHARED_NETWORK:
     case isc::dhcp::Parser6Context::OPTION_DEF:
+    case isc::dhcp::Parser6Context::OPTION_DATA:
         return isc::dhcp::Dhcp6Parser::make_USER_CONTEXT(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("user-context", driver.loc_);
@@ -828,6 +829,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SHARED_NETWORK:
     case isc::dhcp::Parser6Context::OPTION_DEF:
+    case isc::dhcp::Parser6Context::OPTION_DATA:
         return isc::dhcp::Dhcp6Parser::make_COMMENT(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("comment", driver.loc_);
index 4ed697666c00b62fbe486e5139e6464d8dacd626..be31e1b77ad5dd0a19c63a5da8ae2fc6f2f01c2e 100644 (file)
@@ -1225,6 +1225,8 @@ option_data_param: option_data_name
                  | option_data_space
                  | option_data_csv_format
                  | option_data_always_send
+                 | user_context
+                 | comment
                  | unknown_map_entry
                  ;
 
index c81444f7690210580430cf8138cb1a12d07d0acf..2d69334b6a453bb02b1eb66b8bb8ef4b50ddf321 100644 (file)
@@ -6061,6 +6061,12 @@ TEST_F(Dhcp6ParserTest, comments) {
         "    \"type\": \"ipv6-address\",\n"
         "    \"space\": \"isc\"\n"
         " } ],\n"
+        "\"option-data\": [ {\n"
+        "    \"name\": \"subscriber-id\",\n"
+        "    \"comment\": \"Set option value\",\n"
+        "    \"data\": \"ABCDEF0105\",\n"
+        "        \"csv-format\": false\n"
+        " } ],\n"
         "\"shared-networks\": [ {\n"
         "    \"name\": \"foo\"\n,"
         "    \"comment\": \"A shared network\"\n,"
@@ -6090,17 +6096,14 @@ TEST_F(Dhcp6ParserTest, comments) {
     extractConfig(config);
     configure(config, CONTROL_RESULT_SUCCESS, "");
 
-    // Check global user context
+    // Check global user context.
     ConstElementPtr ctx = CfgMgr::instance().getStagingCfg()->getContext();
     ASSERT_TRUE(ctx);
     ASSERT_EQ(1, ctx->size());
     ASSERT_TRUE(ctx->get("comment"));
     EXPECT_EQ("\"A DHCPv6 server\"", ctx->get("comment")->str());
 
-    // Make the option definition available.
-    LibDHCP::commitRuntimeOptionDefs();
-
-    // Get and verify the option definition.
+    // There is a global option definition.
     OptionDefinitionPtr opt_def = LibDHCP::getRuntimeOptionDef("isc", 100);
     ASSERT_TRUE(opt_def);
     EXPECT_EQ("foo", opt_def->getName());
@@ -6109,13 +6112,27 @@ TEST_F(Dhcp6ParserTest, comments) {
     EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, opt_def->getType());
     EXPECT_TRUE(opt_def->getEncapsulatedSpace().empty());
 
-    // Check option definition user context
+    // Check option definition user context.
     ConstElementPtr ctx_opt_def = opt_def->getContext();
     ASSERT_TRUE(ctx_opt_def);
     ASSERT_EQ(1, ctx_opt_def->size());
     ASSERT_TRUE(ctx_opt_def->get("comment"));
     EXPECT_EQ("\"An option definition\"", ctx_opt_def->get("comment")->str());
 
+    // There is an option descriptor aka option data.
+    OptionDescriptor opt_desc =
+        CfgMgr::instance().getStagingCfg()->getCfgOption()->
+            get(DHCP6_OPTION_SPACE, D6O_SUBSCRIBER_ID);
+    ASSERT_TRUE(opt_desc.option_);
+    EXPECT_EQ(D6O_SUBSCRIBER_ID, opt_desc.option_->getType());
+
+    // Check option descriptor user context.
+    ConstElementPtr ctx_opt_desc = opt_desc.getContext();
+    ASSERT_TRUE(ctx_opt_desc);
+    ASSERT_EQ(1, ctx_opt_desc->size());
+    ASSERT_TRUE(ctx_opt_desc->get("comment"));
+    EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
+
     // Now verify that the shared network was indeed configured.
     CfgSharedNetworks6Ptr cfg_net = CfgMgr::instance().getStagingCfg()
         ->getCfgSharedNetworks6();
@@ -6126,7 +6143,7 @@ TEST_F(Dhcp6ParserTest, comments) {
     SharedNetwork6Ptr net = nets->at(0);
     ASSERT_TRUE(net);
 
-    // Check shared network user context
+    // Check shared network user context.
     ConstElementPtr ctx_net = net->getContext();
     ASSERT_TRUE(ctx_net);
     ASSERT_EQ(1, ctx_net->size());
@@ -6140,33 +6157,33 @@ TEST_F(Dhcp6ParserTest, comments) {
     Subnet6Ptr sub = subs->at(0);
     ASSERT_TRUE(sub);
 
-    // Check subnet user context
+    // Check subnet user context.
     ConstElementPtr ctx_sub = sub->getContext();
     ASSERT_TRUE(ctx_sub);
     ASSERT_EQ(1, ctx_sub->size());
     ASSERT_TRUE(ctx_sub->get("comment"));
     EXPECT_EQ("\"A subnet\"", ctx_sub->get("comment")->str());
 
-    // The subnet has a pool
+    // The subnet has a pool.
     const PoolCollection& pools = sub->getPools(Lease::TYPE_NA);
     ASSERT_EQ(1, pools.size());
     PoolPtr pool = pools.at(0);
     ASSERT_TRUE(pool);
 
-    // Check pool user context                                               
+    // Check pool user context.
     ConstElementPtr ctx_pool = pool->getContext();
     ASSERT_TRUE(ctx_pool);
     ASSERT_EQ(1, ctx_pool->size());
     ASSERT_TRUE(ctx_pool->get("comment"));
     EXPECT_EQ("\"A pool\"", ctx_pool->get("comment")->str());
 
-    // The subnet has a prefix pool
+    // The subnet has a prefix pool.
     const PoolCollection& pdpools = sub->getPools(Lease::TYPE_PD);
     ASSERT_EQ(1, pdpools.size());
     PoolPtr pdpool = pdpools.at(0);
     ASSERT_TRUE(pdpool);
 
-    // Check prefix pool user context                                               
+    // Check prefix pool user context.
     ConstElementPtr ctx_pdpool = pdpool->getContext();
     ASSERT_TRUE(ctx_pdpool);
     ASSERT_EQ(1, ctx_pdpool->size());
index 1fac24d5b8302697f15cad121ed92aaaab74cf09..54da107110f2264989f7b7116973b3a5845a8d35 100644 (file)
@@ -201,7 +201,9 @@ CfgOption::toElement() const {
              opt != opts->end(); ++opt) {
             // Get and fill the map for this option
             ElementPtr map = Element::createMap();
-            // First set space from parent iterator
+            // Set user context
+            opt->contextToElement(map);
+            // Set space from parent iterator
             map->set("space", Element::create(*name));
             // Set the code
             uint16_t code = opt->option_->getType();
@@ -242,7 +244,9 @@ CfgOption::toElement() const {
              opt != opts->end(); ++opt) {
             // Get and fill the map for this option
             ElementPtr map = Element::createMap();
-            // First set space from parent iterator
+            // Set user context
+            opt->contextToElement(map);
+            // Set space from parent iterator
             std::ostringstream oss;
             oss << "vendor-" << *id;
             map->set("space", Element::create(oss.str()));
index b0d527cfd3a6d1ab133c41c0c52d58fd5bcf3bb9..5bff00fd2f879be3d17f75a55770b3dfd06c971a 100644 (file)
@@ -10,6 +10,7 @@
 #include <dhcp/option.h>
 #include <dhcp/option_space_container.h>
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <dhcpsrv/key_from_key.h>
 #include <boost/multi_index_container.hpp>
 #include <boost/multi_index/hashed_index.hpp>
@@ -30,7 +31,8 @@ namespace dhcp {
 /// for this option. This information comprises whether this option is sent
 /// to DHCP client only on request (persistent = false) or always
 /// (persistent = true).
-struct OptionDescriptor {
+class OptionDescriptor : public UserContext {
+public:
     /// @brief Option instance.
     OptionPtr option_;
 
index 8280addd34559d19df5becf95341229a599aead7..27fd9ab41f021fcf57d8fc77178afcabe9364bec 100644 (file)
@@ -235,6 +235,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
     OptionalValue<bool> persist_param = extractPersistent(option_data);
     std::string data_param = extractData(option_data);
     std::string space_param = extractSpace(option_data);
+    ConstElementPtr user_context = option_data->get("user-context");
 
     // Require that option code or option name is specified.
     if (!code_param.isSpecified() && !name_param.isSpecified()) {
@@ -357,6 +358,11 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
         }
     }
 
+    // Add user context
+    if (user_context) {
+        desc.setContext(user_context);
+    }
+
     // All went good, so we can set the option space name.
     return make_pair(desc, space_param);
 }
index 99d0c7d6564837873b8d7fe7d99241b269e9b1c9..0ad1f56ae7d9c87f533d626ba675f8c76e18827e 100644 (file)
@@ -600,6 +600,7 @@ TEST_F(CfgOptionTest, unparse) {
     cfg.add(opt1, false, "dns");
     OptionPtr opt2(new Option(Option::V6, 101, OptionBuffer(4, 12)));
     OptionDescriptor desc2(opt2, false, "12, 12, 12, 12");
+    desc2.setContext(data::Element::fromJSON("{ \"comment\": \"foo\" }"));
     cfg.add(desc2, "dns");
     OptionPtr opt3(new Option(Option::V6, D6O_STATUS_CODE, OptionBuffer(2, 0)));
     cfg.add(opt3, false, DHCP6_OPTION_SPACE);
@@ -615,6 +616,7 @@ TEST_F(CfgOptionTest, unparse) {
         "    \"data\": \"12121212\",\n"
         "    \"always-send\": false\n"
         "},{\n"
+        "    \"comment\": \"foo\",\n"
         "    \"code\": 101,\n"
         "    \"space\": \"dns\",\n"
         "    \"csv-format\": true,\n"