// 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 #include #include #include #include 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: no prefix defined at " << xpath); } 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(length); result->set("prefix-len", Element::create(static_cast(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(xlength); result->set("excluded-prefix-len", Element::create(static_cast(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