Performance Management implementation
Introduced a parameter start_up_timing which indicates if PM activation is supported during the start-up procedure. We initialize this parameter, based on the vendor. Notification interval is set to 10s.
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "connect-mplane.h"
|
#include "connect-mplane.h"
|
||||||
|
#include "init-mplane.h"
|
||||||
#include "common/utils/assertions.h"
|
#include "common/utils/assertions.h"
|
||||||
|
|
||||||
#include <libyang/libyang.h>
|
#include <libyang/libyang.h>
|
||||||
@@ -63,6 +64,10 @@ void disconnect_mplane(void *rus_disconnect)
|
|||||||
ru_session_t *ru_session = &ru_session_list->ru_session[i];
|
ru_session_t *ru_session = &ru_session_list->ru_session[i];
|
||||||
if (ru_session->session == NULL)
|
if (ru_session->session == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
MP_LOG_I("Sending PM de-activation request for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||||
|
bool success = pm_conf(ru_session, "false");
|
||||||
|
if (success)
|
||||||
|
MP_LOG_I("Successfully de-activated PM for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||||
MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add);
|
MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add);
|
||||||
nc_session_free(ru_session->session, NULL);
|
nc_session_free(ru_session->session, NULL);
|
||||||
ru_session->session = NULL;
|
ru_session->session = NULL;
|
||||||
|
|||||||
@@ -182,6 +182,10 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz
|
|||||||
success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config);
|
success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config);
|
||||||
AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n");
|
AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n");
|
||||||
|
|
||||||
|
// Performance Management
|
||||||
|
success = get_pm_object_list(operational_ds, &ru_session->pm_stats);
|
||||||
|
AssertError(success, return false, "[MPLANE] Unable to retrieve performance measurement names from RU \"%s\".\n", ru_session->ru_ip_add);
|
||||||
|
|
||||||
success = load_yang_models(ru_session, operational_ds);
|
success = load_yang_models(ru_session, operational_ds);
|
||||||
AssertError(success, return false, "[MPLANE] Unable to load yang models.\n");
|
AssertError(success, return false, "[MPLANE] Unable to load yang models.\n");
|
||||||
|
|
||||||
@@ -212,3 +216,15 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pm_conf(ru_session_t *ru_session, const char *active)
|
||||||
|
{
|
||||||
|
char *content = get_pm_content(ru_session, active);
|
||||||
|
|
||||||
|
bool success = edit_val_commmit_rpc(ru_session, content);
|
||||||
|
AssertError(success, return false, "[MPLANE] Cannot continue.\n");
|
||||||
|
|
||||||
|
free(content);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,4 +29,6 @@ bool init_mplane(ru_session_list_t *ru_session_list);
|
|||||||
|
|
||||||
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus);
|
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus);
|
||||||
|
|
||||||
|
bool pm_conf(ru_session_t *ru_session, const char *active);
|
||||||
|
|
||||||
#endif /* OAI_MPLANE_H */
|
#endif /* OAI_MPLANE_H */
|
||||||
|
|||||||
@@ -182,3 +182,23 @@ bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get_pm_object_list(const char *buffer, pm_stats_t *pm_stats)
|
||||||
|
{
|
||||||
|
const char *ru_vendor = get_ru_xml_node(buffer, "mfg-name");
|
||||||
|
if (strcasecmp(ru_vendor, "BENETEL") == 0) {
|
||||||
|
pm_stats->start_up_timing = false;
|
||||||
|
} else {
|
||||||
|
pm_stats->start_up_timing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rx window
|
||||||
|
get_ru_xml_list(buffer, "rx-window-objects", &pm_stats->rx_window_meas, &pm_stats->rx_num);
|
||||||
|
|
||||||
|
// Tx
|
||||||
|
get_ru_xml_list(buffer, "tx-stats-objects", &pm_stats->tx_meas, &pm_stats->tx_num);
|
||||||
|
|
||||||
|
MP_LOG_I("Successfully retreived all performance measurement names.\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,6 +81,18 @@ typedef struct {
|
|||||||
|
|
||||||
} ru_mplane_config_t;
|
} ru_mplane_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// activation if required at start-up timing
|
||||||
|
bool start_up_timing;
|
||||||
|
|
||||||
|
size_t rx_num;
|
||||||
|
char **rx_window_meas;
|
||||||
|
|
||||||
|
size_t tx_num;
|
||||||
|
char **tx_meas;
|
||||||
|
|
||||||
|
} pm_stats_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *username;
|
char *username;
|
||||||
char *ru_ip_add;
|
char *ru_ip_add;
|
||||||
@@ -89,6 +101,7 @@ typedef struct {
|
|||||||
void *ctx;
|
void *ctx;
|
||||||
xran_mplane_t xran_mplane;
|
xran_mplane_t xran_mplane;
|
||||||
ru_notif_t ru_notif;
|
ru_notif_t ru_notif;
|
||||||
|
pm_stats_t pm_stats;
|
||||||
|
|
||||||
} ru_session_t;
|
} ru_session_t;
|
||||||
|
|
||||||
@@ -103,4 +116,6 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_
|
|||||||
|
|
||||||
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config);
|
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config);
|
||||||
|
|
||||||
|
bool get_pm_object_list(const char *buffer, pm_stats_t *pm_stats);
|
||||||
|
|
||||||
#endif /* RU_MPLANE_API_H */
|
#endif /* RU_MPLANE_API_H */
|
||||||
|
|||||||
@@ -54,6 +54,37 @@ static void notif_clb_v1(struct nc_session *session, const struct nc_notif *noti
|
|||||||
recv_notif_v1(notif, answer);
|
recv_notif_v1(notif, answer);
|
||||||
}
|
}
|
||||||
#elif MPLANE_V2
|
#elif MPLANE_V2
|
||||||
|
static void log_v2_pm_info(const char *ru_ip_add, struct lyd_node_inner *stats)
|
||||||
|
{
|
||||||
|
struct lyd_node *child, *field = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
char *meas_list[8], *count_list[8] = {};
|
||||||
|
|
||||||
|
LY_LIST_FOR(stats->child, child) {
|
||||||
|
// const char *type = child->schema->name; // e.g. "rx-window-stats", "tx-stats"
|
||||||
|
struct lyd_node_inner *stats_inner = (struct lyd_node_inner *)child;
|
||||||
|
LY_LIST_FOR(stats_inner->child, field) {
|
||||||
|
if (strcmp(field->schema->name, "measurement-object") == 0) {
|
||||||
|
meas_list[len] = (char *)lyd_get_value(field);
|
||||||
|
} else if (strcmp(field->schema->name, "count") == 0) {
|
||||||
|
count_list[len] = (char *)lyd_get_value(field);
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_LOG_I("[PM: \"%s\"][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s]\n",
|
||||||
|
ru_ip_add,
|
||||||
|
meas_list[0], count_list[0],
|
||||||
|
meas_list[1], count_list[1],
|
||||||
|
meas_list[2], count_list[2],
|
||||||
|
meas_list[3], count_list[3],
|
||||||
|
meas_list[4], count_list[4],
|
||||||
|
meas_list[5], count_list[5],
|
||||||
|
meas_list[6], count_list[6],
|
||||||
|
meas_list[7], count_list[7]);
|
||||||
|
}
|
||||||
|
|
||||||
static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer)
|
static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer)
|
||||||
{
|
{
|
||||||
const char *notif = op->schema->name;
|
const char *notif = op->schema->name;
|
||||||
@@ -92,9 +123,14 @@ static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp
|
|||||||
char *subs_reply = NULL;
|
char *subs_reply = NULL;
|
||||||
lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS);
|
lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS);
|
||||||
const char *ru_ip_add = nc_session_get_host(session);
|
const char *ru_ip_add = nc_session_get_host(session);
|
||||||
|
struct lyd_node_inner *op_inner = (struct lyd_node_inner *)op;
|
||||||
|
if (strcmp(op_inner->schema->name, "measurement-result-stats") == 0) {
|
||||||
|
log_v2_pm_info(ru_ip_add, op_inner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply);
|
MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply);
|
||||||
|
|
||||||
recv_notif_v2((struct lyd_node_inner *)op, answer);
|
recv_notif_v2(op_inner, answer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ static void find_ru_xml_list(xmlNode *node, const char *filter, char ***match_li
|
|||||||
xmlNode *name_node = NULL;
|
xmlNode *name_node = NULL;
|
||||||
|
|
||||||
for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
|
for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
|
||||||
if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) {
|
const char *name_node_str = (const char *)cur_node2->name;
|
||||||
|
if (cur_node2->type == XML_ELEMENT_NODE && (strcmp(name_node_str, "name") == 0 || strcmp(name_node_str, "measurement-object") == 0)) {
|
||||||
name_node = cur_node2;
|
name_node = cur_node2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,6 +396,56 @@ static bool create_uplane_conf_v2(const ru_session_t *ru_session, const openair0
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool create_pm_conf_v2(const ru_session_t *ru_session, const char *active, struct lyd_node **root)
|
||||||
|
{
|
||||||
|
LY_ERR ret = LY_SUCCESS;
|
||||||
|
|
||||||
|
ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-performance-management:performance-measurement-objects", NULL, 0, root);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"performance-measurement-objects\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(*root, NULL, "notification-interval", "10", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"notification-interval\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(*root, NULL, "rx-window-measurement-interval", "10", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-window-measurement-interval\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(*root, NULL, "tx-measurement-interval", "10", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-measurement-interval\" node.\n");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ru_session->pm_stats.rx_num; i++) {
|
||||||
|
struct lyd_node *rx_window_meas_objects = NULL;
|
||||||
|
ret = lyd_new_list(*root, NULL, "rx-window-measurement-objects", 0, &rx_window_meas_objects, ru_session->pm_stats.rx_window_meas[i]);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-window-measurement-objects\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(rx_window_meas_objects, NULL, "active", active, 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(rx_window_meas_objects, NULL, "object-unit", "RU", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"object-unit\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(rx_window_meas_objects, NULL, "report-info", "COUNT", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"report-info\" node.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ru_session->pm_stats.tx_num; i++) {
|
||||||
|
struct lyd_node *tx_meas_objects = NULL;
|
||||||
|
ret = lyd_new_list(*root, NULL, "tx-measurement-objects", 0, &tx_meas_objects, ru_session->pm_stats.tx_meas[i]);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-measurement-objects\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(tx_meas_objects, NULL, "active", active, 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(tx_meas_objects, NULL, "object-unit", "RU", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"object-unit\" node.\n");
|
||||||
|
|
||||||
|
ret = lyd_new_term(tx_meas_objects, NULL, "report-info", "COUNT", 0, NULL);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"report-info\" node.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result)
|
bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result)
|
||||||
@@ -445,11 +495,43 @@ bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_confi
|
|||||||
ret = lyd_merge_siblings(&all_merge, uplane_conf, 0);
|
ret = lyd_merge_siblings(&all_merge, uplane_conf, 0);
|
||||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n");
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n");
|
||||||
|
|
||||||
|
// <o-ran-pm>
|
||||||
|
struct lyd_node *pm_conf = NULL;
|
||||||
|
if (ru_session->pm_stats.start_up_timing) {
|
||||||
|
success = create_pm_conf_v2(ru_session, "true", &pm_conf);
|
||||||
|
VERIFY_SUCCESS(success, "[MPLANE] Cannot create PM activation.\n");
|
||||||
|
} else {
|
||||||
|
success = create_pm_conf_v2(ru_session, "false", &pm_conf);
|
||||||
|
VERIFY_SUCCESS(success, "[MPLANE] Cannot create PM deactivation.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lyd_merge_siblings(&all_merge, pm_conf, 0);
|
||||||
|
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element, U-plane configuration and PM configuration.\n");
|
||||||
|
|
||||||
lyd_print_mem(result, all_merge, LYD_XML, LYD_PRINT_WITHSIBLINGS);
|
lyd_print_mem(result, all_merge, LYD_XML, LYD_PRINT_WITHSIBLINGS);
|
||||||
|
|
||||||
lyd_free_siblings(all_merge);
|
lyd_free_siblings(all_merge);
|
||||||
lyd_free_siblings(uplane_conf);
|
lyd_free_siblings(uplane_conf);
|
||||||
|
lyd_free_siblings(pm_conf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *get_pm_content(const ru_session_t *ru_session, const char *active)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
char *content = NULL;
|
||||||
|
|
||||||
|
#ifdef MPLANE_V1
|
||||||
|
VERIFY_SUCCESS(success, "[MPLANE] To be implemented and tested.\n");
|
||||||
|
#elif defined MPLANE_V2
|
||||||
|
struct lyd_node *pm_conf = NULL;
|
||||||
|
success = create_pm_conf_v2(ru_session, active, &pm_conf);
|
||||||
|
AssertError(success, return false, "[MPLANE] Cannot create PM configuration.\n");
|
||||||
|
lyd_print_mem(&content, pm_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS);
|
||||||
|
lyd_free_siblings(pm_conf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,4 +29,6 @@
|
|||||||
|
|
||||||
bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result);
|
bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result);
|
||||||
|
|
||||||
|
char *get_pm_content(const ru_session_t *ru_session, const char *active);
|
||||||
|
|
||||||
#endif /* CREATE_MPLANE_YANG_CONFIG_H */
|
#endif /* CREATE_MPLANE_YANG_CONFIG_H */
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ bool load_yang_models(ru_session_t *ru_session, const char *buffer)
|
|||||||
1) the yang models order is not good - the dependancy models have to be loaded first
|
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) */
|
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_dir = YANG_MODELS;
|
||||||
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf"};
|
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf", "ietf-netconf-acm", "ietf-crypto-types", "o-ran-file-management", "o-ran-performance-management"};
|
||||||
|
|
||||||
#ifdef MPLANE_V1
|
#ifdef MPLANE_V1
|
||||||
*ctx = ly_ctx_new(yang_dir, 0);
|
*ctx = ly_ctx_new(yang_dir, 0);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,440 @@
|
|||||||
|
module ietf-netconf-acm {
|
||||||
|
|
||||||
|
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
|
||||||
|
|
||||||
|
prefix nacm;
|
||||||
|
|
||||||
|
import ietf-yang-types {
|
||||||
|
prefix yang;
|
||||||
|
}
|
||||||
|
|
||||||
|
organization
|
||||||
|
"IETF NETCONF (Network Configuration) Working Group";
|
||||||
|
|
||||||
|
contact
|
||||||
|
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
|
||||||
|
WG List: <mailto:netconf@ietf.org>
|
||||||
|
Author: Andy Bierman
|
||||||
|
<mailto:andy@yumaworks.com>
|
||||||
|
Author: Martin Bjorklund
|
||||||
|
<mailto:mbj@tail-f.com>";
|
||||||
|
|
||||||
|
description
|
||||||
|
"Network Configuration Access Control Model.
|
||||||
|
Copyright (c) 2012 - 2018 IETF Trust and the persons
|
||||||
|
identified as authors of the code. All rights reserved.
|
||||||
|
Redistribution and use in source and binary forms, with or
|
||||||
|
without modification, is permitted pursuant to, and subject
|
||||||
|
to the license terms contained in, the Simplified BSD
|
||||||
|
License set forth in Section 4.c of the IETF Trust's
|
||||||
|
Legal Provisions Relating to IETF Documents
|
||||||
|
(https://trustee.ietf.org/license-info).
|
||||||
|
This version of this YANG module is part of RFC 8341; see
|
||||||
|
the RFC itself for full legal notices.";
|
||||||
|
|
||||||
|
revision "2018-02-14" {
|
||||||
|
description
|
||||||
|
"Added support for YANG 1.1 actions and notifications tied to
|
||||||
|
data nodes. Clarified how NACM extensions can be used by
|
||||||
|
other data models.";
|
||||||
|
reference
|
||||||
|
"RFC 8341: Network Configuration Access Control Model";
|
||||||
|
}
|
||||||
|
|
||||||
|
revision "2012-02-22" {
|
||||||
|
description
|
||||||
|
"Initial version.";
|
||||||
|
reference
|
||||||
|
"RFC 6536: Network Configuration Protocol (NETCONF)
|
||||||
|
Access Control Model";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extension statements
|
||||||
|
*/
|
||||||
|
|
||||||
|
extension default-deny-write {
|
||||||
|
description
|
||||||
|
"Used to indicate that the data model node
|
||||||
|
represents a sensitive security system parameter.
|
||||||
|
If present, the NETCONF server will only allow the designated
|
||||||
|
'recovery session' to have write access to the node. An
|
||||||
|
explicit access control rule is required for all other users.
|
||||||
|
If the NACM module is used, then it must be enabled (i.e.,
|
||||||
|
/nacm/enable-nacm object equals 'true'), or this extension
|
||||||
|
is ignored.
|
||||||
|
The 'default-deny-write' extension MAY appear within a data
|
||||||
|
definition statement. It is ignored otherwise.";
|
||||||
|
}
|
||||||
|
|
||||||
|
extension default-deny-all {
|
||||||
|
description
|
||||||
|
"Used to indicate that the data model node
|
||||||
|
controls a very sensitive security system parameter.
|
||||||
|
If present, the NETCONF server will only allow the designated
|
||||||
|
'recovery session' to have read, write, or execute access to
|
||||||
|
the node. An explicit access control rule is required for all
|
||||||
|
other users.
|
||||||
|
If the NACM module is used, then it must be enabled (i.e.,
|
||||||
|
/nacm/enable-nacm object equals 'true'), or this extension
|
||||||
|
is ignored.
|
||||||
|
The 'default-deny-all' extension MAY appear within a data
|
||||||
|
definition statement, 'rpc' statement, or 'notification'
|
||||||
|
statement. It is ignored otherwise.";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derived types
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef user-name-type {
|
||||||
|
type string {
|
||||||
|
length "1..max";
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"General-purpose username string.";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef matchall-string-type {
|
||||||
|
type string {
|
||||||
|
pattern '\*';
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"The string containing a single asterisk '*' is used
|
||||||
|
to conceptually represent all possible values
|
||||||
|
for the particular leaf using this data type.";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef access-operations-type {
|
||||||
|
type bits {
|
||||||
|
bit create {
|
||||||
|
description
|
||||||
|
"Any protocol operation that creates a
|
||||||
|
new data node.";
|
||||||
|
}
|
||||||
|
bit read {
|
||||||
|
description
|
||||||
|
"Any protocol operation or notification that
|
||||||
|
returns the value of a data node.";
|
||||||
|
}
|
||||||
|
bit update {
|
||||||
|
description
|
||||||
|
"Any protocol operation that alters an existing
|
||||||
|
data node.";
|
||||||
|
}
|
||||||
|
bit delete {
|
||||||
|
description
|
||||||
|
"Any protocol operation that removes a data node.";
|
||||||
|
}
|
||||||
|
bit exec {
|
||||||
|
description
|
||||||
|
"Execution access to the specified protocol operation.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Access operation.";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef group-name-type {
|
||||||
|
type string {
|
||||||
|
length "1..max";
|
||||||
|
pattern '[^\*].*';
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Name of administrative group to which
|
||||||
|
users can be assigned.";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef action-type {
|
||||||
|
type enumeration {
|
||||||
|
enum permit {
|
||||||
|
description
|
||||||
|
"Requested action is permitted.";
|
||||||
|
}
|
||||||
|
enum deny {
|
||||||
|
description
|
||||||
|
"Requested action is denied.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Action taken by the server when a particular
|
||||||
|
rule matches.";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef node-instance-identifier {
|
||||||
|
type yang:xpath1.0;
|
||||||
|
description
|
||||||
|
"Path expression used to represent a special
|
||||||
|
data node, action, or notification instance-identifier
|
||||||
|
string.
|
||||||
|
A node-instance-identifier value is an
|
||||||
|
unrestricted YANG instance-identifier expression.
|
||||||
|
All the same rules as an instance-identifier apply,
|
||||||
|
except that predicates for keys are optional. If a key
|
||||||
|
predicate is missing, then the node-instance-identifier
|
||||||
|
represents all possible server instances for that key.
|
||||||
|
This XML Path Language (XPath) expression is evaluated in the
|
||||||
|
following context:
|
||||||
|
o The set of namespace declarations are those in scope on
|
||||||
|
the leaf element where this type is used.
|
||||||
|
o The set of variable bindings contains one variable,
|
||||||
|
'USER', which contains the name of the user of the
|
||||||
|
current session.
|
||||||
|
o The function library is the core function library, but
|
||||||
|
note that due to the syntax restrictions of an
|
||||||
|
instance-identifier, no functions are allowed.
|
||||||
|
o The context node is the root node in the data tree.
|
||||||
|
The accessible tree includes actions and notifications tied
|
||||||
|
to data nodes.";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data definition statements
|
||||||
|
*/
|
||||||
|
|
||||||
|
container nacm {
|
||||||
|
nacm:default-deny-all;
|
||||||
|
|
||||||
|
description
|
||||||
|
"Parameters for NETCONF access control model.";
|
||||||
|
|
||||||
|
leaf enable-nacm {
|
||||||
|
type boolean;
|
||||||
|
default "true";
|
||||||
|
description
|
||||||
|
"Enables or disables all NETCONF access control
|
||||||
|
enforcement. If 'true', then enforcement
|
||||||
|
is enabled. If 'false', then enforcement
|
||||||
|
is disabled.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf read-default {
|
||||||
|
type action-type;
|
||||||
|
default "permit";
|
||||||
|
description
|
||||||
|
"Controls whether read access is granted if
|
||||||
|
no appropriate rule is found for a
|
||||||
|
particular read request.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf write-default {
|
||||||
|
type action-type;
|
||||||
|
default "deny";
|
||||||
|
description
|
||||||
|
"Controls whether create, update, or delete access
|
||||||
|
is granted if no appropriate rule is found for a
|
||||||
|
particular write request.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf exec-default {
|
||||||
|
type action-type;
|
||||||
|
default "permit";
|
||||||
|
description
|
||||||
|
"Controls whether exec access is granted if no appropriate
|
||||||
|
rule is found for a particular protocol operation request.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf enable-external-groups {
|
||||||
|
type boolean;
|
||||||
|
default "true";
|
||||||
|
description
|
||||||
|
"Controls whether the server uses the groups reported by the
|
||||||
|
NETCONF transport layer when it assigns the user to a set of
|
||||||
|
NACM groups. If this leaf has the value 'false', any group
|
||||||
|
names reported by the transport layer are ignored by the
|
||||||
|
server.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf denied-operations {
|
||||||
|
type yang:zero-based-counter32;
|
||||||
|
config false;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"Number of times since the server last restarted that a
|
||||||
|
protocol operation request was denied.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf denied-data-writes {
|
||||||
|
type yang:zero-based-counter32;
|
||||||
|
config false;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"Number of times since the server last restarted that a
|
||||||
|
protocol operation request to alter
|
||||||
|
a configuration datastore was denied.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf denied-notifications {
|
||||||
|
type yang:zero-based-counter32;
|
||||||
|
config false;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"Number of times since the server last restarted that
|
||||||
|
a notification was dropped for a subscription because
|
||||||
|
access to the event type was denied.";
|
||||||
|
}
|
||||||
|
|
||||||
|
container groups {
|
||||||
|
description
|
||||||
|
"NETCONF access control groups.";
|
||||||
|
|
||||||
|
list group {
|
||||||
|
key name;
|
||||||
|
|
||||||
|
description
|
||||||
|
"One NACM group entry. This list will only contain
|
||||||
|
configured entries, not any entries learned from
|
||||||
|
any transport protocols.";
|
||||||
|
|
||||||
|
leaf name {
|
||||||
|
type group-name-type;
|
||||||
|
description
|
||||||
|
"Group name associated with this entry.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf-list user-name {
|
||||||
|
type user-name-type;
|
||||||
|
description
|
||||||
|
"Each entry identifies the username of
|
||||||
|
a member of the group associated with
|
||||||
|
this entry.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list rule-list {
|
||||||
|
key name;
|
||||||
|
ordered-by user;
|
||||||
|
description
|
||||||
|
"An ordered collection of access control rules.";
|
||||||
|
|
||||||
|
leaf name {
|
||||||
|
type string {
|
||||||
|
length "1..max";
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Arbitrary name assigned to the rule-list.";
|
||||||
|
}
|
||||||
|
leaf-list group {
|
||||||
|
type union {
|
||||||
|
type matchall-string-type;
|
||||||
|
type group-name-type;
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"List of administrative groups that will be
|
||||||
|
assigned the associated access rights
|
||||||
|
defined by the 'rule' list.
|
||||||
|
The string '*' indicates that all groups apply to the
|
||||||
|
entry.";
|
||||||
|
}
|
||||||
|
|
||||||
|
list rule {
|
||||||
|
key name;
|
||||||
|
ordered-by user;
|
||||||
|
description
|
||||||
|
"One access control rule.
|
||||||
|
Rules are processed in user-defined order until a match is
|
||||||
|
found. A rule matches if 'module-name', 'rule-type', and
|
||||||
|
'access-operations' match the request. If a rule
|
||||||
|
matches, the 'action' leaf determines whether or not
|
||||||
|
access is granted.";
|
||||||
|
|
||||||
|
leaf name {
|
||||||
|
type string {
|
||||||
|
length "1..max";
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Arbitrary name assigned to the rule.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf module-name {
|
||||||
|
type union {
|
||||||
|
type matchall-string-type;
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
default "*";
|
||||||
|
description
|
||||||
|
"Name of the module associated with this rule.
|
||||||
|
This leaf matches if it has the value '*' or if the
|
||||||
|
object being accessed is defined in the module with the
|
||||||
|
specified module name.";
|
||||||
|
}
|
||||||
|
choice rule-type {
|
||||||
|
description
|
||||||
|
"This choice matches if all leafs present in the rule
|
||||||
|
match the request. If no leafs are present, the
|
||||||
|
choice matches all requests.";
|
||||||
|
case protocol-operation {
|
||||||
|
leaf rpc-name {
|
||||||
|
type union {
|
||||||
|
type matchall-string-type;
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"This leaf matches if it has the value '*' or if
|
||||||
|
its value equals the requested protocol operation
|
||||||
|
name.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case notification {
|
||||||
|
leaf notification-name {
|
||||||
|
type union {
|
||||||
|
type matchall-string-type;
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"This leaf matches if it has the value '*' or if its
|
||||||
|
value equals the requested notification name.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case data-node {
|
||||||
|
leaf path {
|
||||||
|
type node-instance-identifier;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"Data node instance-identifier associated with the
|
||||||
|
data node, action, or notification controlled by
|
||||||
|
this rule.
|
||||||
|
Configuration data or state data
|
||||||
|
instance-identifiers start with a top-level
|
||||||
|
data node. A complete instance-identifier is
|
||||||
|
required for this type of path value.
|
||||||
|
The special value '/' refers to all possible
|
||||||
|
datastore contents.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf access-operations {
|
||||||
|
type union {
|
||||||
|
type matchall-string-type;
|
||||||
|
type access-operations-type;
|
||||||
|
}
|
||||||
|
default "*";
|
||||||
|
description
|
||||||
|
"Access operations associated with this rule.
|
||||||
|
This leaf matches if it has the value '*' or if the
|
||||||
|
bit corresponding to the requested operation is set.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf action {
|
||||||
|
type action-type;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"The access control action associated with the
|
||||||
|
rule. If a rule has been determined to match a
|
||||||
|
particular request, then this object is used
|
||||||
|
to determine whether to permit or deny the
|
||||||
|
request.";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf comment {
|
||||||
|
type string;
|
||||||
|
description
|
||||||
|
"A textual description of the access rule.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
module o-ran-file-management {
|
||||||
|
yang-version 1.1;
|
||||||
|
namespace "urn:o-ran:file-management:1.0";
|
||||||
|
prefix "o-ran-file-mgmt";
|
||||||
|
|
||||||
|
import ietf-crypto-types {
|
||||||
|
prefix "ct";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
organization "O-RAN Alliance";
|
||||||
|
|
||||||
|
contact
|
||||||
|
"www.o-ran.org";
|
||||||
|
|
||||||
|
description
|
||||||
|
"This module defines the configuration and operations for handling upload.
|
||||||
|
|
||||||
|
Copyright 2019 the O-RAN Alliance.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the above disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the above disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the Members of the O-RAN Alliance nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.";
|
||||||
|
|
||||||
|
revision "2019-07-03" {
|
||||||
|
description
|
||||||
|
"version 1.1.0
|
||||||
|
|
||||||
|
1) backward compatible changes to correct sFTP Server Authentication .
|
||||||
|
2) minor fixes according to lack of descriptions
|
||||||
|
3) backward compatible changes to introduce groupings";
|
||||||
|
|
||||||
|
reference "ORAN-WG4.M.0-v01.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
revision "2019-02-04" {
|
||||||
|
description
|
||||||
|
"version 1.0.0
|
||||||
|
|
||||||
|
1) imported model from xRAN
|
||||||
|
2) changed namespace and reference from xran to o-ran";
|
||||||
|
|
||||||
|
reference "ORAN-WG4.M.0-v01.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
grouping file-path-grouping {
|
||||||
|
description "Complete logical path of the file to upload/download
|
||||||
|
(no wildcard is allowed) ex : /o-RAN/log/syslog.1";
|
||||||
|
|
||||||
|
leaf local-logical-file-path {
|
||||||
|
type string;
|
||||||
|
mandatory true;
|
||||||
|
description "Local logical file path";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf remote-file-path {
|
||||||
|
type string;
|
||||||
|
mandatory true;
|
||||||
|
description "URI specifying the remote-file-path on O-DU/NMS.
|
||||||
|
Format:sftp://<username>@<host>[:port]/path";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grouping output-status-grouping {
|
||||||
|
description "Status grouping";
|
||||||
|
|
||||||
|
leaf status {
|
||||||
|
type enumeration {
|
||||||
|
enum SUCCESS {
|
||||||
|
description "";}
|
||||||
|
enum FAILURE {
|
||||||
|
description "";}
|
||||||
|
}
|
||||||
|
description "Operation status";
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf reject-reason {
|
||||||
|
when "../status = 'FAILURE'";
|
||||||
|
type string;
|
||||||
|
description "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grouping credential-information {
|
||||||
|
description "Type of authentication to use for SFTP upload or download.";
|
||||||
|
choice credentials {
|
||||||
|
case password {
|
||||||
|
container password {
|
||||||
|
presence true;
|
||||||
|
leaf password {
|
||||||
|
type string;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"password needed for O-RU authentication.";
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"password for O-RU authentication method in use";
|
||||||
|
}
|
||||||
|
container server {
|
||||||
|
list keys {
|
||||||
|
key algorithm;
|
||||||
|
ordered-by user;
|
||||||
|
uses ct:public-key-grouping;
|
||||||
|
description
|
||||||
|
"List of allowed algorithms with its keys";
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Key for sFTP server authentication";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case certificate {
|
||||||
|
container certificate {
|
||||||
|
presence true;
|
||||||
|
description
|
||||||
|
"certificate authentication method in use";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grouping retrieve-input {
|
||||||
|
description "Grouping for information retrieval RPC input";
|
||||||
|
leaf logical-path {
|
||||||
|
type string;
|
||||||
|
mandatory true;
|
||||||
|
description "O-RAN unit of which the files are to be listed.
|
||||||
|
ex : O-RAN/log, o-RAN/PM, O-RAN/transceiver";
|
||||||
|
}
|
||||||
|
leaf file-name-filter {
|
||||||
|
type string;
|
||||||
|
description "Filter which are to be applied on the result list of file names (* is allowed as wild-card).";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grouping retrieve-output {
|
||||||
|
description "Grouping for information retrieval RPC output";
|
||||||
|
uses output-status-grouping;
|
||||||
|
leaf-list file-list {
|
||||||
|
when "../status = 'SUCCESS'";
|
||||||
|
type string;
|
||||||
|
description "List of files in the unit with the filter applied.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPCs
|
||||||
|
|
||||||
|
rpc file-upload {
|
||||||
|
description "File upload over SFTP from equipment to NETCONF client";
|
||||||
|
input {
|
||||||
|
uses file-path-grouping;
|
||||||
|
uses credential-information;
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
uses output-status-grouping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc retrieve-file-list {
|
||||||
|
description "List all the files in the logical O-RAN unit (* is allowed as wild-card).";
|
||||||
|
input {
|
||||||
|
uses retrieve-input;
|
||||||
|
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
uses retrieve-output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification file-upload-notification {
|
||||||
|
uses file-path-grouping;
|
||||||
|
uses output-status-grouping;
|
||||||
|
description "";
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc file-download {
|
||||||
|
description
|
||||||
|
"Management plane triggered to generate the download file of O-RU.";
|
||||||
|
input {
|
||||||
|
uses file-path-grouping;
|
||||||
|
uses credential-information;
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
uses output-status-grouping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification file-download-event {
|
||||||
|
uses file-path-grouping;
|
||||||
|
uses output-status-grouping;
|
||||||
|
description "";
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -338,6 +338,11 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
|
|||||||
if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) {
|
if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) {
|
||||||
MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add);
|
MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add);
|
||||||
ru_ready[i] = true;
|
ru_ready[i] = true;
|
||||||
|
if (!ru_session->pm_stats.start_up_timing) {
|
||||||
|
success = pm_conf(ru_session, "true");
|
||||||
|
if (success)
|
||||||
|
MP_LOG_I("Sucessfully activated PM after start-up procedure for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
all_rus_ready = false;
|
all_rus_ready = false;
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user