]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[65-libyang-shared-network-translator] Added shared network translator code and tests...
authorFrancis Dupont <fdupont@isc.org>
Mon, 22 Oct 2018 12:48:52 +0000 (14:48 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Mon, 22 Oct 2018 17:59:13 +0000 (19:59 +0200)
src/lib/yang/Makefile.am
src/lib/yang/tests/Makefile.am
src/lib/yang/tests/translator_shared_network_unittests.cc [new file with mode: 0644]
src/lib/yang/translator_shared_network.cc [new file with mode: 0644]
src/lib/yang/translator_shared_network.h [new file with mode: 0644]

index 5a7545bccf0715fbdb116b9e8facbde2cd8b63b4..74aae0da0c5c013e949492489eff2cb63b749482 100644 (file)
@@ -25,6 +25,8 @@ libkea_yang_la_SOURCES += translator_pool.cc translator_pool.h
 libkea_yang_la_SOURCES += translator_pd_pool.cc translator_pd_pool.h
 libkea_yang_la_SOURCES += translator_host.cc translator_host.h
 libkea_yang_la_SOURCES += translator_subnet.cc translator_subnet.h
+libkea_yang_la_SOURCES += translator_shared_network.cc
+libkea_yang_la_SOURCES += translator_shared_network.h
 libkea_yang_la_SOURCES += yang_models.h
 
 libkea_yang_la_LIBADD =  $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
@@ -56,6 +58,7 @@ libkea_yang_include_HEADERS = \
        translator_option_def.h \
        translator_pool.h \
        translator_pd_pool.h \
+       translator_shared_network.h \
        translator_subnet.h \
        yang_models.h
 
index ac62f820fdfb8bf529a1b75115a35e48319bf366..a6764116e25e6e0614ca6ae2301533be8e1362b9 100644 (file)
@@ -34,6 +34,7 @@ run_unittests_SOURCES += translator_pool_unittests.cc
 run_unittests_SOURCES += translator_pd_pool_unittests.cc
 run_unittests_SOURCES += translator_host_unittests.cc
 run_unittests_SOURCES += translator_subnet_unittests.cc
+run_unittests_SOURCES += translator_shared_network_unittests.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/yang/tests/translator_shared_network_unittests.cc b/src/lib/yang/tests/translator_shared_network_unittests.cc
new file mode 100644 (file)
index 0000000..3165926
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <yang/translator_shared_network.h>
+#include <yang/yang_models.h>
+#include <yang/tests/sysrepo_setup.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::data;
+using namespace isc::yang;
+using namespace isc::yang::test;
+
+namespace {
+
+/// @brief Translator name.
+extern char const shared_networks[] = "shared networks";
+
+/// @brief Test fixture class for @ref TranslatorSharedNetworks.
+class TranslatorSharedNetworksTest :
+    public GenericTranslatorTest<shared_networks, TranslatorSharedNetworks> {
+public:
+
+    /// Constructor.
+    TranslatorSharedNetworksTest() { }
+
+    /// Destructor (does nothing).
+    virtual ~TranslatorSharedNetworksTest() { }
+};
+
+// This test verifies that an empty shared network list can be properly
+// translated from YANG to JSON.
+TEST_F(TranslatorSharedNetworksTest, getEmpty) {
+    useModel(KEA_DHCP4_SERVER);
+
+    // Get the shared network list and check if it is empty.
+    const string& xpath = "/kea-dhcp4-server:config/shared-networks";
+    ConstElementPtr networks;
+    EXPECT_NO_THROW(networks = t_obj_->getSharedNetworks(xpath));
+    ASSERT_TRUE(networks);
+    ASSERT_EQ(Element::list, networks->getType());
+    EXPECT_EQ(0, networks->size());
+}
+
+// This test verifies that one shared network can be properly
+// translated from YANG to JSON.
+TEST_F(TranslatorSharedNetworksTest, get) {
+    useModel(KEA_DHCP6_SERVER);
+
+    // Create the subnet 2001:db8::/48 #111 in shared network foo.
+    const string& xpath = "/kea-dhcp6-server:config/shared-networks";
+    const string& xnetwork = xpath + "/shared-network[name='foo']";
+    const string& xsubnet = xnetwork + "/subnet6/subnet6[id='111']/subnet";
+    S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+    EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
+
+    // Get the shared network.
+    ConstElementPtr network;
+    EXPECT_NO_THROW(network = t_obj_->getSharedNetwork(xnetwork));
+    ASSERT_TRUE(network);
+    ElementPtr subnet = Element::createMap();
+    subnet->set("id", Element::create(111));
+    subnet->set("subnet", Element::create(string("2001:db8::/48")));
+    ElementPtr subnets = Element::createList();
+    subnets->add(subnet);
+    ElementPtr expected = Element::createMap();
+    expected->set("name", Element::create(string("foo")));
+    expected->set("subnet6", subnets);
+    EXPECT_TRUE(expected->equals(*network));
+
+    // Get the shared network list and check if the shared network is in it.
+    ConstElementPtr networks;
+    EXPECT_NO_THROW(networks = t_obj_->getSharedNetworks(xpath));
+    ASSERT_TRUE(networks);
+    ASSERT_EQ(Element::list, networks->getType());
+    ASSERT_EQ(1, networks->size());
+    EXPECT_TRUE(network->equals(*networks->get(0)));
+}
+
+// This test verifies that an empty shared network list can be properly
+// translated from JSON to YANG.
+TEST_F(TranslatorSharedNetworksTest, setEmpty) {
+    useModel(KEA_DHCP4_SERVER);
+
+    // Set empty list.
+    const string& xpath = "/kea-dhcp4-server:config/shared-networks";
+    ConstElementPtr networks = Element::createList();
+    EXPECT_NO_THROW(t_obj_->setSharedNetworks(xpath, networks));
+
+    // Get it back.
+    networks.reset();
+    EXPECT_NO_THROW(networks = t_obj_->getSharedNetworks(xpath));
+    ASSERT_TRUE(networks);
+    ASSERT_EQ(Element::list, networks->getType());
+    EXPECT_EQ(0, networks->size());
+
+    // Check that the tree representation is empty.
+    S_Tree tree;
+    EXPECT_NO_THROW(tree = sess_->get_subtree("/kea-dhcp4-server:config"));
+    EXPECT_FALSE(tree);
+}
+
+// This test verifies that one shared network can be properly
+// translated from JSON to YANG.
+TEST_F(TranslatorSharedNetworksTest, set) {
+    useModel(KEA_DHCP6_SERVER);
+
+    // Set one shared network.
+    const string& xpath = "/kea-dhcp6-server:config/shared-networks";
+    ElementPtr networks = Element::createList();
+    ElementPtr share = Element::createMap();
+    ElementPtr subnets = Element::createList();
+    ElementPtr subnet = Element::createMap();
+    subnet->set("subnet", Element::create(string("2001:db8::/48")));
+    subnet->set("id", Element::create(123));
+    subnets->add(subnet);
+    share->set("name", Element::create(string("foo")));
+    share->set("subnet6", subnets);
+    networks->add(share);
+    EXPECT_NO_THROW(t_obj_->setSharedNetworks(xpath, networks));
+
+    // Get it back.
+    networks.reset();
+    EXPECT_NO_THROW(networks = t_obj_->getSharedNetworks(xpath));
+    ASSERT_TRUE(networks);
+    ASSERT_EQ(Element::list, networks->getType());
+    ASSERT_EQ(1, networks->size());
+    EXPECT_TRUE(share->equals(*networks->get(0)));
+
+    // Check the tree representation.
+    S_Tree tree;
+    EXPECT_NO_THROW(tree = sess_->get_subtree("/kea-dhcp6-server:config"));
+    ASSERT_TRUE(tree);
+    string expected =
+        "kea-dhcp6-server:config (container)\n"
+        " |\n"
+        " -- shared-networks (container)\n"
+        "     |\n"
+        "     -- shared-network (list instance)\n"
+        "         |\n"
+        "         -- name = foo\n"
+        "         |\n"
+        "         -- subnet6 (container)\n"
+        "             |\n"
+        "             -- subnet6 (list instance)\n"
+        "                 |\n"
+        "                 -- id = 123\n"
+        "                 |\n"
+        "                 -- subnet = 2001:db8::/48\n";
+    EXPECT_EQ(expected, tree->to_string(100));
+
+    // Check it validates.
+    EXPECT_NO_THROW(sess_->validate());
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/yang/translator_shared_network.cc b/src/lib/yang/translator_shared_network.cc
new file mode 100644 (file)
index 0000000..b74bbaa
--- /dev/null
@@ -0,0 +1,339 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <yang/translator_shared_network.h>
+#include <yang/adaptor.h>
+#include <yang/yang_models.h>
+#include <sstream>
+
+using namespace std;
+using namespace isc::data;
+
+namespace isc {
+namespace yang {
+
+TranslatorSharedNetwork::TranslatorSharedNetwork(S_Session session,
+                                                 const string& model)
+    : TranslatorBasic(session),
+      TranslatorOptionData(session, model),
+      TranslatorOptionDataList(session, model),
+      TranslatorPool(session, model),
+      TranslatorPools(session, model),
+      TranslatorPdPool(session, model),
+      TranslatorPdPools(session, model),
+      TranslatorHost(session, model),
+      TranslatorHosts(session, model),
+      TranslatorSubnet(session, model),
+      TranslatorSubnets(session, model),
+      model_(model) {
+}
+
+TranslatorSharedNetwork::~TranslatorSharedNetwork() {
+}
+
+ElementPtr
+TranslatorSharedNetwork::getSharedNetwork(const string& xpath) {
+    try {
+        if (model_ == KEA_DHCP4_SERVER) {
+            return (getSharedNetworkKea(xpath, "subnet4"));
+        } else if (model_ == KEA_DHCP6_SERVER) {
+            return (getSharedNetworkKea(xpath, "subnet6"));
+        }
+    } catch (const sysrepo_exception& ex) {
+        isc_throw(SysrepoError,
+                  "sysrepo error getting shared network at '" << xpath
+                  << "': " << ex.what());
+    }
+    isc_throw(NotImplemented,
+              "getSharedNetwork not implemented for the model: " << model_);
+}
+
+ElementPtr
+TranslatorSharedNetwork::getSharedNetworkKea(const string& xpath,
+                                             const std::string& subsel) {
+    ElementPtr result = Element::createMap();
+    result->set("name", getItem(xpath + "/name"));
+    ConstElementPtr subnets = getSubnets(xpath + "/" + subsel);
+    if (subnets && (subnets->size() > 0)) {
+        result->set(subsel, subnets);
+    }
+    if (subsel == "subnet6") {
+        ConstElementPtr preferred = getItem(xpath + "/preferred-lifetime");
+        if (preferred) {
+            result->set("preferred-lifetime", preferred);
+        }
+    }
+    ConstElementPtr valid = getItem(xpath + "/valid-lifetime");
+    if (valid) {
+        result->set("valid-lifetime", valid);
+    }
+    ConstElementPtr renew = getItem(xpath + "/renew-timer");
+    if (renew) {
+        result->set("renew-timer", renew);
+    }
+    ConstElementPtr rebind = getItem(xpath + "/rebind-timer");
+    if (rebind) {
+        result->set("rebind-timer", rebind);
+    }
+    ConstElementPtr options = getOptionDataList(xpath + "/option-data-list");
+    if (options && (options->size() > 0)) {
+        result->set("option-data", options);
+    }
+    ConstElementPtr interface = getItem(xpath + "/interface");
+    if (interface) {
+        result->set("interface", interface);
+    }
+    if (subsel == "subnet6") {
+        ConstElementPtr interface_id = getItem(xpath + "/interface-id");
+        if (interface_id) {
+            result->set("interface-id", interface_id);
+        }
+        ConstElementPtr rapid_commit = getItem(xpath + "/rapid-commit");
+        if (rapid_commit) {
+            result->set("rapid-commit", rapid_commit);
+        }
+    }
+    ConstElementPtr guard =  getItem(xpath + "/client-class");
+    if (guard) {
+        result->set("client-class", guard);
+    }
+    ConstElementPtr required = getItems(xpath + "/require-client-classes");
+    if (required && (required->size() > 0)) {
+        result->set("require-client-classes", required);
+    }
+    ConstElementPtr mode = getItem(xpath + "/reservation-mode");
+    if (mode) {
+        result->set("reservation-mode", mode);
+    }
+    ConstElementPtr relay = getItems(xpath + "/relay/ip-addresses");
+    if (relay && (relay->size() > 0)) {
+        ElementPtr relay_map = Element::createMap();
+        relay_map->set("ip-addresses", relay);
+        result->set("relay", relay_map);
+    }
+    if (subsel == "subnet4") {
+        ConstElementPtr match = getItem(xpath + "/match-client-id");
+        if (match) {
+            result->set("match-client-id", match);
+        }
+        ConstElementPtr next = getItem(xpath + "/next-server");
+        if (next) {
+            result->set("next-server", next);
+        }
+        ConstElementPtr hostname = getItem(xpath + "/server-hostname");
+        if (hostname) {
+            result->set("server-hostname", hostname);
+        }
+        ConstElementPtr boot = getItem(xpath + "/boot-file-name");
+        if (boot) {
+            result->set("boot-file-name", boot);
+        }
+    }
+    ConstElementPtr context = getItem(xpath + "/user-context");
+    if (context) {
+        result->set("user-context", Element::fromJSON(context->stringValue()));
+    }
+    return (result);
+}
+
+void
+TranslatorSharedNetwork::setSharedNetwork(const string& xpath,
+                                          ConstElementPtr elem) {
+    try {
+        if (model_ == KEA_DHCP4_SERVER) {
+            setSharedNetworkKea(xpath, elem, "subnet4");
+        } else if (model_ == KEA_DHCP6_SERVER) {
+            setSharedNetworkKea(xpath, elem, "subnet6");
+        } else {
+            isc_throw(NotImplemented,
+                      "setSharedNetwork not implemented for the model: "
+                      << model_);
+        }
+    } catch (const sysrepo_exception& ex) {
+        isc_throw(SysrepoError,
+                  "sysrepo error setting shared network '" << elem->str()
+                  << "' at '" << xpath << "': " << ex.what());
+    }
+}
+
+void
+TranslatorSharedNetwork::setSharedNetworkKea(const string& xpath,
+                                             ConstElementPtr elem,
+                                             const std::string& subsel) {
+    // Skip name which is the key.
+    ConstElementPtr subnets = elem->get(subsel);
+    if (subnets && (subnets->size() > 0)) {
+        setSubnets(xpath + "/" + subsel, subnets);
+    }
+    if (subsel == "subnet6") {
+        ConstElementPtr preferred = elem->get("preferred-lifetime");
+        if (preferred) {
+            setItem(xpath + "/preferred-lifetime", preferred, SR_UINT32_T);
+        }
+    }
+    ConstElementPtr valid = elem->get("valid-lifetime");
+    if (valid) {
+        setItem(xpath + "/valid-lifetime", valid, SR_UINT32_T);
+    }
+    ConstElementPtr renew = elem->get("renew-timer");
+    if (renew) {
+        setItem(xpath + "/renew-timer", renew, SR_UINT32_T);
+    }
+    ConstElementPtr rebind = elem->get("rebind-timer");
+    if (rebind) {
+        setItem(xpath + "/rebind-timer", rebind, SR_UINT32_T);
+    }
+    ConstElementPtr options = elem->get("option-data");
+    if (options && (options->size() > 0)) {
+        setOptionDataList(xpath + "/option-data-list", options);
+    }
+    ConstElementPtr interface = elem->get("interface");
+    if (interface) {
+        setItem(xpath + "/interface", interface, SR_STRING_T);
+    }
+    if (subsel == "subnet6") {
+        ConstElementPtr interface_id = elem->get("interface-id");
+        if (interface_id) {
+            setItem(xpath + "/interface-id", interface_id, SR_STRING_T);
+        }
+        ConstElementPtr rapid_commit = elem->get("rapid-commit");
+        if (rapid_commit) {
+            setItem(xpath + "/rapid-commit", rapid_commit, SR_BOOL_T);
+        }
+    }
+    ConstElementPtr guard = elem->get("client-class");
+    if (guard) {
+        setItem(xpath + "/client-class", guard, SR_STRING_T);
+    }
+    ConstElementPtr required = elem->get("require-client-classes");
+    if (required && (required->size() > 0)) {
+        for (ConstElementPtr rclass : required->listValue()) {
+            setItem(xpath + "/require-client-classes", rclass, SR_STRING_T);
+        }
+    }
+    ConstElementPtr mode = elem->get("reservation-mode");
+    if (mode) {
+        setItem(xpath + "/reservation-mode", mode, SR_ENUM_T);
+    }
+    ConstElementPtr relay = elem->get("relay");
+    if (relay) {
+        ConstElementPtr address = relay->get("ip-address");
+        ConstElementPtr addresses = relay->get("ip-addresses");
+        if (address) {
+            setItem(xpath + "/relay/ip-addresses", address, SR_STRING_T);
+        } else if (addresses && (addresses->size() > 0)) {
+            for (ConstElementPtr addr : addresses->listValue()) {
+                setItem(xpath + "/relay/ip-addresses", addr, SR_STRING_T);
+            }
+        }
+    }
+    if (subsel == "subnet4") {
+        ConstElementPtr match = elem->get("match-client-id");
+        if (match) {
+            setItem(xpath + "/match-client-id", match, SR_BOOL_T);
+        }
+        ConstElementPtr next = elem->get("next-server");
+        if (next) {
+            setItem(xpath + "/next-server", next, SR_STRING_T);
+        }
+        ConstElementPtr hostname = elem->get("server-hostname");
+        if (hostname) {
+            setItem(xpath + "/server-hostname", hostname, SR_STRING_T);
+        }
+        ConstElementPtr boot = elem->get("boot-file-name");
+        if (boot) {
+            setItem(xpath + "/boot-file-name", boot, SR_STRING_T);
+        }
+    }
+    ConstElementPtr context = Adaptor::getContext(elem);
+    if (context) {
+        ConstElementPtr repr = Element::create(context->str());
+        setItem(xpath + "/user-context", repr, SR_STRING_T);
+    }
+}
+
+TranslatorSharedNetworks::TranslatorSharedNetworks(S_Session session,
+                                                   const string& model)
+    : TranslatorBasic(session),
+      TranslatorOptionData(session, model),
+      TranslatorOptionDataList(session, model),
+      TranslatorPool(session, model),
+      TranslatorPools(session, model),
+      TranslatorPdPool(session, model),
+      TranslatorPdPools(session, model),
+      TranslatorHost(session, model),
+      TranslatorHosts(session, model),
+      TranslatorSubnet(session, model),
+      TranslatorSubnets(session, model),
+      TranslatorSharedNetwork(session, model),
+      model_(model) {
+}
+
+TranslatorSharedNetworks::~TranslatorSharedNetworks() {
+}
+
+ElementPtr
+TranslatorSharedNetworks::getSharedNetworks(const string& xpath) {
+    try {
+        ElementPtr result = Element::createList();
+        S_Iter_Value iter = getIter(xpath + "/*");
+        if (!iter) {
+            // Can't happen.
+            isc_throw(Unexpected, "getSharedNetworks: can't get iterator: "
+                      << xpath);
+        }
+        for (;;) {
+            const string& network = getNext(iter);
+            if (network.empty()) {
+                break;
+            }
+            result->add(getSharedNetwork(network));
+        }
+        return (result);
+    } catch (const sysrepo_exception& ex) {
+        isc_throw(SysrepoError,
+                  "sysrepo error getting shared networks at '" << xpath
+                  << "': " << ex.what());
+    }
+}
+
+void
+TranslatorSharedNetworks::setSharedNetworks(const string& xpath,
+                                            ConstElementPtr elem) {
+    try {
+        if ((model_ == KEA_DHCP4_SERVER) ||
+            (model_ == KEA_DHCP6_SERVER)) {
+            setSharedNetworksKea(xpath, elem);
+        } else {
+            isc_throw(NotImplemented,
+                      "setSharedNetworks not implemented for the model: "
+                      << model_);
+        }
+    } catch (const sysrepo_exception& ex) {
+        isc_throw(SysrepoError,
+                  "sysrepo error setting shared networks '" << elem->str()
+                  << "' at '" << xpath << "': " << ex.what());
+    }
+}
+
+void
+TranslatorSharedNetworks::setSharedNetworksKea(const string& xpath,
+                                               ConstElementPtr elem) {
+    for (size_t i = 0; i < elem->size(); ++i) {
+        ConstElementPtr network = elem->get(i);
+        if (!network->contains("name")) {
+            isc_throw(BadValue, "setSharedNetworksKea requires name: "
+                      << network->str());
+        }
+        string name = network->get("name")->stringValue();
+        ostringstream key;
+        key<< xpath << "/shared-network[name='" << name << "']";
+        setSharedNetwork(key.str(), network);
+    }
+}
+
+}; // end of namespace isc::yang
+}; // end of namespace isc
diff --git a/src/lib/yang/translator_shared_network.h b/src/lib/yang/translator_shared_network.h
new file mode 100644 (file)
index 0000000..e39c0df
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef ISC_TRANSLATOR_SHARED_NETWORK_H
+#define ISC_TRANSLATOR_SHARED_NETWORK_H 1
+
+#include <yang/translator.h>
+#include <yang/translator_subnet.h>
+#include <list>
+
+namespace isc {
+namespace yang {
+
+/// Shared network translation between YANG and JSON
+///
+/// JSON syntax for kea-dhcp4 is:
+/// @code
+/// {
+///     "name": <name>,
+///     "subnet4": <subnet list>,
+///     "valid-lifetime": <valid lifetime>,
+///     "renew-timer": <renew timer>,
+///     "rebind-timer": <rebind timer>,
+///     "option-data": [ <list of option data> ],
+///     "interface": "<interface>",
+///     "client-class": "<guard class name>",
+///     "require-client-classes": [ <list of required class names> ],
+///     "reservation-mode": <host reservation mode>,
+///     "relay": <relay ip address(es)>,
+///     "match-client-id": <match client id flag>,
+///     "next-server": "<next server>",
+///     "server-hostname": "<server hostname>",
+///     "boot-file-name": "<boot file name>",
+///     "user-context": { <json map> },
+///     "comment": "<comment>"
+/// }
+/// @endcode
+///
+/// JSON syntax for kea-dhcp6 is:
+/// @code
+/// {
+///     "name": <name>,
+///     "subnet6": <subnet list>,
+///     "preferred-lifetime": <preferred lifetime>,
+///     "valid-lifetime": <valid lifetime>,
+///     "renew-timer": <renew timer>,
+///     "rebind-timer": <rebind timer>,
+///     "option-data": [ <list of option data> ],
+///     "interface": "<interface>",
+///     "interface-id": "<interface id>",
+///     "rapid-commit": <rapid commit flag>,
+///     "client-class": "<guard class name>",
+///     "require-client-classes": [ <list of required class names> ],
+///     "reservation-mode": <host reservation mode>,
+///     "relay": <relay ip address(es)>,
+///     "user-context": { <json map> },
+///     "comment": "<comment>"
+/// }
+/// @endcode
+///
+/// YANG syntax for kea-dhcp[46] is with name as the list key:
+/// @code
+///  +--rw name                      string
+///  +--rw valid-lifetime?           uint32
+///  +--rw renew-timer?              uint32
+///  +--rw rebind-timer?             uint32
+///  +--rw option-data-list          option-data*
+///  +--rw interface?                string
+///  +--rw client-class?             string
+///  +--rw require-client-classes*   string
+///  +--rw reservation-mode?         enumeration
+///  +--rw relay                     ip-addresses*
+///  +--rw user-context?             string
+///  (DHCPv4 only)
+///  +--rw subnet4                   subnet4*
+///  +--rw match-client-id?          boolean
+///  +--rw next-server?              inet:ipv4-address
+///  +--rw server-hostname?          string
+///  +--rw boot-file-name?           string
+///  (DHCPv6 only)
+///  +--rw subnet6                   subnet6*
+///  +--rw preferred-lifetime?       uint32
+///  +--rw interface-id?             string
+///  +--rw rapid-commit?             boolean
+/// @endcode
+///
+/// An example in JSON and YANG formats:
+/// @code
+/// [
+///     {
+///         "name": "foo",
+///         "subnet6":
+///             [
+///                 {
+///                     "subnet": "2001:db8::/48",
+///                     "id": 123
+///                 }
+///             ]
+///     }
+/// ]
+/// @endcode
+/// @code
+///  /kea-dhcp6-server:config (container)
+///  /kea-dhcp6-server:config/shared-networks (container)
+///  /kea-dhcp6-server:config/shared-networks/
+///     shared-network[name='foo'] (list instance)
+///  /kea-dhcp6-server:config/shared-networks/shared-network[name='foo']/
+///     name = foo
+///  /kea-dhcp6-server:config/shared-networks/shared-network[name='foo']/
+///     subnet6 (container)
+///  /kea-dhcp6-server:config/shared-networks/shared-network[name='foo']/
+///     subnet6/subnet6[id='123'] (list instance)
+///  /kea-dhcp6-server:config/shared-networks/shared-network[name='foo']/
+///     subnet6/subnet6[id='123']/id = 123
+///  /kea-dhcp6-server:config/shared-networks/shared-network[name='foo']/
+///     subnet6/subnet6[id='123']/subnet = 2001:db8::/48
+/// @endcode
+
+/// @brief A translator class for converting a shared network between
+/// YANG and JSON.
+///
+/// Currently supports on kea-dhcp[46]-server. Does not exist in
+/// ietf-dhcpv6-server.
+class TranslatorSharedNetwork : virtual public TranslatorSubnets {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param session Sysrepo session.
+    /// @param model Model name.
+    TranslatorSharedNetwork(S_Session session, const std::string& model);
+
+    /// @brief Destructor.
+    virtual ~TranslatorSharedNetwork();
+
+    /// @brief Get and translate a shared network from YANG to JSON.
+    ///
+    /// @param xpath The xpath of the shared network.
+    /// @return JSON representation of the shared network.
+    /// @throw SysrepoError when sysrepo raises an error.
+    isc::data::ElementPtr getSharedNetwork(const std::string& xpath);
+
+    /// @brief Translate and set shared network from JSON to YANG.
+    ///
+    /// @param xpath The xpath of the shared network.
+    /// @param elem The JSON element.
+    void setSharedNetwork(const std::string& xpath,
+                          isc::data::ConstElementPtr elem);
+
+protected:
+    /// @brief getSharedNetwork for kea-dhcp[46].
+    ///
+    /// @param xpath The xpath of the shared network.
+    /// @param subsel The subnet list name.
+    /// @return JSON representation of the shared network.
+    isc::data::ElementPtr getSharedNetworkKea(const std::string& xpath,
+                                              const std::string& subsel);
+
+    /// @brief setSharedNetwork for kea-dhcp[46].
+    ///
+    /// @param xpath The xpath of the shared network.
+    /// @param elem The JSON element.
+    /// @param subsel The subnet list name.
+    void setSharedNetworkKea(const std::string& xpath,
+                             isc::data::ConstElementPtr elem,
+                             const std::string& subsel);
+
+    /// @brief The model.
+    std::string model_;
+};
+
+/// @brief A translator class for converting a shared network list between
+/// YANG and JSON.
+///
+/// Currently supports on kea-dhcp[46]-server. Does not exist in
+/// ietf-dhcpv6-server.
+class TranslatorSharedNetworks : virtual public TranslatorSharedNetwork {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param session Sysrepo session.
+    /// @param model Model name.
+    TranslatorSharedNetworks(S_Session session, const std::string& model);
+
+    /// @brief Destructor.
+    virtual ~TranslatorSharedNetworks();
+
+    /// @brief Get and translate shared networks from YANG to JSON.
+    ///
+    /// @param xpath The xpath of the shared network list.
+    /// @throw SysrepoError when sysrepo raises an error.
+    isc::data::ElementPtr getSharedNetworks(const std::string& xpath);
+
+    /// @brief Translate and set shared networks from JSON to YANG.
+    ///
+    /// @param xpath The xpath of the shared network list.
+    /// @param elem The JSON element.
+    void setSharedNetworks(const std::string& xpath,
+                           isc::data::ConstElementPtr elem);
+
+protected:
+    /// @brief setSharedNetworks for kea-dhcp[46].
+    ///
+    /// @param xpath The xpath of the shared network list.
+    /// @param elem The JSON element.
+    /// @throw BadValue on a shared network without name.
+    void setSharedNetworksKea(const std::string& xpath,
+                              isc::data::ConstElementPtr elem);
+
+    /// @brief The model.
+    std::string model_;
+};
+
+}; // end of namespace isc::yang
+}; // end of namespace isc
+
+#endif // ISC_TRANSLATOR_SHARED_NETWORK_H