]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3582] Extended option-data toElement
authorFrancis Dupont <fdupont@isc.org>
Fri, 18 Oct 2024 08:04:54 +0000 (10:04 +0200)
committerTomek Mrugalski <tomek@isc.org>
Wed, 23 Oct 2024 10:29:32 +0000 (10:29 +0000)
src/lib/dhcpsrv/cfg_option.cc
src/lib/dhcpsrv/cfg_option.h
src/lib/dhcpsrv/client_class_def.cc
src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc

index 1fca0521be13ec5c410c480a9fa706db67eb0fe5..4471fcd16752da9dc37669f1487152e9e2a71cfa 100644 (file)
@@ -477,7 +477,13 @@ CfgOption::toElement() const {
 }
 
 ElementPtr
-CfgOption::toElementWithMetadata(const bool include_metadata) const {
+CfgOption::toElement(CfgOptionDefPtr cfg_option_def) const {
+    return (toElementWithMetadata(false, cfg_option_def));
+}
+
+ElementPtr
+CfgOption::toElementWithMetadata(const bool include_metadata,
+                                 CfgOptionDefPtr cfg_option_def) const {
     // option-data value is a list of maps
     ElementPtr result = Element::createList();
     // Iterate first on options using space names
@@ -495,7 +501,13 @@ CfgOption::toElementWithMetadata(const bool include_metadata) const {
             uint16_t code = opt.option_->getType();
             map->set("code", Element::create(code));
             // Set the name (always for standard options else when asked for)
-            OptionDefinitionPtr def = LibDHCP::getOptionDef(name, code);
+            OptionDefinitionPtr def;
+            if (cfg_option_def) {
+                def = cfg_option_def->get(name, code);
+            }
+            if (!def) {
+                def = LibDHCP::getOptionDef(name, code);
+            }
             if (!def) {
                 def = LibDHCP::getRuntimeOptionDef(name, code);
             }
index f9c5382331b9e7f993403c7693753c3a03d96a2a..31e86cff888b074a0301e8c691117d8fc2bd8cc2 100644 (file)
@@ -747,15 +747,23 @@ public:
     /// @return a pointer to unparsed configuration
     virtual isc::data::ElementPtr toElement() const;
 
+    /// @brief Unparse a configuration object
+    ///
+    /// @param cfg_option_def config option definitions
+    /// @return a pointer to unparsed configuration
+    virtual isc::data::ElementPtr toElement(CfgOptionDefPtr cfg_option_def) const;
+
     /// @brief Unparse a configuration object with optionally including
     /// the metadata.
     ///
     /// @param include_metadata boolean value indicating if the metadata
     /// should be included (if true) or not (if false).
+    /// @param cfg_option_def config option definitions (optional).
     ///
     /// @return A pointer to the unparsed configuration.
     isc::data::ElementPtr
-    toElementWithMetadata(const bool include_metadata) const;
+    toElementWithMetadata(const bool include_metadata,
+                         CfgOptionDefPtr cfg_option_def = CfgOptionDefPtr()) const;
 
 private:
 
index fd0148913aa2c62211890fc0acdd9c7f67cd81c8..5d3ff21e031ea6225d14908c535f44a6eb9ba46e 100644 (file)
@@ -239,9 +239,11 @@ ClientClassDef::toElement() const {
     // Set option-def (used only by DHCPv4)
     if (cfg_option_def_ && (family == AF_INET)) {
         result->set("option-def", cfg_option_def_->toElement());
+        result->set("option-data", cfg_option_->toElement(cfg_option_def_));
+    } else {
+        // Set option-data
+        result->set("option-data", cfg_option_->toElement());
     }
-    // Set option-data
-    result->set("option-data", cfg_option_->toElement());
 
     if (family == AF_INET) {
         // V4 only
index 5b3d9a95a80aff4a71850b7663752339df8173da..8795ef385aea4666b6f30ec384dd2bf65ba75c3e 100644 (file)
@@ -1472,6 +1472,66 @@ TEST_F(ClientClassDefParserTest, option43Def) {
     EXPECT_EQ(0, std::memcmp(expected, &opt->getData()[0], 4));
 }
 
+// Test verifies option-def and option-data is correctly unparsed
+// option 43 as a string.
+TEST_F(ClientClassDefParserTest, option43DefString) {
+    std::string cfg_text =
+        "{ \n"
+        "    \"name\": \"aruba\", \n"
+        "    \"option-def\": [ \n"
+        "        { \n"
+        "           \"name\": \"vendor-encapsulated-options\", \n"
+        "           \"code\": 43, \n"
+        "           \"space\": \"dhcp4\", \n"
+        "           \"type\": \"string\" \n"
+        "        } \n"
+        "      ], \n"
+        "    \"option-data\": [ \n"
+        "      { \n"
+        "         \"name\": \"vendor-encapsulated-options\", \n"
+        "         \"csv-format\": true, \n"
+        "         \"data\": \"192.168.0.150\" \n"
+        "      } \n"
+        "    ] \n"
+        "} \n";
+
+    ClientClassDefPtr cclass;
+    ASSERT_NO_THROW(cclass = parseClientClassDef(cfg_text, AF_INET));
+
+    // We should find our class.
+    ASSERT_TRUE(cclass);
+
+    // And the option definition.
+    CfgOptionDefPtr cfg_def = cclass->getCfgOptionDef();
+    ASSERT_TRUE(cfg_def);
+    EXPECT_TRUE(cfg_def->get(DHCP4_OPTION_SPACE, 43));
+
+    // Verify the option data.
+    OptionDescriptor od = cclass->getCfgOption()->get(DHCP4_OPTION_SPACE, 43);
+    ASSERT_TRUE(od.option_);
+    EXPECT_EQ(43, od.option_->getType());
+    OptionStringPtr opstr = boost::dynamic_pointer_cast<OptionString>(od.option_);
+    ASSERT_TRUE(opstr);
+    EXPECT_EQ("192.168.0.150", opstr->getValue());
+
+    // Verify unparse.
+    auto const& unparsed = cclass->toElement();
+    ASSERT_TRUE(unparsed);
+    ASSERT_EQ(unparsed->getType(), Element::map);
+    auto const& option_data = unparsed->get("option-data");
+    ASSERT_TRUE(option_data);
+    ASSERT_EQ(option_data->getType(), Element::list);
+    ASSERT_EQ(1, option_data->size());
+    auto const& option = option_data->get(0);
+    ASSERT_TRUE(option);
+    ASSERT_EQ(option->getType(), Element::map);
+    auto const& data = option->get("data");
+    ASSERT_TRUE(data);
+    ASSERT_EQ(data->getType(), Element::string);
+    // Data entry must be "192.168.0.150", not "".
+    EXPECT_EQ("192.168.0.150", data->stringValue());
+}
+
 // Test verifies that it is possible to define next-server field and it
 // is actually set in the class properly.
 TEST_F(ClientClassDefParserTest, nextServer) {