},
// 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.
},
// 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.
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);
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");
}
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");
}
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");
}
///
/// Remove empty lists in a pool list.
/// removing:
+ /// - require-client-classes
/// - evaluate-additional-classes
+ /// - client-class
/// - client-classes
///
/// @param pools The pool list.
///
/// Remove empty lists in a subnet list.
/// removing:
+ /// - require-client-classes
/// - evaluate-additional-classes
+ /// - client-class
/// - client-classes
///
/// @param subnets The subnet list.
///
/// 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.
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());
}
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");
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);
/// {
/// "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)
/// +--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]
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 {
}
}
- 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");
/// +--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
/// {
/// "interfaces": [ "eth1" ]
/// },
-/// "control-socket": {
+/// "control-sockets": [ {
/// "socket-type": "unix",
/// "socket-name": "kea4-sock"
-/// },
+/// } ],
/// "subnet4":
/// [
/// {
/// <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
/// <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>,
/// +--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
/// {
/// "interfaces": [ "eth1" ]
/// },
-/// "control-socket": {
+/// "control-sockets": [ {
/// "socket-type": "unix",
/// "socket-name": "kea6-sock"
-/// },
+/// } ],
/// "subnet6":
/// [
/// {
/// <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
: 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 {
"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 {
}
}
+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) {
(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: "
}
}
+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
///
/// 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
/// @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
/// @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.
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
/// @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.
///
/// @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
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) {
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,
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) {
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,
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");
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);
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);
// 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);
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");
/// "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>"
/// +--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?
/// +--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
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");
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);
/// {
/// "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>"
/// +--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
/// +--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
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");
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");
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);
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);
/// "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>,
/// "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> },
/// +--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
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");
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");
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);
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");
/// "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)>,
/// "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)>,
///
/// 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:
{ "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
+++ /dev/null
-eca3d173341b8b318019f9f19548866f4f8d070e0e9739add0aaca6708a46df3
--- /dev/null
+b9fb14697bc1f36d715f7e02088f1c39c81f8bc954e224fbeb42e1f7ab313e07
+++ /dev/null
-459baf1454bb1ee558457b53cc662fc08d71d10471080116d1bb5176cde63555
--- /dev/null
+4f64a63fc3000178b1273079254c50854e0f6d8783736236e535c84fc2540bdf
-59fe3a0d6ee9a5a71e861908c559f5d34098f7443bc38601c439102a088b636c
+a42aa4a91f00d6525b268316dba92a70763686183558dd9657f9112cc1c609ca
-cf4f3382b9ba301f50593a1ccc277c8635225090e17af2dea75d09ad9c5d197b
+c4805486becacef0c3d7ccf7e96d813bee3001cebec6ec53882e1facacf5c1e2
-f7dd8cb1cd744d0533e7f3207d131b6305b083f2a7fe2aefd77b9e4598c2dbf8
+e0703301b9a75cb74ed2922aa1fd7f79a1895859d6aaedaa6bd2c8ad8c1c010b
+++ /dev/null
-250dd730716a0f65682d866958718eb5eefc62ff1e0463d9ae8047bc16123995
--- /dev/null
+252d56c9442ba3d84b69a878a659f6baaaad69d493dc4c3dbd268298bf067447
}
import kea-types {
prefix kea;
- revision-date 2019-08-12;
+ revision-date 2025-06-25;
}
organization "Internet Systems Consortium";
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 "";
}
}
+ uses kea:control-socket-data;
+
+ uses kea:http-headers;
+
+ uses kea:authentication;
+
uses kea:hooks-libraries;
leaf user-context {
}
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";
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";
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.";
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";
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 {
/*
* 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 {
}
}
+ 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 {
}
}
+ 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 {
}
}
+ 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 {
}
import kea-types {
prefix kea;
- revision-date 2019-08-12;
+ revision-date 2025-06-25;
}
import kea-dhcp-types {
prefix dhcp;
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 {
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;
}
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 {
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;
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;
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;
}
import kea-types {
prefix kea;
- revision-date 2019-08-12;
+ revision-date 2025-06-25;
}
import kea-dhcp-types {
prefix dhcp;
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 {
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;
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
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.";
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 {
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;
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;
}
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;
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";
}
}
}
- 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 {
'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(