diff options
Diffstat (limited to 'src/lib/yang/translator_subnet.cc')
-rw-r--r-- | src/lib/yang/translator_subnet.cc | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/src/lib/yang/translator_subnet.cc b/src/lib/yang/translator_subnet.cc new file mode 100644 index 0000000..126b04d --- /dev/null +++ b/src/lib/yang/translator_subnet.cc @@ -0,0 +1,575 @@ +// Copyright (C) 2018-2021 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/adaptor_pool.h> +#include <yang/translator_subnet.h> +#include <yang/yang_models.h> + +#include <sstream> + +using namespace std; +using namespace isc::data; +using namespace sysrepo; + +namespace isc { +namespace yang { + +TranslatorSubnet::TranslatorSubnet(S_Session session, const string& model) + : TranslatorBasic(session, model), + 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::~TranslatorSubnet() { +} + +ElementPtr +TranslatorSubnet::getSubnet(const string& xpath) { + try { + if (model_ == IETF_DHCPV6_SERVER) { + return (getSubnetIetf6(xpath)); + } else if ((model_ == KEA_DHCP4_SERVER) || + (model_ == KEA_DHCP6_SERVER)) { + return (getSubnetKea(xpath)); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error getting subnet at '" << xpath + << "': " << ex.what()); + } + isc_throw(NotImplemented, + "getSubnet not implemented for the model: " << model_); +} + +ElementPtr +TranslatorSubnet::getSubnetIetf6(const string& xpath) { + ElementPtr result = Element::createMap(); + /// @todo timers + /// @todo: option-data + ConstElementPtr pools = getPools(xpath + "/address-pools"); + if (pools) { + /// Set empty list too. + result->set("pools", pools); + } + pools = getPdPools(xpath + "/pd-pools"); + if (pools && (pools->size() > 0)) { + result->set("pd-pools", pools); + } + ConstElementPtr subnet = getItem(xpath + "/network-prefix"); + if (!subnet) { + isc_throw(BadValue, "getSubnetIetf6 requires network prefix"); + } + result->set("subnet", subnet); + ConstElementPtr id = getItem(xpath + "/network-range-id"); + if (!id) { + isc_throw(BadValue, "getSubnetIetf6 requires network range id"); + } + result->set("id", id); + /// @todo: reservations + /// missing a lot of things + ConstElementPtr description = getItem(xpath + "/network-description"); + /// Adding description if exists. + if (description) { + ElementPtr context = Element::createMap(); + context->set("description", description); + result->set("user-context", context); + } + /// missing a lot of things + if (result->get("pools")) { + AdaptorPool::toSubnet(model_, result, result->get("pools")); + } + return (result); +} + +ElementPtr +TranslatorSubnet::getSubnetKea(const string& xpath) { + ElementPtr result = Element::createMap(); + if (model_ == KEA_DHCP6_SERVER) { + ConstElementPtr preferred = getItem(xpath + "/preferred-lifetime"); + if (preferred) { + result->set("preferred-lifetime", preferred); + } + ConstElementPtr min_pref = getItem(xpath + "/min-preferred-lifetime"); + if (min_pref) { + result->set("min-preferred-lifetime", min_pref); + } + ConstElementPtr max_pref = getItem(xpath + "/max-preferred-lifetime"); + if (max_pref) { + result->set("max-preferred-lifetime", max_pref); + } + } + ConstElementPtr valid = getItem(xpath + "/valid-lifetime"); + if (valid) { + result->set("valid-lifetime", valid); + } + ConstElementPtr min_valid = getItem(xpath + "/min-valid-lifetime"); + if (min_valid) { + result->set("min-valid-lifetime", min_valid); + } + ConstElementPtr max_valid = getItem(xpath + "/max-valid-lifetime"); + if (max_valid) { + result->set("max-valid-lifetime", max_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 calculate = getItem(xpath + "/calculate-tee-times"); + if (calculate) { + result->set("calculate-tee-times", calculate); + } + ConstElementPtr t1_percent = getItem(xpath + "/t1-percent"); + if (t1_percent) { + result->set("t1-percent", t1_percent); + } + ConstElementPtr t2_percent = getItem(xpath + "/t2-percent"); + if (t2_percent) { + result->set("t2-percent", t2_percent); + } + ConstElementPtr options = getOptionDataList(xpath); + if (options && (options->size() > 0)) { + result->set("option-data", options); + } + ConstElementPtr pools = getPools(xpath); + if (pools && (pools->size() > 0)) { + result->set("pools", pools); + } + if (model_ == KEA_DHCP6_SERVER) { + pools = getPdPools(xpath); + if (pools && (pools->size() > 0)) { + result->set("pd-pools", pools); + } + } + ConstElementPtr subnet = getItem(xpath + "/subnet"); + if (!subnet) { + isc_throw(BadValue, "getSubnetKea requires subnet"); + } + result->set("subnet", subnet); + ConstElementPtr interface = getItem(xpath + "/interface"); + if (interface) { + result->set("interface", interface); + } + if (model_ == KEA_DHCP6_SERVER) { + ConstElementPtr interface_id = getItem(xpath + "/interface-id"); + if (interface_id) { + result->set("interface-id", interface_id); + } + } + ConstElementPtr id = getItem(xpath + "/id"); + if (!id) { + isc_throw(BadValue, "getSubnetKea requires id"); + } + result->set("id", id); + if (model_ == KEA_DHCP6_SERVER) { + 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 hosts = getHosts(xpath); + if (hosts && (hosts->size() > 0)) { + result->set("reservations", hosts); + } + 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 (model_ == KEA_DHCP4_SERVER) { + ConstElementPtr match = getItem(xpath + "/match-client-id"); + if (match) { + result->set("match-client-id", match); + } + ConstElementPtr auth = getItem(xpath + "/authoritative"); + if (auth) { + result->set("authoritative", auth); + } + 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 s4o6_if = getItem(xpath + "/subnet-4o6-interface"); + if (s4o6_if) { + result->set("4o6-interface", s4o6_if); + } + ConstElementPtr s4o6_id = getItem(xpath + "/subnet-4o6-interface-id"); + if (s4o6_id) { + result->set("4o6-interface-id", s4o6_id); + } + ConstElementPtr s4o6_sub = getItem(xpath + "/subnet-4o6-subnet"); + if (s4o6_sub) { + result->set("4o6-subnet", s4o6_sub); + } + } + ConstElementPtr context = getItem(xpath + "/user-context"); + if (context) { + result->set("user-context", Element::fromJSON(context->stringValue())); + } + checkAndGetLeaf(result, xpath, "cache-max-age"); + checkAndGetLeaf(result, xpath, "cache-threshold"); + checkAndGetLeaf(result, xpath, "ddns-generated-prefix"); + checkAndGetLeaf(result, xpath, "ddns-override-client-update"); + checkAndGetLeaf(result, xpath, "ddns-override-no-update"); + checkAndGetLeaf(result, xpath, "ddns-qualifying-suffix"); + checkAndGetLeaf(result, xpath, "ddns-replace-client-name"); + checkAndGetLeaf(result, xpath, "ddns-send-updates"); + checkAndGetLeaf(result, xpath, "ddns-update-on-renew"); + checkAndGetLeaf(result, xpath, "ddns-use-conflict-resolution"); + checkAndGetLeaf(result, xpath, "hostname-char-replacement"); + checkAndGetLeaf(result, xpath, "hostname-char-set"); + checkAndGetLeaf(result, xpath, "reservations-global"); + checkAndGetLeaf(result, xpath, "reservations-in-subnet"); + checkAndGetLeaf(result, xpath, "reservations-out-of-pool"); + checkAndGetLeaf(result, xpath, "store-extended-info"); + return (result); +} + +void +TranslatorSubnet::setSubnet(const string& xpath, ConstElementPtr elem) { + try { + if (model_ == IETF_DHCPV6_SERVER) { + setSubnetIetf6(xpath, elem); + } else if ((model_ == KEA_DHCP4_SERVER) || + (model_ == KEA_DHCP6_SERVER)) { + setSubnetKea(xpath, elem); + } else { + isc_throw(NotImplemented, + "setSubnet not implemented for the model: " << model_); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error setting subnet '" << elem->str() + << "' at '" << xpath << "': " << ex.what()); + } +} + +void +TranslatorSubnet::setSubnetIetf6(const string& xpath, ConstElementPtr elem) { + /// Skip id as it is the key. + AdaptorPool::fromSubnet(model_, elem, elem->get("pools")); + ConstElementPtr context = elem->get("user-context"); + if (context && context->contains("description")) { + ConstElementPtr description = context->get("description"); + if (description->getType() == Element::string) { + setItem(xpath + "/network-description", description, SR_STRING_T); + } + } + ConstElementPtr subnet = elem->get("subnet"); + if (!subnet) { + isc_throw(BadValue, "setSubnetIetf6 requires subnet: " << elem->str()); + } + setItem(xpath + "/network-prefix", subnet, SR_STRING_T); + /// @todo option-data + ConstElementPtr pools = elem->get("pools"); + if (pools && (pools->size() > 0)) { + setPools(xpath + "/address-pools", pools); + } + pools = elem->get("pd-pools"); + if (pools && (pools->size() > 0)) { + setPdPools(xpath + "/pd-pools", pools); + } + /// @todo reservations +} + +void +TranslatorSubnet::setSubnetKea(const string& xpath, ConstElementPtr elem) { + /// Skip id as it is the key. + if (model_ == KEA_DHCP6_SERVER) { + ConstElementPtr preferred = elem->get("preferred-lifetime"); + if (preferred) { + setItem(xpath + "/preferred-lifetime", preferred, SR_UINT32_T); + } + ConstElementPtr min_pref = elem->get("min-preferred-lifetime"); + if (min_pref) { + setItem(xpath + "/min-preferred-lifetime", min_pref, SR_UINT32_T); + } + ConstElementPtr max_pref = elem->get("max-preferred-lifetime"); + if (max_pref) { + setItem(xpath + "/max-preferred-lifetime", max_pref, SR_UINT32_T); + } + } + ConstElementPtr valid = elem->get("valid-lifetime"); + if (valid) { + setItem(xpath + "/valid-lifetime", valid, SR_UINT32_T); + } + ConstElementPtr min_valid = elem->get("min-valid-lifetime"); + if (min_valid) { + setItem(xpath + "/min-valid-lifetime", min_valid, SR_UINT32_T); + } + ConstElementPtr max_valid = elem->get("max-valid-lifetime"); + if (max_valid) { + setItem(xpath + "/max-valid-lifetime", max_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 calculate = elem->get("calculate-tee-times"); + if (calculate) { + setItem(xpath + "/calculate-tee-times", calculate, SR_BOOL_T); + } + ConstElementPtr t1_percent = elem->get("t1-percent"); + if (t1_percent) { + setItem(xpath + "/t1-percent", t1_percent, SR_DECIMAL64_T); + } + ConstElementPtr t2_percent = elem->get("t2-percent"); + if (t2_percent) { + setItem(xpath + "/t2-percent", t2_percent, SR_DECIMAL64_T); + } + ConstElementPtr options = elem->get("option-data"); + if (options && (options->size() > 0)) { + setOptionDataList(xpath, options); + } + ConstElementPtr pools = elem->get("pools"); + if (pools && (pools->size() > 0)) { + setPools(xpath, pools); + } + if (model_ == KEA_DHCP6_SERVER) { + pools = elem->get("pd-pools"); + if (pools && (pools->size() > 0)) { + setPdPools(xpath, pools); + } + } + ConstElementPtr subnet = elem->get("subnet"); + if (!subnet) { + isc_throw(BadValue, "setSubnetKea requires subnet: " << elem->str()); + } + setItem(xpath + "/subnet", subnet, SR_STRING_T); + ConstElementPtr interface = elem->get("interface"); + if (interface) { + setItem(xpath + "/interface", interface, SR_STRING_T); + } + if (model_ == KEA_DHCP6_SERVER) { + ConstElementPtr interface_id = elem->get("interface-id"); + if (interface_id) { + setItem(xpath + "/interface-id", interface_id, SR_STRING_T); + } + } + if (model_ == KEA_DHCP6_SERVER) { + 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 hosts = elem->get("reservations"); + if (hosts && (hosts->size() > 0)) { + setHosts(xpath, hosts); + } + 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); + } + } + } + checkAndSetLeaf(elem, xpath, "cache-max-age", SR_UINT32_T); + checkAndSetLeaf(elem, xpath, "cache-threshold", SR_DECIMAL64_T); + checkAndSetLeaf(elem, xpath, "ddns-generated-prefix", SR_STRING_T); + checkAndSetLeaf(elem, xpath, "ddns-override-client-update", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "ddns-override-no-update", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "ddns-qualifying-suffix", SR_STRING_T); + checkAndSetLeaf(elem, xpath, "ddns-replace-client-name", SR_STRING_T); + checkAndSetLeaf(elem, xpath, "ddns-send-updates", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "ddns-update-on-renew", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "ddns-use-conflict-resolution", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "hostname-char-replacement", SR_STRING_T); + checkAndSetLeaf(elem, xpath, "hostname-char-set", SR_STRING_T); + checkAndSetLeaf(elem, xpath, "reservations-global", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "reservations-in-subnet", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "reservations-out-of-pool", SR_BOOL_T); + checkAndSetLeaf(elem, xpath, "store-extended-info", SR_BOOL_T); + if (model_ == KEA_DHCP4_SERVER) { + ConstElementPtr match = elem->get("match-client-id"); + if (match) { + setItem(xpath + "/match-client-id", match, SR_BOOL_T); + } + ConstElementPtr auth = elem->get("authoritative"); + if (auth) { + setItem(xpath + "/authoritative", auth, 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 s4o6_if = elem->get("4o6-interface"); + if (s4o6_if) { + setItem(xpath + "/subnet-4o6-interface", s4o6_if, SR_STRING_T); + } + ConstElementPtr s4o6_id = elem->get("4o6-interface-id"); + if (s4o6_id) { + setItem(xpath + "/subnet-4o6-interface-id", s4o6_id, SR_STRING_T); + } + ConstElementPtr s4o6_subnet = elem->get("4o6-subnet"); + if (s4o6_subnet) { + setItem(xpath + "/subnet-4o6-subnet", s4o6_subnet, SR_STRING_T); + } + } + ConstElementPtr context = Adaptor::getContext(elem); + if (context) { + ConstElementPtr repr = Element::create(context->str()); + setItem(xpath + "/user-context", repr, SR_STRING_T); + } +} + +TranslatorSubnets::TranslatorSubnets(S_Session session, const string& model) + : TranslatorBasic(session, model), + 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::~TranslatorSubnets() { +} + +ElementPtr +TranslatorSubnets::getSubnets(const string& xpath) { + try { + if (model_ == IETF_DHCPV6_SERVER) { + return (getSubnetsCommon(xpath, "network-range")); + } else if (model_ == KEA_DHCP4_SERVER) { + return (getSubnetsCommon(xpath, "subnet4")); + } else if (model_ == KEA_DHCP6_SERVER) { + return (getSubnetsCommon(xpath, "subnet6")); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error getting subnets at '" << xpath + << "': " << ex.what()); + } + isc_throw(NotImplemented, + "getSubnets not implemented for the model: " << model_); +} + +ElementPtr +TranslatorSubnets::getSubnetsCommon(const string& xpath, + const std::string& subsel) { + return getList<TranslatorSubnet>(xpath + "/" + subsel, *this, + &TranslatorSubnet::getSubnet); +} + +void +TranslatorSubnets::setSubnets(const string& xpath, ConstElementPtr elem) { + try { + if (model_ == IETF_DHCPV6_SERVER) { + setSubnetsIetf6(xpath, elem); + } else if (model_ == KEA_DHCP4_SERVER) { + setSubnetsKea(xpath, elem, "subnet4"); + } else if (model_ == KEA_DHCP6_SERVER) { + setSubnetsKea(xpath, elem, "subnet6"); + } else { + isc_throw(NotImplemented, + "setSubnets not implemented for the model: " << model_); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error setting subnets '" << elem->str() + << "' at '" << xpath << "': " << ex.what()); + } +} + +void +TranslatorSubnets::setSubnetsIetf6(const string& xpath, ConstElementPtr elem) { + for (size_t i = 0; i < elem->size(); ++i) { + ConstElementPtr subnet = elem->get(i); + ostringstream range; + range << xpath << "/network-range[network-range-id='"; + ConstElementPtr id = subnet->get("id"); + if (!id) { + isc_throw(BadValue, "subnet without id: " << elem->str()); + } + range << id->intValue() << "']"; + setSubnet(range.str().c_str(), subnet); + } +} + +void +TranslatorSubnets::setSubnetsKea(const string& xpath, ConstElementPtr elem, + const std::string& subsel) { + for (size_t i = 0; i < elem->size(); ++i) { + ConstElementPtr subnet = elem->get(i); + if (!subnet->contains("id")) { + isc_throw(BadValue, "subnet without id: " << subnet->str()); + } + ostringstream prefix; + prefix << xpath << "/" << subsel << "[id='" + << subnet->get("id")->intValue() << "']"; + setSubnet(prefix.str(), subnet); + } +} + +} // namespace yang +} // namespace isc |