]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3907] updated control-socket in yang modules
authorRazvan Becheriu <razvan@isc.org>
Wed, 18 Jun 2025 19:16:23 +0000 (22:16 +0300)
committerRazvan Becheriu <razvan@isc.org>
Fri, 20 Jun 2025 13:29:10 +0000 (13:29 +0000)
38 files changed:
doc/examples/kea4/all-keys-netconf.json
doc/examples/kea6/all-keys-netconf.json
src/bin/dhcp4/tests/parser_unittest.cc
src/lib/yang/adaptor_config.cc
src/lib/yang/adaptor_config.h
src/lib/yang/translator.h
src/lib/yang/translator_class.cc
src/lib/yang/translator_class.h
src/lib/yang/translator_config.cc
src/lib/yang/translator_config.h
src/lib/yang/translator_control_socket.cc
src/lib/yang/translator_control_socket.h
src/lib/yang/translator_logger.cc
src/lib/yang/translator_pd_pool.cc
src/lib/yang/translator_pd_pool.h
src/lib/yang/translator_pool.cc
src/lib/yang/translator_pool.h
src/lib/yang/translator_shared_network.cc
src/lib/yang/translator_shared_network.h
src/lib/yang/translator_subnet.cc
src/lib/yang/translator_subnet.h
src/lib/yang/yang_revisions.h
src/share/yang/modules/hashes/kea-ctrl-agent@2019-08-12.hash [deleted file]
src/share/yang/modules/hashes/kea-ctrl-agent@2025-06-25.hash [new file with mode: 0644]
src/share/yang/modules/hashes/kea-dhcp-ddns@2022-07-27.hash [deleted file]
src/share/yang/modules/hashes/kea-dhcp-ddns@2025-06-25.hash [new file with mode: 0644]
src/share/yang/modules/hashes/kea-dhcp-types@2025-06-25.hash
src/share/yang/modules/hashes/kea-dhcp4-server@2025-06-25.hash
src/share/yang/modules/hashes/kea-dhcp6-server@2025-06-25.hash
src/share/yang/modules/hashes/kea-types@2019-08-12.hash [deleted file]
src/share/yang/modules/hashes/kea-types@2025-06-25.hash [new file with mode: 0644]
src/share/yang/modules/kea-ctrl-agent@2025-06-25.yang [moved from src/share/yang/modules/kea-ctrl-agent@2019-08-12.yang with 83% similarity]
src/share/yang/modules/kea-dhcp-ddns@2025-06-25.yang [moved from src/share/yang/modules/kea-dhcp-ddns@2022-07-27.yang with 90% similarity]
src/share/yang/modules/kea-dhcp-types@2025-06-25.yang
src/share/yang/modules/kea-dhcp4-server@2025-06-25.yang
src/share/yang/modules/kea-dhcp6-server@2025-06-25.yang
src/share/yang/modules/kea-types@2025-06-25.yang [moved from src/share/yang/modules/kea-types@2019-08-12.yang with 63% similarity]
src/share/yang/modules/meson.build

index fbf45b126269d4e0b370ce749e03efcd715caab2..e350af1bd2d0cd6d17d385b6ce57de791fc6aa16 100644 (file)
         },
 
         // Command control socket configuration parameters for the Kea DHCPv4 server.
-        "control-socket": {
-            // Location of the UNIX domain socket file the DHCPv4 server uses
-            // to receive control commands from the Kea Control Agent or the
-            // local server administrator.
-            "socket-name": "kea4-ctrl-socket",
-
-            // Control socket type used by the Kea DHCPv4 server. The 'unix'
-            // socket is currently the only supported type.
-            "socket-type": "unix"
-        },
+        "control-sockets": [
+            {
+                // Control socket type used by the Kea DHCPv4 server.
+                // Must be unix, http or https.
+                "socket-type": "unix",
+
+               // Location of the UNIX domain socket file the DHCPv4
+               // server uses to receive control commands from the
+               // local server administrator.
+               "socket-name": "kea4-ctrl-socket"
+            },
+            {
+                // Control socket type used by the Kea DHCPv4 server.
+                // Must be unix, http or https.
+                "socket-type": "https",
+
+                // Address of the HTTPS socket the Kea DHCPv4 server should
+                // listen for incoming queries.
+                "socket-address": "127.0.0.1",
+
+                // Port of the HTTPS socket the Kea DHCPv4 server
+                // should listen for incoming queries. If enabling HA
+                // and multi-threading, the 8000 port is used by the
+                // HA hook library http listener. When using HA hook
+                // library with multi-threading to function, make sure
+                // the port used by dedicated listener is different
+                // (e.g. 8001) than the one specified here.  Note the
+                // commands should still be sent to a control socket.
+                // The dedicated listener is specifically for HA
+                // updates only.
+                "socket-port": 8004,
+
+                // TLS trust anchor (Certificate Authority). This is a
+                // file name or a directory path. Make sense with other
+                // TLS parameters only for the https control socket type.
+                "trust-anchor": "my-ca",
+
+                // TLS server certificate file name.
+                "cert-file": "my-cert",
+
+                // TLS server private key file name.
+                "key-file": "my-key",
+
+                // TLS require client certificates flag. Default is
+                // true and means require client certificates. False
+                // means they are optional.
+                "cert-required": true,
+
+                // Extra HTTP headers to add in responses.
+                "http-headers":
+                [
+                    {
+                        // Optional user context.
+                        "user-context": { "comment": "HSTS header" },
+
+                        // Required HTTP header name.
+                        "name": "Strict-Transport-Security",
+
+                        // Required HTTP header value.
+                        "value": "max-age=31536000"
+                    }
+                ],
+
+                // Optional authentication.
+                "authentication": {
+
+                    // Required authentication type. The only
+                    // supported value is basic for the basic HTTP
+                    // authentication.
+                    "type": "basic",
+
+                    // An optional parameter is the basic HTTP
+                    // authentication realm.  Its default is
+                    // "kea-dhcpv4-server"
+                    "realm": "kea-dhcpv4-server",
+
+                    // This optional parameter can be used to specify a common
+                    // prefix for files handling client credentials.
+                    "directory": "/usr/local/share/kea/kea-creds",
+
+                    // This list specifies the user ids and passwords
+                    // to use for basic HTTP authentication. If empty
+                    // or not present any client is authorized.
+                    "clients": [
+                        // This specifies an authorized client.
+                        {
+                            // The user id must not be empty or
+                            // contain the ':' character. It is a
+                            // mandatory parameter.
+                            "user": "admin",
+
+                            // If password is not specified an empty
+                            // password is used.
+                            "password": "1234"
+                        },
+
+                        // This specifies a hidden client.
+                        {
+                            // The user id is the content of the
+                            // file /usr/local/share/kea/kea-creds/hiddenu.
+                            "user-file": "hiddenu",
+
+                            // The password is the content of the
+                            // file /usr/local/share/kea/kea-creds/hiddenp.
+                            "password-file": "hiddenp"
+                        },
+
+                        // This specifies a hidden client using a
+                        // secret in a file.
+                        {
+                            // The secret is the content of the file
+                            // /usr/local/share/kea/kea-creds/hiddens which must be in
+                            // the <user-id>:<password> format.
+                            "password-file": "hiddens"
+                        }
+                    ]
+                }
+            }
+        ],
 
         // Specifies a prefix to be prepended to the generated Client FQDN.
         // It may be specified at the global, shared-network, and subnet levels.
index 9fc96ff57090c9e0af1a2aced417dc1218778167..e070989d04af4297e782b013145b446173fcde50 100644 (file)
         },
 
         // Command control socket configuration parameters for the Kea DHCPv6 server.
-        "control-socket": {
-            // Location of the UNIX domain socket file the DHCPv4 server uses
-            // to receive control commands from the Kea Control Agent or the
-            // local server administrator.
-            "socket-name": "kea6-ctrl-socket",
-
-            // Control socket type used by the Kea DHCPv4 server. The 'unix'
-            // socket is currently the only supported type.
-            "socket-type": "unix"
-        },
+        "control-sockets": [
+            {
+                // Control socket type used by the Kea DHCPv6 server.
+                // Must be unix, http or https.
+                "socket-type": "unix",
+
+               // Location of the UNIX domain socket file the DHCPv6
+               // server uses to receive control commands from the
+               // local server administrator.
+               "socket-name": "kea6-ctrl-socket"
+            },
+            {
+                // Control socket type used by the Kea DHCPv6 server.
+                // Must be unix, http or https.
+                "socket-type": "https",
+
+                // Address of the HTTPS socket the Kea DHCPv6 server should
+                // listen for incoming queries.
+                "socket-address": "::1",
+
+                // Port of the HTTPS socket the Kea DHCPv6 server
+                // should listen for incoming queries. If enabling HA
+                // and multi-threading, the 8000 port is used by the
+                // HA hook library http listener. When using HA hook
+                // library with multi-threading to function, make sure
+                // the port used by dedicated listener is different
+                // (e.g. 8001) than the one specified here.  Note the
+                // commands should still be sent to a control socket.
+                // The dedicated listener is specifically for HA
+                // updates only.
+                "socket-port": 8006,
+
+                // TLS trust anchor (Certificate Authority). This is a
+                // file name or a directory path. Make sense with other
+                // TLS parameters only for the https control socket type.
+                "trust-anchor": "my-ca",
+
+                // TLS server certificate file name.
+                "cert-file": "my-cert",
+
+                // TLS server private key file name.
+                "key-file": "my-key",
+
+                // TLS require client certificates flag. Default is
+                // true and means require client certificates. False
+                // means they are optional.
+                "cert-required": true,
+
+                // Extra HTTP headers to add in responses.
+                "http-headers":
+                [
+                    {
+                        // Optional user context.
+                        "user-context": { "comment": "HSTS header" },
+
+                        // Required HTTP header name.
+                        "name": "Strict-Transport-Security",
+
+                        // Required HTTP header value.
+                        "value": "max-age=31536000"
+                    }
+                ],
+
+                // Optional authentication.
+                "authentication": {
+
+                    // Required authentication type. The only
+                    // supported value is basic for the basic HTTP
+                    // authentication.
+                    "type": "basic",
+
+                    // An optional parameter is the basic HTTP
+                    // authentication realm.  Its default is
+                    // "kea-dhcpv6-server"
+                    "realm": "kea-dhcpv6-server",
+
+                    // This optional parameter can be used to specify a common
+                    // prefix for files handling client credentials.
+                    "directory": "/usr/local/share/kea/kea-creds",
+
+                    // This list specifies the user ids and passwords
+                    // to use for basic HTTP authentication. If empty
+                    // or not present any client is authorized.
+                    "clients": [
+                        // This specifies an authorized client.
+                        {
+                            // The user id must not be empty or
+                            // contain the ':' character. It is a
+                            // mandatory parameter.
+                            "user": "admin",
+
+                            // If password is not specified an empty
+                            // password is used.
+                            "password": "1234"
+                        },
+
+                        // This specifies a hidden client.
+                        {
+                            // The user id is the content of the
+                            // file /usr/local/share/kea/kea-creds/hiddenu.
+                            "user-file": "hiddenu",
+
+                            // The password is the content of the
+                            // file /usr/local/share/kea/kea-creds/hiddenp.
+                            "password-file": "hiddenp"
+                        },
+
+                        // This specifies a hidden client using a
+                        // secret in a file.
+                        {
+                            // The secret is the content of the file
+                            // /usr/local/share/kea/kea-creds/hiddens which must be in
+                            // the <user-id>:<password> format.
+                            "password-file": "hiddens"
+                        }
+                    ]
+                }
+            }
+        ],
 
         // Specifies a prefix to be prepended to the generated Client FQDN.
         // It may be specified at the global, shared-network, and subnet levels.
index b4e19805d034cd314aaa1f60d4c4742266606d0e..254599d0a662ae98aad14206054359fcba25d81d 100644 (file)
@@ -785,6 +785,7 @@ TEST(ParserTest, mapEntries) {
     string sample_dir(CFG_EXAMPLES);
     sample_dir += "/";
     ElementPtr sample_json = Element::createList();
+    loadFile(sample_dir + "advanced.json", sample_json);
     loadFile(sample_dir + "all-keys.json", sample_json);
     loadFile(sample_dir + "reservations.json", sample_json);
     loadFile(sample_dir + "all-keys-netconf.json", sample_json);
index 7b0a13304c04d53a7d67fedfeaf2661ddf4a81b9..8d9e33481581fe1362d84f14ae9ae68d2aec0275 100644 (file)
@@ -382,11 +382,19 @@ AdaptorConfig::sanitizeEmptyListPools(ConstElementPtr pools) {
 
     for (size_t i = 0; i < pools->size(); ++i) {
         ElementPtr pool = pools->getNonConst(i);
-        ConstElementPtr require = pool->get("evaluate-additional-classes");
+        ConstElementPtr require = pool->get("require-client-classes");
+        if (require && require->empty()) {
+            pool->remove("require-client-classes");
+        }
+        require = pool->get("evaluate-additional-classes");
         if (require && require->empty()) {
             pool->remove("evaluate-additional-classes");
         }
-        ConstElementPtr classes = pool->get("client-classes");
+        ConstElementPtr classes = pool->get("client-class");
+        if (classes && classes->empty()) {
+            pool->remove("client-class");
+        }
+        classes = pool->get("client-classes");
         if (classes && classes->empty()) {
             pool->remove("client-classes");
         }
@@ -404,11 +412,19 @@ AdaptorConfig::sanitizeEmptyListSubnets(ConstElementPtr subnets) {
         ElementPtr subnet = subnets->getNonConst(i);
         sanitizeEmptyListPools(subnet->get("pools"));
         sanitizeEmptyListPools(subnet->get("pd-pools"));
-        ConstElementPtr require = subnet->get("evaluate-additional-classes");
+        ConstElementPtr require = subnet->get("require-client-classes");
+        if (require && require->empty()) {
+            subnet->remove("require-client-classes");
+        }
+        require = subnet->get("evaluate-additional-classes");
         if (require && require->empty()) {
             subnet->remove("evaluate-additional-classes");
         }
-        ConstElementPtr classes = subnet->get("client-classes");
+        ConstElementPtr classes = subnet->get("client-class");
+        if (classes && classes->empty()) {
+            subnet->remove("client-class");
+        }
+        classes = subnet->get("client-classes");
         if (classes && classes->empty()) {
             subnet->remove("client-classes");
         }
@@ -426,11 +442,19 @@ AdaptorConfig::sanitizeEmptyListSharedNetworks(ConstElementPtr networks,
     for (size_t i = 0; i < networks->size(); ++i) {
         ElementPtr network = networks->getNonConst(i);
         sanitizeEmptyListSubnets(network->get(subsel));
-        ConstElementPtr require = network->get("evaluate-additional-classes");
+        ConstElementPtr require = network->get("require-client-classes");
+        if (require && require->empty()) {
+            network->remove("require-client-classes");
+        }
+        require = network->get("evaluate-additional-classes");
         if (require && require->empty()) {
             network->remove("evaluate-additional-classes");
         }
-        ConstElementPtr classes = network->get("client-classes");
+        ConstElementPtr classes = network->get("client-class");
+        if (classes && classes->empty()) {
+            network->remove("client-class");
+        }
+        classes = network->get("client-classes");
         if (classes && classes->empty()) {
             network->remove("client-classes");
         }
index 5dc6935bef404847ebc9544a840a1924290052b2..f77807d75abbf4d7a758a53424c85e8d8bacf9e1 100644 (file)
@@ -195,7 +195,9 @@ protected:
     ///
     /// Remove empty lists in a pool list.
     /// removing:
+    ///  - require-client-classes
     ///  - evaluate-additional-classes
+    ///  - client-class
     ///  - client-classes
     ///
     /// @param pools The pool list.
@@ -205,7 +207,9 @@ protected:
     ///
     /// Remove empty lists in a subnet list.
     /// removing:
+    ///  - require-client-classes
     ///  - evaluate-additional-classes
+    ///  - client-class
     ///  - client-classes
     ///
     /// @param subnets The subnet list.
@@ -215,7 +219,9 @@ protected:
     ///
     /// Remove empty lists in a shared network list.
     /// removing:
+    ///  - require-client-classes
     ///  - evaluate-additional-classes
+    ///  - client-class
     ///  - client-classes
     ///
     /// @param networks The shared network list.
index bee75d2ee8d94f45b42c5a87ceb80be55e5c67d0..cf8a110b16b2174c76be87cbbdfd5306f0216599 100644 (file)
@@ -284,7 +284,7 @@ public:
             for (libyang::DataNode const& i : nodes) {
                 result->add((t.*f)(i));
             }
-            return result;
+            return (result);
         } catch (libyang::Error const& ex) {
             isc_throw(NetconfError, "getting item: " << ex.what());
         }
index 6023dda585d4d237ffa9ee33097a459a2a5a7fcf..4454d18ce01827cea9df71b6b2c03e42965ad4ba 100644 (file)
@@ -60,6 +60,7 @@ TranslatorClass::getClassKea(DataNode const& data_node) {
 
     checkAndGetLeaf(result, data_node, "max-valid-lifetime");
     checkAndGetLeaf(result, data_node, "min-valid-lifetime");
+    checkAndGetLeaf(result, data_node, "only-if-required");
     checkAndGetLeaf(result, data_node, "only-in-additional-list");
     checkAndGetLeaf(result, data_node, "template-test");
     checkAndGetLeaf(result, data_node, "test");
@@ -115,6 +116,7 @@ TranslatorClass::setClassKea(string const& xpath, ConstElementPtr elem) {
 
     checkAndSetLeaf(elem, xpath, "max-valid-lifetime", LeafBaseType::Uint32);
     checkAndSetLeaf(elem, xpath, "min-valid-lifetime", LeafBaseType::Uint32);
+    checkAndSetLeaf(elem, xpath, "only-if-required", LeafBaseType::Bool);
     checkAndSetLeaf(elem, xpath, "only-in-additional-list", LeafBaseType::Bool);
     checkAndSetLeaf(elem, xpath, "template-test", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "test", LeafBaseType::String);
index 49dfd8c693a19026c8e9a91ca497121338d9d25a..72310a23012f7661404f877c481f434604d4a62d 100644 (file)
@@ -20,6 +20,7 @@ namespace yang {
 /// {
 ///     "name": <name>,
 ///     "test": <test expression>,
+///     "only-if-required": <only if required flag>,
 ///     "only-in-additional-list": <only in additional list flag>,
 ///     "option-data": <option data list>,
 ///     (DHCPv4 only)
@@ -37,6 +38,7 @@ namespace yang {
 /// +--rw client-class* [name]
 ///    +--rw name                       string
 ///    +--rw test?                      string
+///    +--rw only-if-required?          boolean
 ///    +--rw only-in-additional-list?   boolean
 ///    +--rw option-def* [code space]
 ///    +--rw option-data* [code space]
index 85098559c208d2a3c9b695e712604cf4e4c49f5e..3f90f2fefaad456fe5d85855287dd03048feb669 100644 (file)
@@ -242,10 +242,15 @@ TranslatorConfig::getServerKeaDhcpCommon(DataNode const& data_node) {
                     return getConfigControlKea(node);
                 });
 
-    checkAndGet(result, data_node, "control-socket",
-                [&](DataNode const& node) -> ElementPtr const {
-                    return getControlSocket(node);
-                });
+    ConstElementPtr control_sockets = getControlSockets(data_node);
+    if (control_sockets && !control_sockets->empty()) {
+        result->set("control-sockets", control_sockets);
+    } else {
+        checkAndGet(result, data_node, "control-socket",
+                    [&](DataNode const& node) -> ElementPtr const {
+                        return getControlSocket(node);
+                    });
+    }
 
     checkAndGet(result, data_node, "dhcp-ddns",
                 [&](DataNode const& node) -> ElementPtr const {
@@ -569,9 +574,14 @@ TranslatorConfig::setServerKeaDhcpCommon(string const& xpath,
         }
     }
 
-    ConstElementPtr socket = elem->get("control-socket");
-    if (socket && !socket->empty()) {
-        setControlSocket(xpath + "/control-socket", socket);
+    ConstElementPtr control_sockets = elem->get("control-sockets");
+    if (control_sockets && !control_sockets->empty()) {
+        setControlSockets(xpath + "/control-sockets", control_sockets);
+    } else {
+        ConstElementPtr control_socket = elem->get("control-socket");
+        if (control_socket && !control_socket->empty()) {
+            setControlSocket(xpath + "/control-socket", control_socket);
+        }
     }
 
     ConstElementPtr ddns = elem->get("dhcp-ddns");
index 6eced22a7b63de5142ff8dad75b618076e8008a2..abb2ca4b266062897920bfc3183e57d8a4bc1a62 100644 (file)
@@ -93,6 +93,7 @@ namespace yang {
 /// +--rw expired-leases-processing
 /// +--rw dhcp4o6-port?                     uint16
 /// +--rw control-socket!
+/// +--rw control-sockets*
 /// +--rw hostname-char-set?                string
 /// +--rw hostname-char-replacement?        string
 /// +--rw dhcp-ddns
@@ -142,10 +143,10 @@ namespace yang {
 ///     {
 ///         "interfaces": [ "eth1" ]
 ///     },
-///         "control-socket": {
+///         "control-sockets": [ {
 ///             "socket-type": "unix",
 ///             "socket-name": "kea4-sock"
-///         },
+///         } ],
 ///     "subnet4":
 ///     [
 ///         {
@@ -179,10 +180,10 @@ namespace yang {
 ///   <interfaces-config>
 ///     <interfaces>eth1</interfaces>
 ///   </interfaces-config>
-///   <control-socket>
+///   <control-sockets>
 ///     <socket-name>kea4-sock</socket-name>
 ///     <socket-type>unix</socket-type>
-///   </control-socket>
+///   </control-sockets>
 /// </config>
 /// @endcode
 
@@ -219,7 +220,7 @@ namespace yang {
 ///     <expired-leases-processing>,
 ///     <server-id>,
 ///     <dhcp4o6-port>,
-///     <control-socket>,
+///     <control-sockets>,
 ///     <hostname-char-set": <hostname character set>,
 ///     <hostname-char-replacement": <hostname character replacement>,
 ///     <dhcp-ddns>,
@@ -265,6 +266,7 @@ namespace yang {
 /// +--rw server-id!
 /// +--rw dhcp4o6-port?                     uint16
 /// +--rw control-socket!
+/// +--rw control-sockets*
 /// +--rw hostname-char-set?                string
 /// +--rw hostname-char-replacement?        string
 /// +--rw dhcp-ddns
@@ -308,10 +310,10 @@ namespace yang {
 ///     {
 ///         "interfaces": [ "eth1" ]
 ///     },
-///         "control-socket": {
+///         "control-sockets": [ {
 ///             "socket-type": "unix",
 ///             "socket-name": "kea6-sock"
-///         },
+///         } ],
 ///     "subnet6":
 ///     [
 ///         {
@@ -344,10 +346,10 @@ namespace yang {
 ///   <interfaces-config>
 ///     <interfaces>eth1</interfaces>
 ///   </interfaces-config>
-///   <control-socket>
+///   <control-sockets>
 ///     <socket-name>kea6-sock</socket-name>
 ///     <socket-type>unix</socket-type>
-///   </control-socket>
+///   </control-sockets>
 /// </config>
 /// @endcode
 
index 2d44b2f56725a23416366d350cd45da090633b78..c64c81e93f64d810fd468e8aa6164718fcbe746f 100644 (file)
@@ -24,6 +24,24 @@ TranslatorControlSocket::TranslatorControlSocket(Session session,
     : Translator(session, model) {
 }
 
+ElementPtr
+TranslatorControlSocket::getControlSockets(DataNode const& data_node) {
+    try {
+        if ((model_ == KEA_DHCP4_SERVER) ||
+            (model_ == KEA_DHCP6_SERVER) ||
+            (model_ == KEA_DHCP_DDNS)) {
+            return (getControlSocketsKea(data_node));
+        } else if (model_ == KEA_CTRL_AGENT) {
+            return (getControlSocketKea(data_node));
+        }
+    } catch (Error const& ex) {
+        isc_throw(NetconfError,
+                  "getting control socket: " << ex.what());
+    }
+    isc_throw(NotImplemented,
+              "getControlSocket not implemented for the model: " << model_);
+}
+
 ElementPtr
 TranslatorControlSocket::getControlSocket(DataNode const& data_node) {
     try {
@@ -41,15 +59,68 @@ TranslatorControlSocket::getControlSocket(DataNode const& data_node) {
               "getControlSocket not implemented for the model: " << model_);
 }
 
+ElementPtr
+TranslatorControlSocket::getControlSocketsKea(DataNode const& data_node) {
+    return (getList(data_node, "control-sockets", *this, &TranslatorControlSocket::getControlSocketKea));
+}
+
 ElementPtr
 TranslatorControlSocket::getControlSocketKea(DataNode const& data_node) {
     ElementPtr result(Element::createMap());
-    getMandatoryLeaf(result, data_node, "socket-name");
     getMandatoryLeaf(result, data_node, "socket-type");
+    checkAndGetLeaf(result, data_node, "socket-name");
+    if (model_ != KEA_CTRL_AGENT) {
+        checkAndGetLeaf(result, data_node, "socket-address");
+        checkAndGetLeaf(result, data_node, "socket-port");
+        checkAndGetLeaf(result, data_node, "trust-anchor");
+        checkAndGetLeaf(result, data_node, "cert-file");
+        checkAndGetLeaf(result, data_node, "key-file");
+        checkAndGetLeaf(result, data_node, "cert-required");
+        checkAndGet(result, data_node, "authentication",
+                    [&](DataNode const& node) -> ElementPtr const {
+                        // If it exists, add to the existing compatibility map created in getServerKeaDhcpCommon.
+                        ConstElementPtr const_authentication(result->get("authentication"));
+                        ElementPtr authentication;
+                        if (const_authentication) {
+                            authentication = copy(const_authentication);
+                        } else {
+                            authentication = Element::createMap();
+                        }
+
+                        getMandatoryDivergingLeaf(authentication, node, "type", "auth-type");
+                        checkAndGetLeaf(authentication, node, "realm");
+                        checkAndGetLeaf(authentication, node, "directory");
+                        ConstElementPtr clients = getControlSocketAuthenticationClients(node);
+                        if (clients) {
+                            authentication->set("clients", clients);
+                        }
+                        return (authentication);
+                    });
+        ConstElementPtr headers = getControlSocketHttpHeaders(data_node);
+        if (headers && !headers->empty()) {
+            result->set("http-headers", headers);
+        }
+    }
     checkAndGetAndJsonifyLeaf(result, data_node, "user-context");
     return (result->empty() ? ElementPtr() : result);
 }
 
+ElementPtr
+TranslatorControlSocket::getControlSocketAuthenticationClients(DataNode const& data_node) {
+    return getList(data_node, "clients", *this,
+                   &TranslatorControlSocket::getControlSocketAuthenticationClient);
+}
+
+ElementPtr
+TranslatorControlSocket::getControlSocketAuthenticationClient(DataNode const& data_node) {
+    ElementPtr result = Element::createMap();
+    getMandatoryLeaf(result, data_node, "user");
+    getMandatoryLeaf(result, data_node, "password");
+    getMandatoryLeaf(result, data_node, "user-file");
+    getMandatoryLeaf(result, data_node, "password-file");
+    return (result->empty() ? ElementPtr() : result);
+}
+
 ElementPtr
 TranslatorControlSocket::getControlSocketFromAbsoluteXpath(string const& xpath) {
     try {
@@ -59,6 +130,28 @@ TranslatorControlSocket::getControlSocketFromAbsoluteXpath(string const& xpath)
     }
 }
 
+void
+TranslatorControlSocket::setControlSockets(string const& xpath,
+                                           ConstElementPtr elem) {
+    try {
+        if ((model_ == KEA_DHCP4_SERVER) ||
+            (model_ == KEA_DHCP6_SERVER) ||
+            (model_ == KEA_DHCP_DDNS)) {
+            setControlSocketsKea(xpath, elem);
+        } else if (model_ == KEA_CTRL_AGENT) {
+            setControlSocketKea(xpath, elem, false);
+        } else {
+          isc_throw(NotImplemented,
+                    "setControlSocket not implemented for the model: "
+                    << model_);
+        }
+    } catch (Error const& ex) {
+        isc_throw(NetconfError,
+                  "setting control socket '" << elem->str()
+                  << "' at '" << xpath << "': " << ex.what());
+    }
+}
+
 void
 TranslatorControlSocket::setControlSocket(string const& xpath,
                                           ConstElementPtr elem) {
@@ -67,7 +160,7 @@ TranslatorControlSocket::setControlSocket(string const& xpath,
             (model_ == KEA_DHCP6_SERVER) ||
             (model_ == KEA_DHCP_DDNS) ||
             (model_ == KEA_CTRL_AGENT)) {
-            setControlSocketKea(xpath, elem);
+            setControlSocketKea(xpath, elem, true);
         } else {
           isc_throw(NotImplemented,
                     "setControlSocket not implemented for the model: "
@@ -80,18 +173,141 @@ TranslatorControlSocket::setControlSocket(string const& xpath,
     }
 }
 
+void
+TranslatorControlSocket::setControlSocketsKea(string const& xpath,
+                                              ConstElementPtr elem) {
+    if (!elem) {
+        deleteItem(xpath);
+        return;
+    }
+    for (size_t i = 0; i < elem->size(); ++i) {
+        ElementPtr control_socket = elem->getNonConst(i);
+        if (!control_socket->contains("socket-type")) {
+            isc_throw(BadValue, "control-socket without socket-type: " << control_socket->str());
+        }
+        string type = control_socket->get("socket-type")->stringValue();
+        ostringstream key;
+        key << xpath << "[socket-type='" << type << "']";
+        setControlSocketKea(key.str(), control_socket, true);
+    }
+}
+
 void
 TranslatorControlSocket::setControlSocketKea(string const& xpath,
-                                             ConstElementPtr elem) {
+                                             ConstElementPtr elem,
+                                             bool skip) {
     if (!elem) {
         deleteItem(xpath);
         return;
     }
 
-    setMandatoryLeaf(elem, xpath, "socket-name", LeafBaseType::String);
-    setMandatoryLeaf(elem, xpath, "socket-type", LeafBaseType::Enum);
+    checkAndSetLeaf(elem, xpath, "socket-name", LeafBaseType::String);
+
+    if (model_ == KEA_CTRL_AGENT) {
+        setMandatoryLeaf(elem, xpath, "socket-type", LeafBaseType::Enum);
+    } else {
+        checkAndSetLeaf(elem, xpath, "socket-address", LeafBaseType::String);
+        checkAndSetLeaf(elem, xpath, "socket-port", LeafBaseType::Uint32);
+        checkAndSetLeaf(elem, xpath, "trust-anchor", LeafBaseType::String);
+        checkAndSetLeaf(elem, xpath, "cert-file", LeafBaseType::String);
+        checkAndSetLeaf(elem, xpath, "key-file", LeafBaseType::String);
+        checkAndSetLeaf(elem, xpath, "cert-required", LeafBaseType::Bool);
+        ConstElementPtr authentication = elem->get("authentication");
+        if (authentication && !authentication->empty()) {
+            setMandatoryDivergingLeaf(authentication, xpath , "type", "auth-type", LeafBaseType::String);
+            checkAndSetLeaf(authentication, xpath + "/authentication", "realm", LeafBaseType::String);
+            checkAndSetLeaf(authentication, xpath + "/authentication", "directory", LeafBaseType::String);
+            ConstElementPtr clients = authentication->get("clients");
+            setControlSocketAuthenticationClients(xpath + "/authentication/clients", clients, skip);
+        }
+        ConstElementPtr http_headers = elem->get("http-headers");
+        if (http_headers && !http_headers->empty()) {
+            for (size_t i = 0; i < http_headers->size(); ++i) {
+                ElementPtr header = elem->getNonConst(i);
+                // setHeader
+            }
+        }
+        if (!skip) {
+            setMandatoryLeaf(elem, xpath, "socket-type", LeafBaseType::Enum);
+        }
+    }
     checkAndSetUserContext(elem, xpath);
 }
 
+void
+TranslatorControlSocket::setControlSocketAuthenticationClients(string const& xpath,
+                                                               ConstElementPtr elem,
+                                                               bool skip) {
+    if (!elem) {
+        deleteItem(xpath);
+        return;
+    }
+    for (size_t i = 0; i < elem->size(); ++i) {
+        ElementPtr client = elem->getNonConst(i);
+        ostringstream key;
+        auto user = client->get("user");
+        string user_str;
+        if (user) {
+            user_str = user->stringValue();
+        }
+        auto password = client->get("password");
+        string password_str;
+        if (password) {
+            password_str = password->stringValue();
+        }
+        auto user_file = client->get("user-file");
+        string user_file_str;
+        if (user_file) {
+            user_file_str = user_file->stringValue();
+        }
+        auto password_file = client->get("password-file");
+        string password_file_str;
+        if (password_file) {
+            password_file_str = password_file->stringValue();
+        }
+        key << xpath << "[user='" << user_str << "'][password=']" << password_str
+                     << "'][user-file='" << user_file_str << "'][password-file='"
+                     << password_file_str << "']";
+        setControlSocketAuthenticationClient(key.str(), client, skip);
+    }
+}
+
+void
+TranslatorControlSocket::setControlSocketAuthenticationClient(string const& xpath,
+                                                              ConstElementPtr /* elem */,
+                                                              bool /* skip */) {
+    setItem(xpath, ElementPtr(), LeafBaseType::Unknown);
+}
+
+void
+TranslatorControlSocket::setControlSocketHttpHeaders(const std::string& xpath,
+                            isc::data::ConstElementPtr elem,
+                            bool skip) {
+    if (!elem) {
+        deleteItem(xpath);
+        return;
+    }
+    for (size_t i = 0; i < elem->size(); ++i) {
+        ElementPtr header = elem->getNonConst(i);
+        ostringstream key;
+        if (!header->contains("name")) {
+            isc_throw(BadValue, "http header without name: " << header->str());
+        }
+        key << xpath << "[name='" << header->stringValue() << "']";
+        setControlSocketHttpHeader(key.str(), header, skip);
+    }
+}
+
+void
+TranslatorControlSocket::setControlSocketHttpHeader(const std::string& xpath,
+                                                    isc::data::ConstElementPtr elem,
+                                                    bool skip) {
+    checkAndSetLeaf(elem, xpath, "value", LeafBaseType::String);
+    checkAndSetUserContext(elem, xpath);
+    if (!skip) {
+        setMandatoryLeaf(elem, xpath, "name", LeafBaseType::Enum);
+    }
+}
+
 }  // namespace yang
 }  // namespace isc
index b8881d6a29e07e6deb840648b7f4309bc37e6640..b9cc12c3b1a977c0ea374d5c51beff8163d54efb 100644 (file)
@@ -16,17 +16,18 @@ namespace yang {
 ///
 /// JSON syntax for all Kea servers with command channel is:
 /// @code
-/// "control-socket": {
+/// "control-sockets": [ {
 ///     "socket-type": "<socket type>",
 ///     "socket-name": "<socket name>",
 ///     "user-context": { <json map> },
 ///     "comment": "<comment>"
-/// }
+/// } ]
 /// @endcode
 ///
 /// YANG syntax is:
 /// @code
 /// +--rw control-socket!
+/// +--rw control-sockets*
 /// +--rw socket-name     string
 /// +--rw socket-type     enumeration
 /// +--rw user-context?   user-context
@@ -77,6 +78,15 @@ public:
     /// @brief Destructor.
     virtual ~TranslatorControlSocket() = default;
 
+    /// @brief Translate a control socket from YANG to JSON.
+    ///
+    /// @param data_node the YANG node representing the control sockets
+    ///
+    /// @return the JSON representation of the control socket
+    ///
+    /// @throw NetconfError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSockets(libyang::DataNode const& data_node);
+
     /// @brief Translate a control socket from YANG to JSON.
     ///
     /// @param data_node the YANG node representing the control socket
@@ -100,6 +110,13 @@ public:
     /// @throw NetconfError when sysrepo raises an error.
     isc::data::ElementPtr getControlSocketFromAbsoluteXpath(std::string const& xpath);
 
+    /// @brief Translate and set control sockets from JSON to YANG.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    void setControlSockets(const std::string& xpath,
+                           isc::data::ConstElementPtr elem);
+
     /// @brief Translate and set control socket from JSON to YANG.
     ///
     /// @param xpath The xpath of the control socket.
@@ -108,6 +125,13 @@ public:
                           isc::data::ConstElementPtr elem);
 
 protected:
+    /// @brief getControlSocket JSON for kea models.
+    ///
+    /// @param data_node the YANG node representing the control socket
+    /// @return JSON representation of the control socket.
+    /// @throw NetconfError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSocketsKea(libyang::DataNode const& data_node);
+
     /// @brief getControlSocket JSON for kea models.
     ///
     /// @param data_node the YANG node representing the control socket
@@ -115,6 +139,46 @@ protected:
     /// @throw NetconfError when sysrepo raises an error.
     isc::data::ElementPtr getControlSocketKea(libyang::DataNode const& data_node);
 
+    /// @brief getControlSocketsAuthenticationClients JSON for kea models.
+    ///
+    /// @param data_node the YANG node representing the control socket
+    /// @return JSON representation of the control socket.
+    /// @throw NetconfError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSocketAuthenticationClients(libyang::DataNode const& data_node);
+
+    /// @brief getControlSocketsAuthenticationClients JSON for kea models.
+    ///
+    /// @param data_node the YANG node representing the control socket
+    /// @return JSON representation of the control socket.
+    /// @throw NetconfError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSocketAuthenticationClient(libyang::DataNode const& data_node);
+
+    /// @brief getControlSocketsAuthenticationClients JSON for kea models.
+    ///
+    /// @param data_node the YANG node representing the control socket
+    /// @return JSON representation of the control socket.
+    /// @throw NetconfError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSocketHttpHeaders(libyang::DataNode const& data_node);
+
+    /// @brief getControlSocketsAuthenticationClients JSON for kea models.
+    ///
+    /// @param data_node the YANG node representing the control socket
+    /// @return JSON representation of the control socket.
+    /// @throw NetconfError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSocketHttpHeader(libyang::DataNode const& data_node);
+
+    /// @brief setControlSocket for kea models.
+    ///
+    /// Null elem argument removes the container.
+    /// Required parameters passed in elem are: socket-name, socket-type.
+    /// Optional parameters are: user-context.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    /// @throw BadValue on control socket without socket type or name.
+    void setControlSocketsKea(const std::string& xpath,
+                              isc::data::ConstElementPtr elem);
+
     /// @brief setControlSocket for kea models.
     ///
     /// Null elem argument removes the container.
@@ -123,9 +187,67 @@ protected:
     ///
     /// @param xpath The xpath of the control socket.
     /// @param elem The JSON element.
+    /// @param skip The skip type field flag.
     /// @throw BadValue on control socket without socket type or name.
     void setControlSocketKea(const std::string& xpath,
-                             isc::data::ConstElementPtr elem);
+                             isc::data::ConstElementPtr elem,
+                             bool skip);
+
+    /// @brief setControlSocketAuthenticationClients for kea models.
+    ///
+    /// Null elem argument removes the container.
+    /// Required parameters passed in elem are: socket-name, socket-type.
+    /// Optional parameters are: user-context.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    /// @param skip The skip type field flag.
+    /// @throw BadValue on control socket without socket type or name.
+    void setControlSocketAuthenticationClients(const std::string& xpath,
+                                               isc::data::ConstElementPtr elem,
+                                               bool skip);
+
+    /// @brief setControlSocketAuthenticationClient for kea models.
+    ///
+    /// Null elem argument removes the container.
+    /// Required parameters passed in elem are: socket-name, socket-type.
+    /// Optional parameters are: user-context.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    /// @param skip The skip type field flag.
+    /// @throw BadValue on control socket without socket type or name.
+    void setControlSocketAuthenticationClient(const std::string& xpath,
+                                              isc::data::ConstElementPtr elem,
+                                              bool skip);
+
+    /// @brief setControlSocketHttpHeaders for kea models.
+    ///
+    /// Null elem argument removes the container.
+    /// Required parameters passed in elem are: socket-name, socket-type.
+    /// Optional parameters are: user-context.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    /// @param skip The skip type field flag.
+    /// @throw BadValue on control socket without socket type or name.
+    void setControlSocketHttpHeaders(const std::string& xpath,
+                                     isc::data::ConstElementPtr elem,
+                                     bool skip);
+
+    /// @brief setControlSocketHttpHeader for kea models.
+    ///
+    /// Null elem argument removes the container.
+    /// Required parameters passed in elem are: socket-name, socket-type.
+    /// Optional parameters are: user-context.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    /// @param skip The skip type field flag.
+    /// @throw BadValue on control socket without socket type or name.
+    void setControlSocketHttpHeader(const std::string& xpath,
+                                    isc::data::ConstElementPtr elem,
+                                    bool skip);
 };  // TranslatorControlSocket
 
 }  // namespace yang
index 7265b9b80eef5257ef35714e309372fde0db52f5..1147b6830484e83d351f9c1ac8ecfe8c17376448 100644 (file)
@@ -27,9 +27,7 @@ ElementPtr
 TranslatorLogger::getLogger(DataNode const& data_node) {
     try {
         if ((model_ == KEA_DHCP4_SERVER) ||
-            (model_ == KEA_DHCP6_SERVER) ||
-            (model_ == KEA_DHCP_DDNS) ||
-            (model_ == KEA_CTRL_AGENT)) {
+            (model_ == KEA_DHCP6_SERVER)) {
             return (getLoggerKea(data_node));
         }
     } catch (Error const& ex) {
@@ -83,9 +81,7 @@ void
 TranslatorLogger::setLogger(string const& xpath, ConstElementPtr elem) {
     try {
         if ((model_ == KEA_DHCP4_SERVER) ||
-            (model_ == KEA_DHCP6_SERVER) ||
-            (model_ == KEA_DHCP_DDNS) ||
-            (model_ == KEA_CTRL_AGENT)) {
+            (model_ == KEA_DHCP6_SERVER)) {
             setLoggerKea(xpath, elem);
         } else {
             isc_throw(NotImplemented,
@@ -151,9 +147,7 @@ ConstElementPtr
 TranslatorLoggers::getLoggers(DataNode const& data_node) {
     try {
         if ((model_ == KEA_DHCP4_SERVER) ||
-            (model_ == KEA_DHCP6_SERVER) ||
-            (model_ == KEA_DHCP_DDNS) ||
-            (model_ == KEA_CTRL_AGENT)) {
+            (model_ == KEA_DHCP6_SERVER)) {
             return (getLoggersKea(data_node));
         }
     } catch (Error const& ex) {
@@ -183,9 +177,7 @@ void
 TranslatorLoggers::setLoggers(string const& xpath, ConstElementPtr elem) {
     try {
         if ((model_ == KEA_DHCP4_SERVER) ||
-            (model_ == KEA_DHCP6_SERVER) ||
-            (model_ == KEA_DHCP_DDNS) ||
-            (model_ == KEA_CTRL_AGENT)) {
+            (model_ == KEA_DHCP6_SERVER)) {
             setLoggersKea(xpath, elem);
         } else {
             isc_throw(NotImplemented,
index 97a1d2a94ce22d17c6ea6298aa8acaf6cec934bd..a407a49918dd9a2cc41085f574672de905d76941 100644 (file)
@@ -78,7 +78,7 @@ TranslatorPdPool::getPdPoolIetf6(DataNode const& data_node) {
     getMandatoryDivergingLeaf(result, data_node, "prefix-len", "prefix-length");
 
     checkAndGetLeaf(result, data_node, "preferred-lifetime");
-    checkAndGetLeaf(result, data_node, "client-classes");
+    checkAndGetLeaf(result, data_node, "client-class");
     checkAndGetLeaf(result, data_node, "valid-lifetime");
 
     checkAndGetDivergingLeaf(result, data_node, "rebind-timer", "rebind-time");
@@ -162,12 +162,12 @@ TranslatorPdPool::getPdPoolKea(DataNode const& data_node) {
     checkAndGetLeaf(result, data_node, "ddns-conflict-resolution-mode");
     checkAndGetLeaf(result, data_node, "hostname-char-replacement");
     checkAndGetLeaf(result, data_node, "hostname-char-set");
+    checkAndGetLeaf(result, data_node, "client-class");
     checkAndGetLeaf(result, data_node, "client-classes");
     checkAndGetLeaf(result, data_node, "delegated-len");
+    checkAndGetLeaf(result, data_node, "require-client-classes");
     checkAndGetLeaf(result, data_node, "evaluate-additional-classes");
-
     checkAndGetLeaf(result, data_node, "pool-id");
-
     checkAndGetAndJsonifyLeaf(result, data_node, "user-context");
 
     ConstElementPtr options = getOptionDataList(data_node);
@@ -210,7 +210,7 @@ TranslatorPdPool::setPdPoolIetf6(string const& xpath, ConstElementPtr elem) {
     setItem(xpath + "/prefix", Element::create(prefix.str()), LeafBaseType::String);
     setItem(xpath + "/prefix-length", length, LeafBaseType::Uint8);
 
-    checkAndSetLeafList(elem, xpath, "client-classes", LeafBaseType::String);
+    checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "preferred-lifetime", LeafBaseType::Uint32);
     checkAndSetLeaf(elem, xpath, "valid-lifetime", LeafBaseType::Uint32);
 
@@ -230,8 +230,8 @@ TranslatorPdPool::setPdPoolKea(string const& xpath, ConstElementPtr elem) {
     // Keys are set by setting the list itself.
     setItem(xpath, ElementPtr(), LeafBaseType::Unknown);
 
+    checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "delegated-len", LeafBaseType::Uint8);
-
     checkAndSetLeaf(elem, xpath, "ddns-generated-prefix", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "ddns-override-client-update", LeafBaseType::Bool);
     checkAndSetLeaf(elem, xpath, "ddns-override-no-update", LeafBaseType::Bool);
@@ -248,10 +248,9 @@ TranslatorPdPool::setPdPoolKea(string const& xpath, ConstElementPtr elem) {
     checkAndSetLeaf(elem, xpath, "hostname-char-replacement", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "hostname-char-set", LeafBaseType::String);
     checkAndSetLeafList(elem, xpath, "client-classes", LeafBaseType::String);
+    checkAndSetLeafList(elem, xpath, "require-client-classes", LeafBaseType::String);
     checkAndSetLeafList(elem, xpath, "evaluate-additional-classes", LeafBaseType::String);
-
     checkAndSetLeaf(elem, xpath, "pool-id", LeafBaseType::Dec64);
-
     checkAndSetUserContext(elem, xpath);
 
     ConstElementPtr xprefix = elem->get("excluded-prefix");
index 33f8df3a36547c69c38eb527d556dcdd3b0cfc35..6b9b7f1a4bf12c1185f81376837308c44ce2ed7d 100644 (file)
@@ -23,7 +23,9 @@ namespace yang {
 ///     "excluded-prefix": <excluded prefix>,
 ///     "excluded-prefix-len": <excluded prefix length>,
 ///     "option-data": [ <list of option data> ],
+///     "client-class": "<guard class name>",
 ///     "client-classes": [ <list of guard class names> ],
+///     "require-client-classes": [ <list of required class names> ],
 ///     "evaluate-additional-classes": [ <list of evaluate additional class names> ],
 ///     "user-context": { <json map> },
 ///     "comment": "<comment>"
@@ -40,6 +42,7 @@ namespace yang {
 ///  +--rw rebind-time                 yang:timeticks
 ///  +--rw preferred-lifetime          yang:timeticks
 ///  +--rw rapid-commit?               boolean
+///  +--rw client-class?               string
 ///  +--rw client-classes*             string
 ///  +--rw max-pd-space-utilization?   threshold
 ///  +--rw option-set-id?
@@ -52,7 +55,9 @@ namespace yang {
 ///    +--rw prefix                         inet:ipv6-prefix
 ///    +--rw delegated-len?                 uint8
 ///    +--rw option-data* [code space]
+///    +--rw client-class?                  string
 ///    +--rw client-classes*                string
+///    +--rw require-client-classes*        string
 ///    +--rw evaluate-additional-classes*   string
 ///    +--rw excluded-prefix?               inet:ipv6-prefix
 ///    +--rw user-context?                  user-context
index 6145c5b02a5efe54c9bddf55eaedce8bcd73b4ee..62327ab6f5a9975a061968525c9cfc21c08ef79b 100644 (file)
@@ -118,8 +118,9 @@ TranslatorPool::getPoolKea(DataNode const& data_node) {
     checkAndGetLeaf(result, data_node, "ddns-conflict-resolution-mode");
     checkAndGetLeaf(result, data_node, "hostname-char-replacement");
     checkAndGetLeaf(result, data_node, "hostname-char-set");
-
+    checkAndGetLeaf(result, data_node, "client-class");
     checkAndGetLeaf(result, data_node, "client-classes");
+    checkAndGetLeaf(result, data_node, "require-client-classes");
     checkAndGetLeaf(result, data_node, "evaluate-additional-classes");
 
     checkAndGetLeaf(result, data_node, "pool-id");
@@ -220,7 +221,9 @@ TranslatorPool::setPoolKea(string const& xpath, ConstElementPtr elem) {
     checkAndSetLeaf(elem, xpath, "ddns-conflict-resolution-mode", LeafBaseType::Enum);
     checkAndSetLeaf(elem, xpath, "hostname-char-replacement", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "hostname-char-set", LeafBaseType::String);
+    checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
     checkAndSetLeafList(elem, xpath, "client-classes", LeafBaseType::String);
+    checkAndSetLeafList(elem, xpath, "require-client-classes", LeafBaseType::String);
     checkAndSetLeafList(elem, xpath, "evaluate-additional-classes", LeafBaseType::String);
 
     checkAndSetLeaf(elem, xpath, "pool-id", LeafBaseType::Dec64);
index de200c0d9e46c18e8ae802712f987ee19e0a3053..4dd5f26cbb3c8605ed15aeaa8dd6d43c9075ce13 100644 (file)
@@ -21,7 +21,9 @@ namespace yang {
 /// {
 ///     "pool": "<pool prefix or start - end addresses>",
 ///     "option-data": [ <list of option data> ],
+///     "client-class": "<guard class name>",
 ///     "client-classes": [ <list of guard class names> ],
+///     "require-client-classes": [ <list of required class names> ],
 ///     "evaluate-additional-classes": [ <list of evaluate additional class names> ],
 ///     "user-context": { <json map> },
 ///     "comment": "<comment>"
@@ -39,6 +41,7 @@ namespace yang {
 ///  +--rw rebind-time           yang:timeticks
 ///  +--rw preferred-lifetime    yang:timeticks
 ///  +--rw rapid-commit?         boolean
+///  +--rw client-class?         string
 ///  +--rw client-classes*       string
 ///  +--rw max-address-count     threshold
 ///  +--rw option-set-id
@@ -53,7 +56,9 @@ namespace yang {
 ///    +--rw start-address                  inet:ipv[46]-address
 ///    +--rw end-address                    inet:ipv[46]-address
 ///    +--rw option-data* [code space]
+///    +--rw client-class?                  string
 ///    +--rw client-classes*                string
+///    +--rw require-client-classes*        string
 ///    +--rw evaluate-additional-classes*   string
 ///    +--rw user-context?                  user-context
 /// @endcode
index c1bfd7874422bac04a00c9756856a63af720056f..272bceb7c373c0d8caae1fa18b2c9c57da017db5 100644 (file)
@@ -71,6 +71,7 @@ TranslatorSharedNetwork::getSharedNetworkKea(DataNode const& data_node,
     checkAndGetLeaf(result, data_node, "cache-max-age");
     checkAndGetLeaf(result, data_node, "cache-threshold");
     checkAndGetLeaf(result, data_node, "calculate-tee-times");
+    checkAndGetLeaf(result, data_node, "client-class");
     checkAndGetLeaf(result, data_node, "client-classes");
     checkAndGetLeaf(result, data_node, "ddns-generated-prefix");
     checkAndGetLeaf(result, data_node, "ddns-override-client-update");
@@ -92,6 +93,7 @@ TranslatorSharedNetwork::getSharedNetworkKea(DataNode const& data_node,
     checkAndGetLeaf(result, data_node, "min-valid-lifetime");
     checkAndGetLeaf(result, data_node, "rebind-timer");
     checkAndGetLeaf(result, data_node, "renew-timer");
+    checkAndGetLeaf(result, data_node, "require-client-classes");
     checkAndGetLeaf(result, data_node, "evaluate-additional-classes");
     checkAndGetLeaf(result, data_node, "reservations-global");
     checkAndGetLeaf(result, data_node, "reservations-in-subnet");
@@ -173,6 +175,7 @@ TranslatorSharedNetwork::setSharedNetworkKea(string const& xpath,
     checkAndSetLeaf(elem, xpath, "cache-max-age", LeafBaseType::Uint32);
     checkAndSetLeaf(elem, xpath, "cache-threshold", LeafBaseType::Dec64);
     checkAndSetLeaf(elem, xpath, "calculate-tee-times", LeafBaseType::Bool);
+    checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "ddns-generated-prefix", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "ddns-override-client-update", LeafBaseType::Bool);
     checkAndSetLeaf(elem, xpath, "ddns-override-no-update", LeafBaseType::Bool);
@@ -200,8 +203,8 @@ TranslatorSharedNetwork::setSharedNetworkKea(string const& xpath,
     checkAndSetLeaf(elem, xpath, "t1-percent", LeafBaseType::Dec64);
     checkAndSetLeaf(elem, xpath, "t2-percent", LeafBaseType::Dec64);
     checkAndSetLeaf(elem, xpath, "valid-lifetime", LeafBaseType::Uint32);
-
     checkAndSetLeafList(elem, xpath, "client-classes", LeafBaseType::String);
+    checkAndSetLeafList(elem, xpath, "require-client-classes", LeafBaseType::String);
     checkAndSetLeafList(elem, xpath, "evaluate-additional-classes", LeafBaseType::String);
 
     checkAndSetUserContext(elem, xpath);
index 96da42f02c73917bd580a0ba01cd5fb18271f8d3..fe7a346459a20dc8b6055f392d53159ed5af67a4 100644 (file)
@@ -30,7 +30,9 @@ namespace yang {
 ///     "t2-percent": <T2 percent>,
 ///     "option-data": [ <list of option data> ],
 ///     "interface": "<interface>",
+///     "client-class": "<guard class name>",
 ///     "client-classes": [ <list of guard class names> ],
+///     "require-client-classes": [ <list of required class names> ],
 ///     "evaluate-additional-classes": [ <list of evaluate additional class names> ],
 ///     "relay": <relay ip address(es)>,
 ///     "match-client-id": <match client id flag>,
@@ -63,7 +65,9 @@ namespace yang {
 ///     "interface": "<interface>",
 ///     "interface-id": "<interface id>",
 ///     "rapid-commit": <rapid commit flag>,
+///     "client-class": "<guard class name>",
 ///     "client-classes": [ <list of guard class names> ],
+///     "require-client-classes": [ <list of required class names> ],
 ///     "evaluate-additional-classes": [ <list of evaluate additional class names> ],
 ///     "relay": <relay ip address(es)>,
 ///     "user-context": { <json map> },
@@ -79,7 +83,9 @@ namespace yang {
 ///    +--rw renew-timer?                    uint32
 ///    +--rw rebind-timer?                   uint32
 ///    +--rw option-data* [code space]
+///    +--rw client-class?                   string
 ///    +--rw client-classes*                 string
+///    +--rw require-client-classes*         string
 ///    +--rw evaluate-additional-classes*    string
 ///    +--rw valid-lifetime?                 uint32
 ///    +--rw min-valid-lifetime?             uint32
index be9b69dfe2041ac2eb3e4cbca67604ccc6ad7c25..f22ebbf8abc01862a4c02774ebeb23bc1f8e1514 100644 (file)
@@ -104,6 +104,7 @@ TranslatorSubnet::getSubnetKea(DataNode const& data_node) {
     checkAndGetLeaf(result, data_node, "cache-max-age");
     checkAndGetLeaf(result, data_node, "cache-threshold");
     checkAndGetLeaf(result, data_node, "calculate-tee-times");
+    checkAndGetLeaf(result, data_node, "client-class");
     checkAndGetLeaf(result, data_node, "client-classes");
     checkAndGetLeaf(result, data_node, "ddns-generated-prefix");
     checkAndGetLeaf(result, data_node, "ddns-override-client-update");
@@ -125,6 +126,7 @@ TranslatorSubnet::getSubnetKea(DataNode const& data_node) {
     checkAndGetLeaf(result, data_node, "min-valid-lifetime");
     checkAndGetLeaf(result, data_node, "rebind-timer");
     checkAndGetLeaf(result, data_node, "renew-timer");
+    checkAndGetLeaf(result, data_node, "require-client-classes");
     checkAndGetLeaf(result, data_node, "evaluate-additional-classes");
     checkAndGetLeaf(result, data_node, "reservations-global");
     checkAndGetLeaf(result, data_node, "reservations-in-subnet");
@@ -259,6 +261,7 @@ TranslatorSubnet::setSubnetKea(string const& xpath, ConstElementPtr elem) {
     checkAndSetLeaf(elem, xpath, "cache-max-age", LeafBaseType::Uint32);
     checkAndSetLeaf(elem, xpath, "cache-threshold", LeafBaseType::Dec64);
     checkAndSetLeaf(elem, xpath, "calculate-tee-times", LeafBaseType::Bool);
+    checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "ddns-generated-prefix", LeafBaseType::String);
     checkAndSetLeaf(elem, xpath, "ddns-override-client-update", LeafBaseType::Bool);
     checkAndSetLeaf(elem, xpath, "ddns-override-no-update", LeafBaseType::Bool);
@@ -286,8 +289,8 @@ TranslatorSubnet::setSubnetKea(string const& xpath, ConstElementPtr elem) {
     checkAndSetLeaf(elem, xpath, "t1-percent", LeafBaseType::Dec64);
     checkAndSetLeaf(elem, xpath, "t2-percent", LeafBaseType::Dec64);
     checkAndSetLeaf(elem, xpath, "valid-lifetime", LeafBaseType::Uint32);
-
     checkAndSetLeafList(elem, xpath, "client-classes", LeafBaseType::String);
+    checkAndSetLeafList(elem, xpath, "require-client-classes", LeafBaseType::String);
     checkAndSetLeafList(elem, xpath, "evaluate-additional-classes", LeafBaseType::String);
 
     ConstElementPtr options = elem->get("option-data");
index cadbccd1399d708f452dcb0c5bb58559118cd325..7db470d4a38d9d2833a8c628153a17a80dc080e2 100644 (file)
@@ -33,7 +33,9 @@ namespace yang {
 ///     "subnet": "<subnet prefix>",
 ///     "interface": "<interface>",
 ///     "id": <id>,
+///     "client-class": "<guard class name>",
 ///     "client-classes": [ <list of guard class names> ],
+///     "require-client-classes": [ <list of required class names> ],
 ///     "evaluate-additional-classes": [ <list of evaluate additional class names> ],
 ///     "reservations": [ <list of host reservations> ],
 ///     "relay": <relay ip address(es)>,
@@ -72,7 +74,9 @@ namespace yang {
 ///     "interface-id": "<interface id>",
 ///     "id": <id>,
 ///     "rapid-commit": <rapid commit flag>,
+///     "client-class": "<guard class name>",
 ///     "client-classes": [ <list of guard class names> ],
+///     "require-client-classes": [ <list of required class names> ],
 ///     "evaluate-additional-classes": [ <list of evaluate additional class names> ],
 ///     "reservations": [ <list of host reservations> ],
 ///     "relay": <relay ip address(es)>,
@@ -95,60 +99,62 @@ namespace yang {
 ///
 /// YANG syntax for kea-dhcp[46]-server is with id as the key:
 /// @code
-///  +--rw subnet[46]* [id]
-///     +--rw valid-lifetime?                 uint32
-///     +--rw min-valid-lifetime?             uint32
-///     +--rw max-valid-lifetime?             uint32
-///     +--rw renew-timer?                    uint32
-///     +--rw rebind-timer?                   uint32
-///     +--rw calculate-tee-times?            boolean
-///     +--rw t1-percent?                     decimal64
-///     +--rw t2-percent?                     decimal64
-///     +--rw option-data* [code space]
-///     +--rw pool* [start-address end-address]
-///     +--rw subnet                          inet:ipv4-prefix
-///     +--rw interface?                      string
-///     +--rw id                              uint32
-///     +--rw client-classes*                 string
-///     +--rw evaluate-additional-classes*    string
-///     +--rw host* [identifier-type identifier]
-///     +--rw relay
-///     +--rw cache-max-age?                  uint32
-///     +--rw cache-threshold?                decimal64
-///     +--rw ddns-generated-prefix?          string
-///     +--rw ddns-override-client-update?    boolean
-///     +--rw ddns-override-no-update?        boolean
-///     +--rw ddns-qualifying-suffix?         string
-///     +--rw ddns-replace-client-name?       string
-///     +--rw ddns-send-updates?              boolean
-///     +--rw ddns-update-on-renew?           boolean
-///     +--rw ddns-use-conflict-resolution?   boolean
-///     +--rw ddns-conflict-resolution-mode?  conflict-resolution-mode
-///     +--rw hostname-char-replacement?      string
-///     +--rw hostname-char-set?              string
-///     +--rw reservations-global?            boolean
-///     +--rw reservations-in-subnet?         boolean
-///     +--rw reservations-out-of-pool?       boolean
-///     +--rw store-extended-info?            boolean
-///     +--rw user-context?                   user-context
+/// +--rw subnet[46]* [id]
+///    +--rw valid-lifetime?                 uint32
+///    +--rw min-valid-lifetime?             uint32
+///    +--rw max-valid-lifetime?             uint32
+///    +--rw renew-timer?                    uint32
+///    +--rw rebind-timer?                   uint32
+///    +--rw calculate-tee-times?            boolean
+///    +--rw t1-percent?                     decimal64
+///    +--rw t2-percent?                     decimal64
+///    +--rw option-data* [code space]
+///    +--rw pool* [start-address end-address]
+///    +--rw subnet                          inet:ipv4-prefix
+///    +--rw interface?                      string
+///    +--rw id                              uint32
+///    +--rw client-class?                    string
+///    +--rw client-classes*                  string
+///    +--rw require-client-classes*          string
+///    +--rw evaluate-additional-classes* client    string
+///    +--rw host* [identifier-type identifier]
+///    +--rw relay
+///    +--rw cache-max-age?                  uint32
+///    +--rw cache-threshold?                decimal64
+///    +--rw ddns-generated-prefix?          string
+///    +--rw ddns-override-client-update?    boolean
+///    +--rw ddns-override-no-update?        boolean
+///    +--rw ddns-qualifying-suffix?         string
+///    +--rw ddns-replace-client-name?       string
+///    +--rw ddns-send-updates?              boolean
+///    +--rw ddns-update-on-renew?           boolean
+///    +--rw ddns-use-conflict-resolution?   boolean
+///    +--rw ddns-conflict-resolution-mode?  conflict-resolution-mode
+///    +--rw hostname-char-replacement?      string
+///    +--rw hostname-char-set?              string
+///    +--rw reservations-global?            boolean
+///    +--rw reservations-in-subnet?         boolean
+///    +--rw reservations-out-of-pool?       boolean
+///    +--rw store-extended-info?            boolean
+///    +--rw user-context?                   user-context
 ///
-///  DHCPv4 only:
-///  +--rw match-client-id?          boolean
-///  +--rw next-server?              inet:ipv4-address
-///  +--rw server-hostname?          string
-///  +--rw boot-file-name?           string
-///  +--rw subnet-4o6-interface?     string
-///  +--rw subnet-4o6-interface-id?  string
-///  +--rw subnet-4o6-subnet?        inet:ipv6-prefix
-///  +--rw authoritative?            boolean
+/// DHCPv4 only:
+/// +--rw match-client-id?          boolean
+/// +--rw next-server?              inet:ipv4-address
+/// +--rw server-hostname?          string
+/// +--rw boot-file-name?           string
+/// +--rw subnet-4o6-interface?     string
+/// +--rw subnet-4o6-interface-id?  string
+/// +--rw subnet-4o6-subnet?        inet:ipv6-prefix
+/// +--rw authoritative?            boolean
 ///
-///  DHCPv6 only:
-///  +--rw preferred-lifetime?       uint32
-///  +--rw min-preferred-lifetime?   uint32
-///  +--rw max-preferred-lifetime?   uint32
-///  +--rw pd-pool*
-///  +--rw interface-id?             string
-///  +--rw rapid-commit?             boolean
+/// DHCPv6 only:
+/// +--rw preferred-lifetime?       uint32
+/// +--rw min-preferred-lifetime?   uint32
+/// +--rw max-preferred-lifetime?   uint32
+/// +--rw pd-pool*
+/// +--rw interface-id?             string
+/// +--rw rapid-commit?             boolean
 /// @endcode
 ///
 /// An example in JSON and YANG formats for the IETF model:
index 35ac2acfa2ac06ab781c46deaa0ef237bf5b3e11..11e84a4f8cb3fbf25ea16174a1dbb5d3fb7bd197 100644 (file)
@@ -21,12 +21,12 @@ static const std::unordered_map<std::string, std::string> YANG_REVISIONS = {
     { "ietf-dhcpv6-types", "2018-09-04" },
     { "ietf-dhcpv6-options", "2018-09-04" },
     { "ietf-dhcpv6-server", "2018-09-04" },
-    { "kea-types", "2019-08-12" },
+    { "kea-types", "2025-06-25" },
     { "kea-dhcp-types", "2025-06-25" },
     { "kea-dhcp4-server", "2025-06-25" },
     { "kea-dhcp6-server", "2025-06-25" },
-    { "kea-ctrl-agent", "2019-08-12" },
-    { "kea-dhcp-ddns", "2022-07-27" }
+    { "kea-ctrl-agent", "2025-06-25" },
+    { "kea-dhcp-ddns", "2025-06-25" }
 };  // YANG_REVISIONS
 
 }  // namespace yang
diff --git a/src/share/yang/modules/hashes/kea-ctrl-agent@2019-08-12.hash b/src/share/yang/modules/hashes/kea-ctrl-agent@2019-08-12.hash
deleted file mode 100644 (file)
index e37cc12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-eca3d173341b8b318019f9f19548866f4f8d070e0e9739add0aaca6708a46df3
diff --git a/src/share/yang/modules/hashes/kea-ctrl-agent@2025-06-25.hash b/src/share/yang/modules/hashes/kea-ctrl-agent@2025-06-25.hash
new file mode 100644 (file)
index 0000000..4092dab
--- /dev/null
@@ -0,0 +1 @@
+b9fb14697bc1f36d715f7e02088f1c39c81f8bc954e224fbeb42e1f7ab313e07
diff --git a/src/share/yang/modules/hashes/kea-dhcp-ddns@2022-07-27.hash b/src/share/yang/modules/hashes/kea-dhcp-ddns@2022-07-27.hash
deleted file mode 100644 (file)
index c73dcca..0000000
+++ /dev/null
@@ -1 +0,0 @@
-459baf1454bb1ee558457b53cc662fc08d71d10471080116d1bb5176cde63555
diff --git a/src/share/yang/modules/hashes/kea-dhcp-ddns@2025-06-25.hash b/src/share/yang/modules/hashes/kea-dhcp-ddns@2025-06-25.hash
new file mode 100644 (file)
index 0000000..6120b9d
--- /dev/null
@@ -0,0 +1 @@
+4f64a63fc3000178b1273079254c50854e0f6d8783736236e535c84fc2540bdf
index 4410e2efe4947648cb3c464e89dbf8b2603d18d7..d9c5a58a3a1749ad9a499c43c7f2862a0f23b936 100644 (file)
@@ -1 +1 @@
-59fe3a0d6ee9a5a71e861908c559f5d34098f7443bc38601c439102a088b636c
+a42aa4a91f00d6525b268316dba92a70763686183558dd9657f9112cc1c609ca
index 9e93f81908f1d2777194713462e61238c24cb4fb..489f2c02c542f95afefd65fd0ca7bddab38c12a9 100644 (file)
@@ -1 +1 @@
-cf4f3382b9ba301f50593a1ccc277c8635225090e17af2dea75d09ad9c5d197b
+c4805486becacef0c3d7ccf7e96d813bee3001cebec6ec53882e1facacf5c1e2
index a0545cbd862c07ac360ddc0f55f0b59c3bf9e89b..89edf3c4ad8662debf5700673c0df34c8b4aeb11 100644 (file)
@@ -1 +1 @@
-f7dd8cb1cd744d0533e7f3207d131b6305b083f2a7fe2aefd77b9e4598c2dbf8
+e0703301b9a75cb74ed2922aa1fd7f79a1895859d6aaedaa6bd2c8ad8c1c010b
diff --git a/src/share/yang/modules/hashes/kea-types@2019-08-12.hash b/src/share/yang/modules/hashes/kea-types@2019-08-12.hash
deleted file mode 100644 (file)
index 49d7419..0000000
+++ /dev/null
@@ -1 +0,0 @@
-250dd730716a0f65682d866958718eb5eefc62ff1e0463d9ae8047bc16123995
diff --git a/src/share/yang/modules/hashes/kea-types@2025-06-25.hash b/src/share/yang/modules/hashes/kea-types@2025-06-25.hash
new file mode 100644 (file)
index 0000000..8e9dcf0
--- /dev/null
@@ -0,0 +1 @@
+252d56c9442ba3d84b69a878a659f6baaaad69d493dc4c3dbd268298bf067447
similarity index 83%
rename from src/share/yang/modules/kea-ctrl-agent@2019-08-12.yang
rename to src/share/yang/modules/kea-ctrl-agent@2025-06-25.yang
index ff25896d077e7d84f3a79103914d3b6276155885..b62e1bc6399b38e7e68fc6cdf799b8aacb90f54f 100644 (file)
@@ -8,7 +8,7 @@ module kea-ctrl-agent {
   }
   import kea-types {
     prefix kea;
-    revision-date 2019-08-12;
+    revision-date 2025-06-25;
   }
 
   organization "Internet Systems Consortium";
@@ -16,6 +16,12 @@ module kea-ctrl-agent {
   description "This model defines a YANG data model that can be
                used to configure and manage a Kea control agent.";
 
+  revision 2025-06-25 {
+    description "Added HTTP/HTTPS control socket types.
+                 Added trust-anchor, cert-file, key-file, cert-required
+                 authentication and http-headers parameters to control sockets.";
+  }
+
   revision 2019-08-12 {
     description "Initial revision";
     reference "";
@@ -66,6 +72,12 @@ module kea-ctrl-agent {
       }
     }
 
+    uses kea:control-socket-data;
+
+    uses kea:http-headers;
+
+    uses kea:authentication;
+
     uses kea:hooks-libraries;
 
     leaf user-context {
similarity index 90%
rename from src/share/yang/modules/kea-dhcp-ddns@2022-07-27.yang
rename to src/share/yang/modules/kea-dhcp-ddns@2025-06-25.yang
index bafa6a3de12957525d53dd7d98f6b86741cadec3..0b9114a5d42398a85473ca495d3c8b7991f8086b 100644 (file)
@@ -8,7 +8,11 @@ module kea-dhcp-ddns {
   }
   import kea-types {
     prefix kea;
-    revision-date 2019-08-12;
+    revision-date 2025-06-25;
+  }
+  import kea-dhcp-types {
+    prefix dhcp;
+    revision-date 2025-06-25;
   }
 
   organization "Internet Systems Consortium";
@@ -16,6 +20,12 @@ module kea-dhcp-ddns {
   description "This model defines a YANG data model that can be
     used to configure and manage a Kea DHCP-DDNS server.";
 
+  revision 2025-06-25 {
+    description "Added HTTP/HTTPS control socket types.
+                 Added trust-anchor, cert-file, key-file, cert-required
+                 authentication and http-headers parameters to control sockets.";
+  }
+
   revision 2022-07-27 {
     description "Added GSS-TSIG key-name configration parameter for DNS
                  servers";
@@ -131,7 +141,11 @@ module kea-dhcp-ddns {
       description "Packet format to use when sending requests to the server.";
     }
 
-    uses kea:control-socket;
+    container control-socket {
+      description "Control socket.";
+      uses dhcp:control-socket;
+    }
+    uses dhcp:control-sockets;
 
     container forward-ddns {
       description "Forward DNS zones.";
index c5d3468b5b4ecc3b246ec8a9b6714c3e6fb9fe2d..64cc0399168f4c3e98ccbc6fe10a319886d9d56d 100644 (file)
@@ -6,9 +6,10 @@ module kea-dhcp-types {
   import ietf-inet-types {
     prefix inet;
   }
+
   import kea-types {
     prefix kea;
-    revision-date 2019-08-12;
+    revision-date 2025-06-25;
   }
 
   organization "Internet Systems Consortium";
@@ -17,10 +18,10 @@ module kea-dhcp-types {
                groupings.";
 
   revision 2025-06-25 {
-    description "Renamed only-if-required to only-in-additional-list, renamed
-                 require-client-classes to evaluate-additional-classes, removed
-                 client-class and added client-classes list, and added ddns-ttl,
-                 ddns-ttl-min, ddns-ttl-max.";
+    description "Added only-in-additional-list, evaluate-additional-classes,
+                 client-classes list, ddns-ttl, ddns-ttl-min and ddns-ttl-max.
+                 Added trust-anchor, cert-file, key-file, cert-required
+                 authentication and http-headers parameters to control sockets.";
   }
 
   revision 2024-05-29 {
@@ -127,6 +128,57 @@ module kea-dhcp-types {
   /*
   * Grouping
   */
+  grouping control-socket {
+    description "Control socket grouping.";
+    leaf socket-type {
+      type enumeration {
+        enum "unix" {
+          description "Unix socket type.";
+        }
+        enum "http" {
+          description "HTTP socket type.";
+        }
+        enum "https" {
+          description "HTTPS socket type.";
+        }
+      }
+      description "Socket type.";
+      mandatory true;
+    }
+    leaf socket-name {
+      type string;
+      description "Path to the UNIX socket.";
+    }
+    leaf socket-address {
+      type string;
+      description "HTTP/HTTPS socket address.";
+    }
+    leaf socket-port {
+      type string;
+      description "HTTP/HTTPS socket port.";
+    }
+
+    container control-socket {
+      presence "Have control socket.";
+      description "Control socket container.";
+      uses kea:control-socket-data;
+      uses kea:http-headers;
+      uses kea:authentication;
+    }
+  }
+
+  grouping control-sockets {
+    description "Control sockets grouping.";
+    container control-sockets {
+      description "Control sockets.";
+      list control-socket {
+        key "socket-type";
+        description "List of control sockets.";
+        uses control-socket;
+      }
+    }
+  }
+
   grouping valid-lifetime {
     description "Valid lifetime grouping.";
     leaf valid-lifetime {
@@ -537,6 +589,45 @@ module kea-dhcp-types {
     }
   }
 
+  grouping client-class {
+    description "Client class grouping.";
+    leaf client-class {
+      type string;
+      description "Client class entry.";
+    }
+  }
+
+  grouping pool-client-class {
+    description "Client class grouping for a pool.";
+    uses client-class {
+      refine client-class {
+        description "Pool client class guard (only clients belonging
+                     to this class will be allowed in this pool).";
+      }
+    }
+  }
+
+  grouping subnet-client-class {
+    description "Client class grouping for a subnet.";
+    uses client-class {
+      refine client-class {
+        description "Subnet client class guard (only clients belonging to this
+                     class will be allowed in this subnet).";
+      }
+    }
+  }
+
+  grouping network-client-class {
+    description "Client class grouping for a shared network.";
+    uses client-class {
+      refine client-class {
+        description "Shared network client class guard (only clients
+                     belonging to this class will be allowed in this
+                     shared network).";
+      }
+    }
+  }
+
   grouping client-classes {
     description "Client classes grouping.";
     leaf-list client-classes {
@@ -586,6 +677,41 @@ module kea-dhcp-types {
     }
   }
 
+  grouping require-client-classes {
+    description "Require client classes grouping.";
+    leaf-list require-client-classes {
+      type string;
+      description "List of client classes.";
+    }
+  }
+
+  grouping pool-require-client-classes {
+    description "Require client classes grouping for a pool.";
+    uses require-client-classes {
+      refine require-client-classes {
+        description "Pool require client classes.";
+      }
+    }
+  }
+
+  grouping subnet-require-client-classes {
+    description "Require client classes grouping for a subnet.";
+    uses require-client-classes {
+      refine require-client-classes {
+        description "Subnet require client classes.";
+      }
+    }
+  }
+
+  grouping network-require-client-classes {
+    description "Require client classes grouping for a shared network.";
+    uses require-client-classes {
+      refine require-client-classes {
+        description "Shared network require client classes.";
+      }
+    }
+  }
+
   grouping evaluate-additional-classes {
     description "Evaluate additional client classes grouping.";
     leaf-list evaluate-additional-classes {
@@ -771,6 +897,14 @@ module kea-dhcp-types {
     }
   }
 
+  grouping class-only-if-required {
+    description "Client class only-if-required grouping.";
+    leaf only-if-required {
+      type boolean;
+      description "Client class only if required flag.";
+    }
+  }
+
   grouping class-only-in-additional-list {
     description "Client class only-in-additional-list grouping.";
     leaf only-in-additional-list {
index 5b6b36e25964ad4161d36ed2a0a734933cfc00d7..a17018593f134c20f28e594ab8d2c093da49518f 100644 (file)
@@ -8,7 +8,7 @@ module kea-dhcp4-server {
   }
   import kea-types {
     prefix kea;
-    revision-date 2019-08-12;
+    revision-date 2025-06-25;
   }
   import kea-dhcp-types {
     prefix dhcp;
@@ -21,14 +21,16 @@ module kea-dhcp4-server {
                used to configure and manage a Kea DHCPv4 server.";
 
   revision 2025-06-25 {
-    description "Renamed only-if-required to only-in-additional-list, renamed
-                 require-client-classes to evaluate-additional-classes, removed
-                 client-class and added client-classes list, added ddns-ttl,
-                 ddns-ttl-min, ddns-ttl-max, and added ddns-generated-prefix,
-                 ddns-override-client-update, ddns-override-no-update,
-                 ddns-qualifying-suffix, ddns-replace-client-name, ddns-send-updates,
-                 ddns-update-on-renew, ddns-conflict-resolution-mode,
-                 hostname-char-replacement and hostname-char-set at pool level.";
+    description "Added only-in-additional-list, evaluate-additional-classes,
+                 client-classes list, ddns-ttl, ddns-ttl-min, ddns-ttl-max,
+                 ddns-generated-prefix, ddns-override-client-update,
+                 ddns-override-no-update, ddns-qualifying-suffix,
+                 ddns-replace-client-name, ddns-send-updates, ddns-update-on-renew,
+                 ddns-conflict-resolution-mode, hostname-char-replacement and
+                 hostname-char-set at pool level.
+                 Added HTTP/HTTPS control socket types.
+                 Added trust-anchor, cert-file, key-file, cert-required
+                 authentication and http-headers parameters to control sockets.";
   }
 
   revision 2024-05-29 {
@@ -256,7 +258,9 @@ module kea-dhcp4-server {
         uses dhcp:ddns-conflict-resolution-mode;
         uses dhcp:hostname-char-replacement;
         uses dhcp:hostname-char-set;
+        uses dhcp:pool-client-class;
         uses dhcp:pool-client-classes;
+        uses dhcp:pool-require-client-classes;
         uses dhcp:pool-evaluate-additional-classes;
         uses dhcp:pool-id;
         uses dhcp:pool-user-context;
@@ -268,7 +272,9 @@ module kea-dhcp4-server {
       }
       uses dhcp:subnet-interface;
       uses dhcp:subnet-id;
+      uses dhcp:subnet-client-class;
       uses dhcp:subnet-client-classes;
+      uses dhcp:subnet-require-client-classes;
       uses dhcp:subnet-evaluate-additional-classes;
       uses reservations {
         refine host {
@@ -330,6 +336,7 @@ module kea-dhcp4-server {
       uses dhcp:class-name;
       uses dhcp:class-test;
       uses dhcp:template-test;
+      uses dhcp:class-only-if-required;
       uses dhcp:class-only-in-additional-list;
       uses dhcp:offer-lifetime;
       uses option-def-list;
@@ -432,7 +439,9 @@ module kea-dhcp4-server {
         uses relay;
       }
       uses authoritative;
+      uses dhcp:network-client-class;
       uses dhcp:network-client-classes;
+      uses dhcp:network-require-client-classes;
       uses dhcp:network-evaluate-additional-classes;
       uses dhcp:valid-lifetime;
       uses dhcp:min-valid-lifetime;
@@ -514,7 +523,11 @@ module kea-dhcp4-server {
     uses kea:hooks-libraries;
     uses dhcp:expired-leases-processing;
     uses dhcp:dhcp4o6-port;
-    uses kea:control-socket;
+    container control-socket {
+      description "Control socket.";
+      uses dhcp:control-socket;
+    }
+    uses dhcp:control-sockets;
     uses dhcp:hostname-char-set;
     uses dhcp:hostname-char-replacement;
     uses dhcp:dhcp-ddns;
index 162ac948e0c99f8d21265eae72a3862367239726..adbe1da62707314a2981a4aadfcd4e53bd446dd6 100644 (file)
@@ -8,7 +8,7 @@ module kea-dhcp6-server {
   }
   import kea-types {
     prefix kea;
-    revision-date 2019-08-12;
+    revision-date 2025-06-25;
   }
   import kea-dhcp-types {
     prefix dhcp;
@@ -21,15 +21,16 @@ module kea-dhcp6-server {
                used to configure and manage a Kea DHCPv6 server.";
 
   revision 2025-06-25 {
-    description "Renamed only-if-required to only-in-additional-list, renamed
-                 require-client-classes to evaluate-additional-classes, removed
-                 client-class and added client-classes list, added ddns-ttl,
-                 ddns-ttl-min, ddns-ttl-max, added ddns-generated-prefix,
-                 ddns-override-client-update, ddns-override-no-update,
-                 ddns-qualifying-suffix, ddns-replace-client-name, ddns-send-updates,
-                 ddns-update-on-renew, ddns-conflict-resolution-mode,
-                 hostname-char-replacement and hostname-char-set at pool and pd-pool
-                 level, and added excluded-prefixes at pd-pool level.";
+    description "Added only-in-additional-list, evaluate-additional-classes,
+                 client-classes list, ddns-ttl, ddns-ttl-min, ddns-ttl-max,
+                 ddns-generated-prefix, ddns-override-client-update,
+                 ddns-override-no-update, ddns-qualifying-suffix,
+                 ddns-replace-client-name, ddns-send-updates, ddns-update-on-renew,
+                 ddns-conflict-resolution-mode, hostname-char-replacement and
+                 hostname-char-set at pool and pd-pool level, added
+                 excluded-prefixes at pd-pool level.
+                 Added trust-anchor, cert-file, key-file, cert-required
+                 authentication and http-headers parameters to control sockets.";
   }
 
   revision 2024-05-29 {
@@ -266,7 +267,9 @@ module kea-dhcp6-server {
         uses dhcp:ddns-conflict-resolution-mode;
         uses dhcp:hostname-char-replacement;
         uses dhcp:hostname-char-set;
+        uses dhcp:pool-client-class;
         uses dhcp:pool-client-classes;
+        uses dhcp:pool-require-client-classes;
         uses dhcp:pool-evaluate-additional-classes;
         uses dhcp:pool-id;
         uses dhcp:pool-user-context;
@@ -300,6 +303,13 @@ module kea-dhcp6-server {
         uses dhcp:ddns-conflict-resolution-mode;
         uses dhcp:hostname-char-replacement;
         uses dhcp:hostname-char-set;
+        uses dhcp:client-class {
+          refine client-class {
+            description "Prefix pool client class guard. (only
+                         clients belonging to this class will be
+                         allowed in this pool).";
+          }
+        }
         uses dhcp:client-classes {
           refine client-classes {
             description "Prefix pool client class guard. (only clients
@@ -307,6 +317,11 @@ module kea-dhcp6-server {
                          allowed in this pool).";
           }
         }
+        uses dhcp:require-client-classes {
+          refine require-client-classes {
+            description "Prefix pool require client classes.";
+          }
+        }
         uses dhcp:evaluate-additional-classes {
           refine evaluate-additional-classes {
             description "Prefix pool evaluate additional client classes.";
@@ -341,7 +356,9 @@ module kea-dhcp6-server {
           description "Subnet rapid commit flag.";
         }
       }
+      uses dhcp:subnet-client-class;
       uses dhcp:subnet-client-classes;
+      uses dhcp:subnet-require-client-classes;
       uses dhcp:subnet-evaluate-additional-classes;
       uses reservations {
         refine host {
@@ -386,6 +403,7 @@ module kea-dhcp6-server {
       uses dhcp:class-name;
       uses dhcp:class-test;
       uses dhcp:template-test;
+      uses dhcp:class-only-if-required;
       uses dhcp:class-only-in-additional-list;
       uses option-data-list;
       uses preferred-lifetime;
@@ -490,7 +508,9 @@ module kea-dhcp6-server {
         description "Optional information about relay agent.";
         uses relay;
       }
+      uses dhcp:network-client-class;
       uses dhcp:network-client-classes;
+      uses dhcp:network-require-client-classes;
       uses dhcp:network-evaluate-additional-classes;
       uses preferred-lifetime;
       uses min-preferred-lifetime;
@@ -611,7 +631,11 @@ module kea-dhcp6-server {
     }
 
     uses dhcp:dhcp4o6-port;
-    uses kea:control-socket;
+    container control-socket {
+      description "Control socket.";
+      uses dhcp:control-socket;
+    }
+    uses dhcp:control-sockets;
     uses dhcp:hostname-char-set;
     uses dhcp:hostname-char-replacement;
     uses dhcp:dhcp-ddns;
similarity index 63%
rename from src/share/yang/modules/kea-types@2019-08-12.yang
rename to src/share/yang/modules/kea-types@2025-06-25.yang
index a19c18f9e8b04e64633e74e5785370735cbb01f9..2a999492d308481cef2c962be1ce04a08eaaa3d7 100644 (file)
@@ -7,6 +7,11 @@ module kea-types {
   contact "kea-dev@lists.isc.org";
   description "This file defines some commonly used Kea types and groupings.";
 
+  revision 2025-06-25 {
+    description "Added trust-anchor, cert-file, key-file, cert-required
+                 authentication and http-headers parameters to control sockets.";
+  }
+
   revision 2019-08-12 {
     description "Initial revision";
   }
@@ -52,13 +57,94 @@ module kea-types {
     }
   }
 
-  grouping control-socket {
-    description "Control socket grouping.";
-    container control-socket {
-      presence "Have control socket.";
-      description "Control socket container.";
-      uses control-socket-info;
+  grouping control-socket-data {
+    description "Control socket parameters.";
+    leaf trust-anchor {
+      type string;
+      description "TLS trust anchor (Certificate Authority).";
+    }
+    leaf cert-file {
+      type string;
+      description "TLS server certificate file name.";
+    }
+    leaf key-file {
+      type string;
+      description "TLS server private key file name.";
+    }
+    leaf cert-required {
+      type boolean;
+      description "TLS require client certificates flag.";
+    }
+  }
+
+  grouping http-headers {
+    description "HTTP headers grouping.";
+    list http-headers {
+      key name;
+      description "List of HTTP headers.";
+      leaf name {
+        type string;
+        mandatory true;
+        description "HTTP header name.";
+      }
+      leaf value {
+        type string;
+        description "Value (JSON value).";
+      }
+      leaf user-context {
+        type user-context;
+        description "HTTP header user context.";
+      }
+    }
+  }
+
+  grouping clients {
+    description "HTTP client authentication.";
+    list clients {
+      leaf user {
+        type string;
+        description "HTTP user.";
+      }
+      leaf password {
+        type string;
+        description "HTTP password.";
+      }
+      leaf user-file {
+        type string;
+        description "HTTP user file.";
+      }
+      leaf password-file {
+        type string;
+        description "HTTP password file.";
+      }
+      key "user password user-file password-file";
+    }
+  }
+
+  grouping authentication {
+    description "HTTP authentication.";
+    container authentication {
+      grouping auth-type {
+        leaf auth-type {
+          type enumeration {
+            enum "basic" {
+              description "Basic HTTP authentication";
+            }
+          }
+          description "HTTP authentication type.";
+          mandatory true;
+        }
+      }
+      leaf realm {
+        type string;
+        description "HTTP authentication realm.";
+      }
+      leaf directory {
+        type string;
+        description "HTTP authentication directory.";
+      }
     }
+    uses clients;
   }
 
   grouping hooks-libraries {
index c81026da6ce057f8f98e780ec19326c49b7f188b..f87d129f86eca888e1265851ee616d6792e6b160 100644 (file)
@@ -14,12 +14,12 @@ yangmodules_list = [
     'ietf-inet-types@2013-07-15.yang',
     'ietf-interfaces@2018-02-20.yang',
     'ietf-yang-types@2013-07-15.yang',
-    'kea-ctrl-agent@2019-08-12.yang',
-    'kea-dhcp-ddns@2022-07-27.yang',
+    'kea-ctrl-agent@2025-06-25.yang',
+    'kea-dhcp-ddns@2025-06-25.yang',
     'kea-dhcp-types@2025-06-25.yang',
     'kea-dhcp4-server@2025-06-25.yang',
     'kea-dhcp6-server@2025-06-25.yang',
-    'kea-types@2019-08-12.yang',
+    'kea-types@2025-06-25.yang',
     'keatest-module@2022-11-30.yang',
 ]
 list = run_command(