--- /dev/null
- 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
--- /dev/null
- 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