mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-05 00:15:17 +00:00
[65-libyang-pd-pool_rebased] Rebased after database translator merge
This commit is contained in:
@@ -16,6 +16,7 @@ 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
|
||||
|
||||
|
||||
@@ -40,6 +41,7 @@ libkea_yang_include_HEADERS = \
|
||||
translator_option_data.h \
|
||||
translator_option_def.h \
|
||||
translator_pool.h \
|
||||
translator_pd_pool.h \
|
||||
yang_models.h
|
||||
|
||||
EXTRA_DIST = yang.dox
|
||||
|
@@ -25,6 +25,7 @@ run_unittests_SOURCES += translator_database_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)
|
||||
|
322
src/lib/yang/tests/translator_pd_pool_unittests.cc
Normal file
322
src/lib/yang/tests/translator_pd_pool_unittests.cc
Normal file
@@ -0,0 +1,322 @@
|
||||
// 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(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(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(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(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(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(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(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
|
366
src/lib/yang/translator_pd_pool.cc
Normal file
366
src/lib/yang/translator_pd_pool.cc
Normal file
@@ -0,0 +1,366 @@
|
||||
// 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 {
|
||||
if (model_ == IETF_DHCPV6_SERVER) {
|
||||
return (getPdPoolIetf6(xpath));
|
||||
} 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 {
|
||||
if (model_ == IETF_DHCPV6_SERVER) {
|
||||
setPdPoolIetf6(xpath, elem);
|
||||
} 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 {
|
||||
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
|
227
src/lib/yang/translator_pd_pool.h
Normal file
227
src/lib/yang/translator_pd_pool.h
Normal file
@@ -0,0 +1,227 @@
|
||||
// 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_PD_POOL_H
|
||||
#define ISC_TRANSLATOR_PD_POOL_H 1
|
||||
|
||||
#include <yang/translator_option_data.h>
|
||||
#include <list>
|
||||
|
||||
namespace isc {
|
||||
namespace yang {
|
||||
|
||||
/// Prefix delegation pool translation between YANG and JSON
|
||||
///
|
||||
/// JSON syntax for both kea-dhcp4 and kea-dhcp6 is:
|
||||
/// @code
|
||||
/// {
|
||||
/// "prefix": <prefix base>,
|
||||
/// "prefix-len": <prefix length>,
|
||||
/// "delegated-len": <delegated length>,
|
||||
/// "excluded-prefix": <excluded prefix>,
|
||||
/// "excluded-prefix-len": <excluded prefix length>,
|
||||
/// "option-data": [ <list of option data> ],
|
||||
/// "client-class": "<guard class name>",
|
||||
/// "require-client-classes": [ <list of required class names> ],
|
||||
/// "user-context": { <json map> },
|
||||
/// "comment": "<comment>"
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// YANG syntax for ietf-dhcpv6-server is with pool-id as the key.
|
||||
/// @code
|
||||
/// +--rw pool-id uint32
|
||||
/// +--rw prefix inet:ipv6-prefix
|
||||
/// +--rw prefix-length uint8
|
||||
/// +--rw valid-lifetime yang:timeticks
|
||||
/// +--rw renew-time yang:timeticks
|
||||
/// +--rw rebind-time yang:timeticks
|
||||
/// +--rw preferred-lifetime yang:timeticks
|
||||
/// +--rw rapid-commit? boolean
|
||||
/// +--rw client-class? string
|
||||
/// +--rw max-pd-space-utilization? threshold
|
||||
/// +--rw option-set-id?
|
||||
/// /server/server-config/option-sets/option-set/option-set-id
|
||||
/// @endcode
|
||||
///
|
||||
/// YANG syntax for kea-dhcp6 is with prefix as the key.
|
||||
/// @code
|
||||
/// +--rw prefix? inet:ipv6-prefix
|
||||
/// +--rw delegated-len? uint8
|
||||
/// +--rw excluded-prefix? inet:ipv6-prefix
|
||||
/// +--rw option-data-list option-data*
|
||||
/// +--rw client-class? string
|
||||
/// +--rw require-client-classes* string
|
||||
/// +--rw user-context? string
|
||||
/// @endcode
|
||||
///
|
||||
/// An example in JSON and YANG formats:
|
||||
/// @code
|
||||
/// [
|
||||
/// {
|
||||
/// "prefix": "2001:db8:0:1000::",
|
||||
/// "prefix-len": 56,
|
||||
/// "delegated-len": 64
|
||||
/// }
|
||||
/// ]
|
||||
/// @endcode
|
||||
/// @code
|
||||
/// /ietf-dhcpv6-server:server (container)
|
||||
/// /ietf-dhcpv6-server:server/server-config (container)
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges (container)
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111'] (list instance)
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111']/network-range-id = 111
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111']/network-prefix = 2001:db8::/48
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111']/pd-pools (container)
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111']/pd-pools/
|
||||
/// pd-pool[pool-id='0'] (list instance)
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges/
|
||||
/// pd-pool[pool-id='0']/pool-id = 0
|
||||
/// network-range[network-range-id='111']/pd-pools/
|
||||
/// pd-pool[pool-id='0']/prefix = 2001:db8:0:1000::/56
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111']/pd-pools/
|
||||
/// pd-pool[pool-id='0']/prefix-length = 56
|
||||
/// /ietf-dhcpv6-server:server/server-config/network-ranges
|
||||
/// network-range[network-range-id='111']/pd-pools/
|
||||
/// pd-pool[pool-id='0']/max-pd-space-utilization = disabled
|
||||
/// @endcode
|
||||
/// @code
|
||||
/// /kea-dhcp6-server:config (container)
|
||||
/// /kea-dhcp6-server:config/subnet6 (container)
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111'] (list instance)
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111']/id = 111
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111']/subnet = 2001:db8::/48
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111']/pd-pools (container)
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111']/pd-pools/
|
||||
/// pd-pool[prefix='2001:db8:0:1000::/56' (list instance)
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111']/pd-pools/
|
||||
/// pd-pool[prefix='2001:db8:0:1000::/56'/prefix = 2001:db8:0:1000::/56
|
||||
/// /kea-dhcp6-server:config/subnet6/subnet6[id='111']/pd-pools/
|
||||
/// pd-pool[prefix='2001:db8:0:1000::/56'/delegated-len = 64
|
||||
/// @endcode
|
||||
|
||||
/// @brief A translator class for converting a pd-pool between
|
||||
/// YANG and JSON.
|
||||
///
|
||||
/// Currently supports on kea-dhcp[46]-server and partially ietf-dhcpv6-server.
|
||||
class TranslatorPdPool : virtual public TranslatorOptionDataList {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param session Sysrepo session.
|
||||
/// @param model Model name.
|
||||
TranslatorPdPool(S_Session session, const std::string& model);
|
||||
|
||||
/// @brief Destructor.
|
||||
virtual ~TranslatorPdPool();
|
||||
|
||||
/// @brief Get and translate a pd-pool from YANG to JSON.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool.
|
||||
/// @return JSON representation of the pd-pool.
|
||||
/// @throw SysrepoError when sysrepo raises an error.
|
||||
/// @throw BadValue on pd-pool without well formed prefix.
|
||||
isc::data::ElementPtr getPdPool(const std::string& xpath);
|
||||
|
||||
/// @brief Translate and set pd-pool from JSON to YANG.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool.
|
||||
/// @param elem The JSON element.
|
||||
void setPdPool(const std::string& xpath, isc::data::ConstElementPtr elem);
|
||||
|
||||
protected:
|
||||
/// @brief getPdPool for ietf-dhcpv6-server.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool.
|
||||
/// @return JSON representation of the pd-pool.
|
||||
/// @throw SysrepoError when sysrepo raises an error.
|
||||
isc::data::ElementPtr getPdPoolIetf6(const std::string& xpath);
|
||||
|
||||
/// @brief setPdPool for ietf-dhcpv6-server.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool.
|
||||
/// @param elem The JSON element.
|
||||
/// @throw BadValue on pd-pool without prefix or prefix length.
|
||||
void setPdPoolIetf6(const std::string& xpath,
|
||||
isc::data::ConstElementPtr elem);
|
||||
|
||||
/// @brief getPdPool for kea-dhcp6.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool.
|
||||
/// @return JSON representation of the pd-pool.
|
||||
/// @throw SysrepoError when sysrepo raises an error.
|
||||
isc::data::ElementPtr getPdPoolKea(const std::string& xpath);
|
||||
|
||||
/// @brief setPdPool for kea-dhcp6.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool.
|
||||
/// @param elem The JSON element.
|
||||
void setPdPoolKea(const std::string& xpath,
|
||||
isc::data::ConstElementPtr elem);
|
||||
|
||||
/// @brief The model.
|
||||
std::string model_;
|
||||
};
|
||||
|
||||
/// @brief A translator class for converting a pd-pool list between
|
||||
/// YANG and JSON.
|
||||
///
|
||||
/// Currently supports on kea-dhcp[46]-server and partially ietf-dhcpv6-server.
|
||||
class TranslatorPdPools : virtual public TranslatorPdPool {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param session Sysrepo session.
|
||||
/// @param model Model name.
|
||||
TranslatorPdPools(S_Session session, const std::string& model);
|
||||
|
||||
/// @brief Destructor.
|
||||
virtual ~TranslatorPdPools();
|
||||
|
||||
/// @brief Get and translate pd-pools from YANG to JSON.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool list.
|
||||
/// @throw SysrepoError when sysrepo raises an error.
|
||||
isc::data::ElementPtr getPdPools(const std::string& xpath);
|
||||
|
||||
/// @brief Translate and set pd-pools from JSON to YANG.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool list.
|
||||
/// @param elem The JSON element.
|
||||
void setPdPools(const std::string& xpath, isc::data::ConstElementPtr elem);
|
||||
|
||||
protected:
|
||||
/// @brief setPdPools using pool-id.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool list.
|
||||
/// @param elem The JSON element.
|
||||
void setPdPoolsId(const std::string& xpath,
|
||||
isc::data::ConstElementPtr elem);
|
||||
|
||||
/// @brief setPdPools using prefix.
|
||||
///
|
||||
/// @param xpath The xpath of the pd-pool list.
|
||||
/// @param elem The JSON element.
|
||||
/// @throw BadValue on pd-pool without prefix or prefix length.
|
||||
void setPdPoolsPrefix(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_PD_POOL_H
|
Reference in New Issue
Block a user