]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[65-libyang-pd-pool_rebased] Updated after pool merge
authorFrancis Dupont <fdupont@isc.org>
Sat, 6 Oct 2018 10:17:16 +0000 (12:17 +0200)
committerFrancis Dupont <fdupont@isc.org>
Sat, 6 Oct 2018 10:17:16 +0000 (12:17 +0200)
1  2 
src/lib/yang/Makefile.am
src/lib/yang/tests/Makefile.am
src/lib/yang/tests/translator_pd_pool_unittests.cc
src/lib/yang/translator_pd_pool.cc

index bc7d227481b8830a6180724b4951f3ea481c1101,1310f192e8649f813717c01339fa8fa8c300c16a..818de2193855596102b8af08ff05999b2ee03587
@@@ -12,8 -12,7 +12,9 @@@ libkea_yang_la_SOURCES += translator_op
  libkea_yang_la_SOURCES += translator_option_data.h
  libkea_yang_la_SOURCES += translator_option_def.cc
  libkea_yang_la_SOURCES += translator_option_def.h
 +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 += yang_models.h
  
  libkea_yang_la_LIBADD =  $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
  libkea_yang_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
@@@ -33,7 -32,7 +34,9 @@@ libkea_yang_include_HEADERS = 
        translator.h \
        translator_option_data.h \
        translator_option_def.h \
-       translator_pool.h
 -      translator_pd_pool.h
++      translator_pool.h \
++      translator_pd_pool.h \
++      yang_models.h
  
  EXTRA_DIST = yang.dox
  # Distribute yang models.
index 58018a599b0600a22723208167277bf661f90466,3c1cca0ae2c92dc85775aa0837407f81a9953226..9c3aaee9f46d032d76073fe244cf35b5123a70a5
@@@ -22,7 -22,7 +22,8 @@@ run_unittests_SOURCES += sysrepo_setup.
  run_unittests_SOURCES += translator_unittests.cc
  run_unittests_SOURCES += translator_option_data_unittests.cc
  run_unittests_SOURCES += translator_option_def_unittests.cc
 +run_unittests_SOURCES += translator_pool_unittests.cc
+ run_unittests_SOURCES += translator_pd_pool_unittests.cc
  run_unittests_SOURCES += run_unittests.cc
  run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
  run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
index 0000000000000000000000000000000000000000,7869bc06d92600982f0c1c7d87318e9889c298f4..dc703c7f7a352cb2b0fb142d1220582599a1ba8c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,321 +1,322 @@@
 -    useModel("ietf-dhcpv6-server");
+ // 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_pd_pool.h>
++#include <yang/yang_models.h>
+ #include <yang/tests/sysrepo_setup.h>
+ #include <gtest/gtest.h>
+ #include <sstream>
+ 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 pd_pool_list[] = "pd pool list";
+ /// @brief Test fixture class for @ref TranslatorPdPools.
+ class TranslatorPdPoolsTest :
+     public GenericTranslatorTest<pd_pool_list, TranslatorPdPools> {
+ public:
+     /// Constructor.
+     TranslatorPdPoolsTest() { }
+     /// Destructor (does nothing).
+     virtual ~TranslatorPdPoolsTest() { }
+ };
+ // This test verifies that an empty pd pool list can be properly
+ // translated from YANG to JSON using the IETF model.
+ TEST_F(TranslatorPdPoolsTest, getEmptyIetf) {
 -    useModel("kea-dhcp6-server");
++    useModel(IETF_DHCPV6_SERVER);
+     // Get the pd-pool list and checks it is empty.
+     const string& xpath =
+         "/ietf-dhcpv6-server:server/server-config/network-ranges"
+         "/network-range[network-range-id='111']/pd-pools";
+     ConstElementPtr pools;
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     EXPECT_EQ(0, pools->size());
+ }
+ // This test verifies that an empty pd pool list can be properly
+ // translated from YANG to JSON using the Kea ad hoc model.
+ TEST_F(TranslatorPdPoolsTest, getEmptyKea) {
 -    useModel("ietf-dhcpv6-server");
++    useModel(KEA_DHCP6_SERVER);
+     // Get the pd-pool list and checks it is empty.
+     const string& xpath =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']/pd-pools";
+     ConstElementPtr pools;
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     EXPECT_EQ(0, pools->size());
+ }
+ // This test verifies that one empty pd pool can be properly
+ // translated from YANG to JSON using the IETF model.
+ TEST_F(TranslatorPdPoolsTest, getIetf) {
 -    useModel("kea-dhcp6-server");
++    useModel(IETF_DHCPV6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/ietf-dhcpv6-server:server/server-config/network-ranges"
+         "/network-range[network-range-id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& subnet_subnet = subnet + "/network-prefix";
+     EXPECT_NO_THROW(sess_->set_item(subnet_subnet.c_str(), v_subnet));
+     // Create the pd-pool 2001:db8:0:1000::/64 #222.
+     const string& xpath = subnet + "/pd-pools/pd-pool[pool-id='222']";
+     const string& prefix = xpath + "/prefix";
+     S_Val s_prefix(new Val("2001:db8:0:1000::/56"));
+     EXPECT_NO_THROW(sess_->set_item(prefix.c_str(), s_prefix));
+     const string& length = xpath + "/prefix-length";
+     uint8_t len = 56;
+     S_Val s_length(new Val(len, SR_UINT8_T));
+     EXPECT_NO_THROW(sess_->set_item(length.c_str(), s_length));
+     // Get the pool.
+     ConstElementPtr pool;
+     EXPECT_NO_THROW(pool = t_obj_->getPdPool(xpath));
+     ASSERT_TRUE(pool);
+     ElementPtr expected = Element::createMap();
+     expected->set("prefix", Element::create(string("2001:db8:0:1000::")));
+     expected->set("prefix-len", Element::create(56));
+     EXPECT_TRUE(expected->equals(*pool));
+     // Get the pd-pool list and checks the pd-pool is in it.
+     ConstElementPtr pools;
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(subnet + "/pd-pools"));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     ASSERT_EQ(1, pools->size());
+     EXPECT_TRUE(pool->equals(*pools->get(0)));
+ }
+ // This test verifies that one empty pd pool can be properly
+ // translated from YANG to JSON using the Kea ad hoc model.
+ TEST_F(TranslatorPdPoolsTest, getKea) {
 -    useModel("ietf-dhcpv6-server");
++    useModel(KEA_DHCP6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& subnet_subnet = subnet + "/subnet";
+     EXPECT_NO_THROW(sess_->set_item(subnet_subnet.c_str(), v_subnet));
+     // Create the pd-pool 2001:db8:0:1000::/64.
+     const string& xpath = subnet + "/pd-pools";
+     const string& prefix = "2001:db8:0:1000::/56";
+     ostringstream spool;
+     spool << xpath + "/pd-pool[prefix='" << prefix << "']";
+     const string& x_delegated = spool.str() + "/delegated-len";
+     uint8_t dl = 64;
+     S_Val s_delegated(new Val(dl, SR_UINT8_T));
+     EXPECT_NO_THROW(sess_->set_item(x_delegated.c_str(), s_delegated));
+     // Get the pool.
+     ConstElementPtr pool;
+     EXPECT_NO_THROW(pool = t_obj_->getPdPool(spool.str()));
+     ASSERT_TRUE(pool);
+     ElementPtr expected = Element::createMap();
+     expected->set("prefix", Element::create(string("2001:db8:0:1000::")));
+     expected->set("prefix-len", Element::create(56));
+     expected->set("delegated-len", Element::create(64));
+     EXPECT_TRUE(expected->equals(*pool));
+     // Get the pd-pool list and checks the pd-pool is in it.
+     ConstElementPtr pools;
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     ASSERT_EQ(1, pools->size());
+     EXPECT_TRUE(pool->equals(*pools->get(0)));
+ }
+ // This test verifies that an empty pd pool list can be properly
+ // translated from JSON to YANG using the IETF model.
+ TEST_F(TranslatorPdPoolsTest, setEmptyIetf) {
 -    useModel("kea-dhcp6-server");
++    useModel(IETF_DHCPV6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/ietf-dhcpv6-server:server/server-config/network-ranges"
+         "/network-range[network-range-id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& subnet_subnet = subnet + "/network-prefix";
+     EXPECT_NO_THROW(sess_->set_item(subnet_subnet.c_str(), v_subnet));
+     // Set empty list.
+     const string& xpath = subnet + "/pd-pools";
+     ConstElementPtr pools = Element::createList();
+     EXPECT_NO_THROW(t_obj_->setPdPools(xpath, pools));
+     // Get it back.
+     pools.reset();
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     EXPECT_EQ(0, pools->size());
+ }
+ // This test verifies that an empty pd pool list can be properly
+ // translated from JSON to YANG using the Kea ad hoc model.
+ TEST_F(TranslatorPdPoolsTest, setEmptyKea) {
 -    useModel("ietf-dhcpv6-server");
++    useModel(KEA_DHCP6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& subnet_subnet = subnet + "/subnet";
+     EXPECT_NO_THROW(sess_->set_item(subnet_subnet.c_str(), v_subnet));
+     // Set empty list.
+     const string& xpath = subnet + "/pd-pools";
+     ConstElementPtr pools = Element::createList();
+     EXPECT_NO_THROW(t_obj_->setPdPools(xpath, pools));
+     // Get it back.
+     pools.reset();
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     EXPECT_EQ(0, pools->size());
+ }
+ // This test verifies that one pd pool can be properly
+ // translated from JSON to YANG using the IETF model.
+ TEST_F(TranslatorPdPoolsTest, setIetf) {
 -    useModel("kea-dhcp6-server");
++    useModel(IETF_DHCPV6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/ietf-dhcpv6-server:server/server-config/network-ranges"
+         "/network-range[network-range-id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& subnet_subnet = subnet + "/network-prefix";
+     EXPECT_NO_THROW(sess_->set_item(subnet_subnet.c_str(), v_subnet));
+     // Set one pool.
+     const string& xpath = subnet + "/pd-pools";
+     ElementPtr pools = Element::createList();
+     ElementPtr pool = Element::createMap();
+     pool->set("prefix", Element::create(string("2001:db8:0:1000::")));
+     pool->set("prefix-len", Element::create(56));
+     pools->add(pool);
+     EXPECT_NO_THROW(t_obj_->setPdPools(xpath, pools));
+     // Get it back.
+     pools.reset();
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     ASSERT_EQ(1, pools->size());
+     EXPECT_TRUE(pool->equals(*pools->get(0)));
+     // Check the tree representation.
+     S_Tree tree;
+     EXPECT_NO_THROW(tree = sess_->get_subtree("/ietf-dhcpv6-server:server"));
+     ASSERT_TRUE(tree);
+     string expected =
+         "ietf-dhcpv6-server:server (container)\n"
+         " |\n"
+         " -- server-config (container)\n"
+         "     |\n"
+         "     -- network-ranges (container)\n"
+         "         |\n"
+         "         -- network-range (list instance)\n"
+         "             |\n"
+         "             -- network-range-id = 111\n"
+         "             |\n"
+         "             -- network-prefix = 2001:db8::/48\n"
+         "             |\n"
+         "             -- pd-pools (container)\n"
+         "                 |\n"
+         "                 -- pd-pool (list instance)\n"
+         "                     |\n"
+         "                     -- pool-id = 0\n"
+         "                     |\n"
+         "                     -- prefix = 2001:db8:0:1000::/56\n"
+         "                     |\n"
+         "                     -- prefix-length = 56\n"
+         "                     |\n"
+         "                     -- max-pd-space-utilization = disabled\n";
+     EXPECT_EQ(expected, tree->to_string(100));
+ }
+ // This test verifies that one pd pool can be properly
+ // translated from JSON to YANG using the kea ad hoc model.
+ TEST_F(TranslatorPdPoolsTest, setKea) {
++    useModel(KEA_DHCP6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& subnet_subnet = subnet + "/subnet";
+     EXPECT_NO_THROW(sess_->set_item(subnet_subnet.c_str(), v_subnet));
+     // Set one pool.
+     const string& xpath = subnet + "/pd-pools";
+     ElementPtr pools = Element::createList();
+     ElementPtr pool = Element::createMap();
+     pool->set("prefix", Element::create(string("2001:db8:0:1000::")));
+     pool->set("prefix-len", Element::create(56));
+     pool->set("delegated-len", Element::create(64));
+     pools->add(pool);
+     EXPECT_NO_THROW(t_obj_->setPdPools(xpath, pools));
+     // Get it back.
+     pools.reset();
+     EXPECT_NO_THROW(pools = t_obj_->getPdPools(xpath));
+     ASSERT_TRUE(pools);
+     ASSERT_EQ(Element::list, pools->getType());
+     ASSERT_EQ(1, pools->size());
+     EXPECT_TRUE(pool->equals(*pools->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"
+         " -- subnet6 (container)\n"
+         "     |\n"
+         "     -- subnet6 (list instance)\n"
+         "         |\n"
+         "         -- id = 111\n"
+         "         |\n"
+         "         -- subnet = 2001:db8::/48\n"
+         "         |\n"
+         "         -- pd-pools (container)\n"
+         "             |\n"
+         "             -- pd-pool (list instance)\n"
+         "                 |\n"
+         "                 -- prefix = 2001:db8:0:1000::/56\n"
+         "                 |\n"
+         "                 -- delegated-len = 64\n";
+     EXPECT_EQ(expected, tree->to_string(100));
+     // Check it validates.
+     EXPECT_NO_THROW(sess_->validate());
+ }
+ }; // end of anonymous namespace
index 0000000000000000000000000000000000000000,c700fc4e22b1e11f9417dacdb53c1a8cd3123259..16636e3f5bc2cb2262f36debe85d1d2f208a771d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,365 +1,366 @@@
 -        if (model_ == "ietf-dhcpv6-server") {
+ // 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/adaptor.h>
+ #include <yang/translator_pd_pool.h>
++#include <yang/yang_models.h>
+ #include <boost/lexical_cast.hpp>
+ #include <sstream>
+ using namespace std;
+ using namespace isc::data;
+ namespace isc {
+ namespace yang {
+ TranslatorPdPool::TranslatorPdPool(S_Session session, const string& model)
+     : TranslatorBasic(session),
+       TranslatorOptionData(session, model),
+       TranslatorOptionDataList(session, model),
+       model_(model) {
+ }
+ TranslatorPdPool::~TranslatorPdPool() {
+ }
+ ElementPtr
+ TranslatorPdPool::getPdPool(const string& xpath) {
+     try {
 -        } else if (model_ == "kea-dhcp6-server") {
++        if (model_ == IETF_DHCPV6_SERVER) {
+             return (getPdPoolIetf6(xpath));
 -        if (model_ == "ietf-dhcpv6-server") {
++        } else if (model_ == KEA_DHCP6_SERVER) {
+             return (getPdPoolKea(xpath));
+         }
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error getting pd-pool at '" << xpath
+                   << "': " << ex.what());
+     }
+     isc_throw(NotImplemented,
+               "getPdPool not implemented for the model: " << model_);
+ }
+ ElementPtr
+ TranslatorPdPool::getPdPoolIetf6(const string& xpath) {
+     ElementPtr result = Element::createMap();
+     ConstElementPtr pref = getItem(xpath + "/prefix");
+     if (!pref) {
+         isc_throw(BadValue, "getPdPoolIetf6: prefix is required");
+     }
+     const string& prefix = pref->stringValue();
+     size_t slash = prefix.find("/");
+     if (slash == string::npos) {
+         isc_throw(BadValue,
+                   "getPdPoolIetf6: no '/' in prefix '" << prefix << "'");
+     }
+     const string& address = prefix.substr(0, slash);
+     if (address.empty()) {
+         isc_throw(BadValue,
+                   "getPdPoolIetf6: malformed prefix '" << prefix << "'");
+     }
+     result->set("prefix", Element::create(address));
+     // Silly: the prefix length is specified twice...
+     ConstElementPtr preflen = getItem(xpath + "/prefix-length");
+     if (!preflen) {
+         isc_throw(BadValue, "getPdPoolIetf6: prefix length is required");
+     }
+     result->set("prefix-len", preflen);
+     ConstElementPtr valid_lifetime = getItem(xpath + "/valid-lifetime");
+     if (valid_lifetime) {
+         result->set("valid-lifetime", valid_lifetime);
+     }
+     ConstElementPtr preferred_lifetime =
+         getItem(xpath + "/preferred-lifetime");
+     if (preferred_lifetime) {
+         result->set("preferred-lifetime", preferred_lifetime);
+     }
+     ConstElementPtr renew_time = getItem(xpath + "/renew-time");
+     if (renew_time) {
+         result->set("renew-timer", renew_time);
+     }
+     ConstElementPtr rebind_time = getItem(xpath + "/rebind-time");
+     if (rebind_time) {
+         result->set("rebind-timer", rebind_time);
+     }
+     // Skip rapid-commit.
+     ConstElementPtr guard = getItem(xpath + "/client-class");
+     if (guard) {
+         result->set("client-class", guard);
+     }
+     // no require-client-classes nor user-context.
+     // Skip max-pd-space-utilization.
+     // @todo option-data.
+     return (result);
+ }
+ ElementPtr
+ TranslatorPdPool::getPdPoolKea(const string& xpath) {
+     ElementPtr result = Element::createMap();
+     ConstElementPtr pref = getItem(xpath + "/prefix");
+     if (!pref) {
+         isc_throw(BadValue, "getPdPoolKea: prefix is required");
+     }
+     const string& prefix = pref->stringValue();
+     size_t slash = prefix.find("/");
+     if (slash == string::npos) {
+         isc_throw(BadValue,
+                   "getPdPoolKea: no '/' in prefix '" << prefix << "'");
+     }
+     const string& address = prefix.substr(0, slash);
+     const string& length = prefix.substr(slash + 1, string::npos);
+     if (address.empty() || length.empty()) {
+         isc_throw(BadValue,
+                   "getPdPoolKea: malformed prefix '" << prefix << "'");
+     }
+     result->set("prefix", Element::create(address));
+     try {
+         unsigned len = boost::lexical_cast<unsigned>(length);
+         result->set("prefix-len", Element::create(static_cast<int>(len)));
+     } catch (const boost::bad_lexical_cast&) {
+         isc_throw(BadValue,
+                   "getPdPoolKea: bad prefix length in '" << prefix << "'");
+     }
+     ConstElementPtr xpref = getItem(xpath + "/excluded-prefix");
+     if (xpref) {
+         const string& xprefix = xpref->stringValue();
+         size_t xslash = xprefix.find("/");
+         if (xslash == string::npos) {
+             isc_throw(BadValue,
+                       "getPdPoolKea: no '/' in excluded prefix '"
+                       << xprefix << "'");
+         }
+         const string& xaddress = xprefix.substr(0, xslash);
+         const string& xlength = xprefix.substr(xslash + 1, string::npos);
+         if (xaddress.empty() || xlength.empty()) {
+             isc_throw(BadValue,
+                       "getPdPoolKea: malformed excluded prefix '"
+                       << xprefix << "'");
+         }
+         result->set("excluded-prefix", Element::create(xaddress));
+         try {
+             unsigned xlen = boost::lexical_cast<unsigned>(xlength);
+             result->set("excluded-prefix-len",
+                         Element::create(static_cast<int>(xlen)));
+         } catch (const boost::bad_lexical_cast&) {
+             isc_throw(BadValue,
+                       "getPdPoolKea: bad excluded prefix length in '"
+                       << xprefix << "'");
+         }
+     }
+     ConstElementPtr delegated = getItem(xpath + "/delegated-len");
+     if (delegated) {
+         result->set("delegated-len", delegated);
+     }
+     ConstElementPtr options = getOptionDataList(xpath + "/option-data-list");
+     if (options && (options->size() > 0)) {
+         result->set("option-data", options);
+     }
+     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 context = getItem(xpath + "/user-context");
+     if (context) {
+         result->set("user-context", Element::fromJSON(context->stringValue()));
+     }
+     return (result);
+ }
+ void
+ TranslatorPdPool::setPdPool(const string& xpath, ConstElementPtr elem) {
+     try {
 -        } else if (model_ == "kea-dhcp6-server") {
++        if (model_ == IETF_DHCPV6_SERVER) {
+             setPdPoolIetf6(xpath, elem);
 -        if (model_ == "ietf-dhcpv6-server") {
++        } else if (model_ == KEA_DHCP6_SERVER) {
+             setPdPoolKea(xpath, elem);
+         } else {
+             isc_throw(NotImplemented,
+                       "setPdPool not implemented for the model: " << model_);
+         }
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error setting pd-pool '" << elem->str()
+                   << "' at '" << xpath << "': " << ex.what());
+     }
+ }
+ void
+ TranslatorPdPool::setPdPoolIetf6(const string& xpath, ConstElementPtr elem) {
+     ConstElementPtr base = elem->get("prefix");
+     ConstElementPtr length = elem->get("prefix-len");
+     if (!base || !length) {
+         isc_throw(BadValue,
+                   "setPdPoolIetf6 requires prefix and prefix length: "
+                   << elem->str());
+     }
+     ostringstream prefix;
+     prefix << base->stringValue() << "/" << length->intValue();
+     setItem(xpath + "/prefix", Element::create(prefix.str()), SR_STRING_T);
+     setItem(xpath + "/prefix-length", length, SR_UINT8_T);
+     ConstElementPtr valid_lifetime = elem->get("valid-lifetime");
+     if (valid_lifetime) {
+         setItem(xpath + "/valid-lifetime", valid_lifetime, SR_UINT32_T);
+     }
+     ConstElementPtr preferred_lifetime = elem->get("preferred-lifetime");
+     if (preferred_lifetime) {
+         setItem(xpath + "/preferred-lifetime",
+                 preferred_lifetime, SR_UINT32_T);
+     }
+     ConstElementPtr renew_timer = elem->get("renew-timer");
+     if (renew_timer) {
+         setItem(xpath + "/renew-time", renew_timer, SR_UINT32_T);
+     }
+     ConstElementPtr rebind_timer = elem->get("rebind-timer");
+     if (rebind_timer) {
+         setItem(xpath + "/rebind-time", rebind_timer, SR_UINT32_T);
+     }
+     // Skip rapid-commit.
+     ConstElementPtr guard = elem->get("client-class");
+     if (guard) {
+         setItem(xpath + "/client-class", guard, SR_STRING_T);
+     }
+     // Set max pd space utilization to disabled.
+     setItem(xpath + "/max-pd-space-utilization",
+             Element::create(string("disabled")),
+             SR_ENUM_T);
+     // @todo option-data.
+ }
+ void
+ TranslatorPdPool::setPdPoolKea(const string& xpath, ConstElementPtr elem) {
+     // Skip prefix as it is the key.
+     bool created = false;
+     ConstElementPtr delegated = elem->get("delegated-len");
+     if (delegated) {
+         setItem(xpath + "/delegated-len", delegated, SR_UINT8_T);
+     }
+     ConstElementPtr xprefix = elem->get("excluded-prefix");
+     ConstElementPtr xlen = elem->get("excluded-prefix-len");
+     if (xprefix && xlen) {
+         ostringstream xpref;
+         xpref << xprefix->stringValue() << "/" << xlen->intValue();
+         setItem(xpath + "/excluded-prefix", Element::create(xpref.str()),
+                 SR_STRING_T);
+         created = true;
+     }
+     ConstElementPtr options = elem->get("option-data");
+     if (options && (options->size() > 0)) {
+         setOptionDataList(xpath + "/option-data-list", options);
+         created = true;
+     }
+     ConstElementPtr guard = elem->get("client-class");
+     if (guard) {
+         setItem(xpath + "/client-class", guard, SR_STRING_T);
+         created = true;
+     }
+     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);
+             created = true;
+         }
+     }
+     ConstElementPtr context = Adaptor::getContext(elem);
+     if (context) {
+         setItem(xpath + "/user-context", Element::create(context->str()),
+                 SR_STRING_T);
+         created = true;
+     }
+     // There is no mandatory fields outside the keys so force creation.
+     if (!created) {
+         ConstElementPtr list = Element::createList();
+         setItem(xpath, list, SR_LIST_T);
+     }
+ }
+ TranslatorPdPools::TranslatorPdPools(S_Session session, const string& model)
+     : TranslatorBasic(session),
+       TranslatorOptionData(session, model),
+       TranslatorOptionDataList(session, model),
+       TranslatorPdPool(session, model),
+       model_(model) {
+ }
+ TranslatorPdPools::~TranslatorPdPools() {
+ }
+ ElementPtr
+ TranslatorPdPools::getPdPools(const string& xpath) {
+     try {
+         ElementPtr result = Element::createList();
+         S_Iter_Value iter = getIter(xpath + "/*");
+         if (!iter) {
+             // Can't happen.
+             isc_throw(Unexpected, "getPdPools: can't get iterator: " << xpath);
+         }
+         for (;;) {
+             const string& pool = getNext(iter);
+             if (pool.empty()) {
+                 break;
+             }
+             result->add(getPdPool(pool));
+         }
+         return (result);
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error getting pd-pools at '" << xpath
+                   << "': " << ex.what());
+     }
+ }
+ void
+ TranslatorPdPools::setPdPools(const string& xpath, ConstElementPtr elem) {
+     try {
 -        } else if (model_ == "kea-dhcp6-server") {
++        if (model_ == IETF_DHCPV6_SERVER) {
+             setPdPoolsId(xpath, elem);
++        } else if (model_ == KEA_DHCP6_SERVER) {
+             setPdPoolsPrefix(xpath, elem);
+         } else {
+             isc_throw(NotImplemented,
+                       "setPdPools not implemented for the model: " << model_);
+         }
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error setting pools '" << elem->str()
+                   << "' at '" << xpath << "': " << ex.what());
+     }
+ }
+ void
+ TranslatorPdPools::setPdPoolsId(const string& xpath, ConstElementPtr elem) {
+     for (size_t i = 0; i < elem->size(); ++i) {
+         ConstElementPtr pool = elem->get(i);
+         ostringstream prefix;
+         prefix << xpath << "/pd-pool[pool-id='" << i << "']";
+         setPdPool(prefix.str(), pool);
+     }
+ }
+ void
+ TranslatorPdPools::setPdPoolsPrefix(const string& xpath,
+                                     ConstElementPtr elem) {
+     for (size_t i = 0; i < elem->size(); ++i) {
+         ConstElementPtr pool = elem->get(i);
+         if (!pool->contains("prefix") || !pool->contains("prefix-len")) {
+             isc_throw(BadValue, "pd-pool requires prefix and prefix length: "
+                       << pool->str());
+         }
+         ostringstream prefix;
+         prefix << xpath << "/pd-pool[prefix='"
+                << pool->get("prefix")->stringValue() << "/"
+                << pool->get("prefix-len")->intValue() << "']";
+         setPdPool(prefix.str(), pool);
+     }
+ }
+ }; // end of namespace isc::yang
+ }; // end of namespace isc