1. Create a free_ru_session_list() function to free the memory allocated for the connected RUs before closing the nr-softmodem. 2. xmlReadMemory() and xmlNodeGetContent() were causing serious memory leakages, and now all is properly freed using xmlFreeDoc() and xmlFree().
165 lines
6.7 KiB
C
165 lines
6.7 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
#include "get-yang.h"
|
|
#include "../rpc-send-recv.h"
|
|
#include "common/utils/assertions.h"
|
|
|
|
#include <libxml/parser.h>
|
|
|
|
static bool store_schemas(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx)
|
|
{
|
|
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
|
NC_WD_MODE wd = NC_WD_ALL;
|
|
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
|
LYS_INFORMAT ly_format = LYS_IN_YANG;
|
|
|
|
#ifdef MPLANE_V1
|
|
*ctx = ly_ctx_new(NULL, 0);
|
|
#elif defined MPLANE_V2
|
|
ly_ctx_new(NULL, 0, ctx);
|
|
#endif
|
|
|
|
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
|
|
if (strcmp((const char *)cur_node->name, "schema") == 0) {
|
|
|
|
xmlNode *name_node = xmlFirstElementChild(cur_node);
|
|
xmlChar *module_name = xmlNodeGetContent(name_node);
|
|
xmlNode *revision_node = xmlNextElementSibling(name_node);
|
|
xmlChar *module_revision = xmlNodeGetContent(revision_node);
|
|
xmlNode *format_node = xmlNextElementSibling(revision_node);
|
|
xmlChar *module_format = xmlNodeGetContent(format_node);
|
|
|
|
if (strcmp((char*)module_format, "yang") != 0) {
|
|
xmlFree(module_name);
|
|
xmlFree(module_revision);
|
|
xmlFree(module_format);
|
|
continue;
|
|
}
|
|
|
|
MP_LOG_I("RPC request to RU \"%s\" = <get-schema> for module \"%s\".\n", ru_session->ru_ip_add, module_name);
|
|
struct nc_rpc *get_schema_rpc = nc_rpc_getschema((char*)module_name, (char*)module_revision, "yang", param);
|
|
char *schema_data = NULL;
|
|
bool success = rpc_send_recv((struct nc_session *)ru_session->session, get_schema_rpc, wd, timeout, &schema_data);
|
|
if (!success) {
|
|
MP_LOG_W("[MPLANE] Unable to get schema for module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add);
|
|
xmlFree(module_name);
|
|
xmlFree(module_revision);
|
|
xmlFree(module_format);
|
|
return false;
|
|
}
|
|
|
|
if (schema_data) {
|
|
#ifdef MPLANE_V1
|
|
const struct lys_module *mod = lys_parse_mem(*ctx, schema_data, ly_format);
|
|
#elif defined MPLANE_V2
|
|
struct lys_module *mod = NULL;
|
|
lys_parse_mem(*ctx, schema_data, ly_format, &mod);
|
|
#endif
|
|
free(schema_data);
|
|
if (!mod) {
|
|
MP_LOG_W("Unable to load module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add);
|
|
nc_rpc_free(get_schema_rpc);
|
|
#ifdef MPLANE_V1
|
|
ly_ctx_destroy(*ctx, NULL);
|
|
#elif defined MPLANE_V2
|
|
ly_ctx_destroy(*ctx);
|
|
#endif
|
|
xmlFree(module_name);
|
|
xmlFree(module_revision);
|
|
xmlFree(module_format);
|
|
return false;
|
|
}
|
|
}
|
|
nc_rpc_free(get_schema_rpc);
|
|
xmlFree(module_name);
|
|
xmlFree(module_revision);
|
|
xmlFree(module_format);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool load_from_operational_ds(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx)
|
|
{
|
|
for (xmlNode *schemas_node = node; schemas_node; schemas_node = schemas_node->next) {
|
|
if(schemas_node->type != XML_ELEMENT_NODE)
|
|
continue;
|
|
if (strcmp((const char *)schemas_node->name, "schemas") == 0) {
|
|
return store_schemas(schemas_node->children, ru_session, ctx);
|
|
} else {
|
|
bool success = load_from_operational_ds(schemas_node->children, ru_session, ctx);
|
|
if (success)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool load_yang_models(ru_session_t *ru_session, const char *buffer)
|
|
{
|
|
struct ly_ctx **ctx = (struct ly_ctx **)&ru_session->ctx;
|
|
|
|
// Initialize the xml file
|
|
size_t len = strlen(buffer) + 1;
|
|
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
|
|
xmlNode *root_element = xmlDocGetRootElement(doc);
|
|
|
|
bool success = load_from_operational_ds(root_element->children, ru_session, ctx);
|
|
xmlFreeDoc(doc);
|
|
if (success) {
|
|
MP_LOG_I("Successfully loaded all yang modules from operational datastore for RU \"%s\".\n", ru_session->ru_ip_add);
|
|
return true;
|
|
} else {
|
|
MP_LOG_W("Unable to load all yang modules from operational datastore for RU \"%s\". Using yang models present in \"models\" subfolder.\n", ru_session->ru_ip_add);
|
|
}
|
|
|
|
/* ideally, we should load the yang models from the operational datastore, but the issues are following:
|
|
1) the yang models order is not good - the dependancy models have to be loaded first
|
|
2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) */
|
|
const char *yang_dir = YANG_MODELS;
|
|
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-wg4-features", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "ietf-crypto-types", "o-ran-usermgmt", "o-ran-processing-element", "o-ran-hardware", "o-ran-common-yang-types", "o-ran-delay-management", "o-ran-uplane-conf", "ietf-netconf-acm", "o-ran-file-management", "o-ran-performance-management"};
|
|
|
|
#ifdef MPLANE_V1
|
|
*ctx = ly_ctx_new(yang_dir, 0);
|
|
AssertError(*ctx != NULL, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx));
|
|
#elif defined MPLANE_V2
|
|
LY_ERR ret = ly_ctx_new(yang_dir, 0, ctx);
|
|
AssertError(ret == LY_SUCCESS, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx));
|
|
#endif
|
|
|
|
const size_t num_models = sizeof(yang_models) / sizeof(yang_models[0]);
|
|
for (size_t i = 0; i < num_models; ++i) {
|
|
#ifdef MPLANE_V1
|
|
const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL);
|
|
AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]);
|
|
#elif defined MPLANE_V2
|
|
const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL, NULL);
|
|
AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]);
|
|
#endif
|
|
}
|
|
|
|
MP_LOG_I("Successfully loaded all yang modules for RU \"%s\".\n", ru_session->ru_ip_add);
|
|
|
|
return true;
|
|
}
|