These 3 states: "oper-state", "admin-state", "availability-state" are optional, but shall be checked in order to activate the carriers. If an O-RU doesn't support it, we assume the expected values: - "oper-state" = "enabled" - "admin-state" = "unlocked" - "availability-state" = "NORMAL" Implement retrieval of the hardware states if O-RU supports, i.e. Benetel release v1.4.1.
255 lines
11 KiB
C
255 lines
11 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 "init-mplane.h"
|
|
#include "radio/fhi_72/oran-params.h"
|
|
#include "get-mplane.h"
|
|
#include "subscribe-mplane.h"
|
|
#include "config-mplane.h"
|
|
#include "xml/get-xml.h"
|
|
#include "yang/get-yang.h"
|
|
#include "yang/create-yang-config.h"
|
|
|
|
#include <libyang/libyang.h>
|
|
#include <nc_client.h>
|
|
|
|
static void lnc2_print_clb(NC_VERB_LEVEL level, const char *msg)
|
|
{
|
|
switch (level) {
|
|
case NC_VERB_ERROR:
|
|
MP_LOG_I("[LIBNETCONF2] ERROR: %s.\n", msg);
|
|
break;
|
|
case NC_VERB_WARNING:
|
|
MP_LOG_I("[LIBNETCONF2] WARNING: %s.\n", msg);
|
|
break;
|
|
case NC_VERB_VERBOSE:
|
|
MP_LOG_I("[LIBNETCONF2] VERBOSE: %s.\n", msg);
|
|
break;
|
|
case NC_VERB_DEBUG:
|
|
case NC_VERB_DEBUG_LOWLVL:
|
|
MP_LOG_I("[LIBNETCONF2] DEBUG: %s.\n", msg);
|
|
break;
|
|
default:
|
|
assert(false && "[LIBNETCONF2] Unknown log level.");
|
|
}
|
|
}
|
|
|
|
static void ly_print_clb(LY_LOG_LEVEL level, const char *msg, const char *path)
|
|
{
|
|
switch (level) {
|
|
case LY_LLERR:
|
|
MP_LOG_I("[LIBYANG] ERROR: %s (path: %s).\n", msg, path);
|
|
break;
|
|
case LY_LLWRN:
|
|
MP_LOG_I("[LIBYANG] WARNING: %s (path: %s).\n", msg, path);
|
|
break;
|
|
case LY_LLVRB:
|
|
MP_LOG_I("[LIBYANG] VERBOSE: %s (path: %s).\n", msg, path);
|
|
break;
|
|
case LY_LLDBG:
|
|
MP_LOG_I("[LIBYANG] DEBUG: %s (path: %s).\n", msg, path);
|
|
break;
|
|
default:
|
|
assert(false && "[LIBYANG] Unknown log level.");
|
|
}
|
|
}
|
|
|
|
static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name)
|
|
{
|
|
/* the config module does not know const-correctness... */
|
|
int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name);
|
|
DevAssert(idx >= 0);
|
|
return &pd[idx];
|
|
}
|
|
|
|
bool init_mplane(ru_session_list_t *ru_session_list)
|
|
{
|
|
paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC;
|
|
int nump = sizeofArray(fhip);
|
|
int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN);
|
|
if (ret <= 0) {
|
|
MP_LOG_I("Problem reading section \"%s\".\n", CONFIG_STRING_ORAN);
|
|
return false;
|
|
}
|
|
|
|
ru_session_list->du_key_pair = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->strlistptr;
|
|
int num_keys = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->numelt;
|
|
AssertError(num_keys == 2, return false, "[MPLANE] Expected {pub-key-path, priv-key-path}. Loaded {%s, %s}.\n", ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]);
|
|
|
|
char **ru_ip_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->strlistptr;
|
|
int num_rus = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->numelt;
|
|
char **ru_usernames = gpd(fhip, nump, ORAN_CONFIG_RU_USERNAME)->strlistptr;
|
|
int num_ru_users = gpd(fhip, nump, ORAN_CONFIG_RU_USERNAME)->numelt;
|
|
char **du_mac_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
|
|
int num_dus = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
|
|
int32_t *vlan_tag = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->iptr;
|
|
int num_vlan_tags = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->numelt;
|
|
|
|
AssertError(num_rus == num_ru_users, return false, "[MPLANE] Number of RUs should be equal to the number of users, one for each.\n");
|
|
AssertError(num_dus == num_vlan_tags, return false, "[MPLANE] Number of DU MAC addresses should be equal to the number of VLAN tags.\n");
|
|
|
|
int num_cu_planes = num_dus / num_rus;
|
|
|
|
ru_session_list->num_rus = num_rus;
|
|
ru_session_list->ru_session = calloc(num_rus, sizeof(ru_session_t));
|
|
for (size_t i = 0; i < num_rus; i++) {
|
|
ru_session_t *ru_session = &ru_session_list->ru_session[i];
|
|
ru_session->session = NULL;
|
|
ru_session->ru_ip_add = calloc(strlen(ru_ip_addrs[i]) + 1, sizeof(char));
|
|
memcpy(ru_session->ru_ip_add, ru_ip_addrs[i], strlen(ru_ip_addrs[i]) + 1);
|
|
ru_session->username = calloc(strlen(ru_usernames[i]) + 1, sizeof(char));
|
|
memcpy(ru_session->username, ru_usernames[i], strlen(ru_usernames[i]) + 1);
|
|
|
|
// store DU MAC addresses and VLAN tags
|
|
ru_session->ru_mplane_config.num_cu_planes = num_cu_planes;
|
|
ru_session->ru_mplane_config.du_mac_addr = calloc_or_fail(num_cu_planes, sizeof(char*));
|
|
ru_session->ru_mplane_config.vlan_tag = calloc_or_fail(num_cu_planes, sizeof(int32_t));
|
|
for (int j = 0; j < num_cu_planes; j++) {
|
|
const int idx = i*num_cu_planes+j;
|
|
ru_session->ru_mplane_config.du_mac_addr[j] = calloc(1, strlen(du_mac_addr[idx]) + 1);
|
|
memcpy(ru_session->ru_mplane_config.du_mac_addr[j], du_mac_addr[idx], strlen(du_mac_addr[idx]) + 1);
|
|
ru_session->ru_mplane_config.vlan_tag[j] = vlan_tag[idx];
|
|
}
|
|
}
|
|
|
|
nc_client_init();
|
|
int keypair_ret = nc_client_ssh_add_keypair(ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]);
|
|
AssertError(keypair_ret == 0, return false, "[MPLANE] Unable to add DU ssh key pair.\n");
|
|
|
|
// logs for netconf2 and yang libraries
|
|
nc_set_print_clb(lnc2_print_clb);
|
|
ly_set_log_clb(ly_print_clb, 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void init_ru_notif(ru_session_t *ru_session, const char* buffer)
|
|
{
|
|
char* usage_state = get_ru_xml_node(buffer, "usage-state");
|
|
if (usage_state != NULL && strcmp(usage_state, "busy") == 0) {
|
|
ru_session->ru_notif.rx_carrier_state = BUSY_CARRIER;
|
|
ru_session->ru_notif.tx_carrier_state = BUSY_CARRIER;
|
|
ru_session->ru_notif.config_change = true;
|
|
} else if (usage_state != NULL && strcmp(usage_state, "active") == 0) {
|
|
ru_session->ru_notif.rx_carrier_state = READY_CARRIER;
|
|
ru_session->ru_notif.tx_carrier_state = READY_CARRIER;
|
|
ru_session->ru_notif.config_change = true;
|
|
} else { // "idle" or NULL
|
|
ru_session->ru_notif.rx_carrier_state = DISABLED_CARRIER;
|
|
ru_session->ru_notif.tx_carrier_state = DISABLED_CARRIER;
|
|
ru_session->ru_notif.config_change = false;
|
|
}
|
|
|
|
char *oper_state = get_ru_xml_node(buffer, "oper-state");
|
|
ru_session->ru_notif.hardware.oper_state = (str_to_enum_oper(oper_state) != OPER_COUNT) ? str_to_enum_oper(oper_state) : ENABLED_OPER;
|
|
|
|
char *admin_state = get_ru_xml_node(buffer, "admin-state");
|
|
ru_session->ru_notif.hardware.admin_state = (str_to_enum_admin(admin_state) != ADMIN_COUNT) ? str_to_enum_admin(admin_state) : UNLOCKED_ADMIN;
|
|
|
|
char *avail_state = get_ru_xml_node(buffer, "availability-state");
|
|
ru_session->ru_notif.hardware.avail_state = (str_to_enum_avail(avail_state) != AVAIL_COUNT) ? str_to_enum_avail(avail_state) : NORMAL_AVAIL;
|
|
|
|
char *ptp_state = get_ru_xml_node(buffer, "sync-state");
|
|
ru_session->ru_notif.ptp_state = str_to_enum_ptp(ptp_state);
|
|
MP_LOG_I("RU is in \"%s\" sync state.\n", ptp_state);
|
|
|
|
free(usage_state);
|
|
free(oper_state);
|
|
free(admin_state);
|
|
free(avail_state);
|
|
free(ptp_state);
|
|
}
|
|
|
|
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus)
|
|
{
|
|
bool success = false;
|
|
|
|
char *operational_ds = NULL;
|
|
success = get_mplane(ru_session, &operational_ds);
|
|
AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via get_mplane().\n");
|
|
|
|
// init RU notifications
|
|
init_ru_notif(ru_session, operational_ds);
|
|
|
|
/* 1) as per M-plane spec, RU must be in supervised mode,
|
|
where stream = NULL && filter = "/o-ran-supervision:supervision-notification";
|
|
2) additionally, we want to subscribe to PTP state change,
|
|
where stream = NULL && filter = "/o-ran-sync:synchronization-state-change";
|
|
=> since more than one subscription at the time within one session is not possible, we will subscribe to all notifications */
|
|
const char *stream = "NETCONF";
|
|
const char *filter = NULL;
|
|
success = subscribe_mplane(ru_session, stream, filter, (void *)&ru_session->ru_notif);
|
|
AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via subscribe_mplane().\n");
|
|
|
|
// when subscribed to the supervision notification, the watchdog timer needs to be updated
|
|
char *watchdog_answer = NULL;
|
|
success = update_timer_mplane(ru_session, &watchdog_answer);
|
|
AssertError(success, return false, "[MPLANE] Unable to update the watchdog timer. RU will do a reset after default supervision timer of (60+10)[s] expires.\n");
|
|
MP_LOG_I("Watchdog timer answer: \n\t%s\n", watchdog_answer);
|
|
|
|
// save RU info for xran
|
|
const int max_num_ant = max(oai->tx_num_channels/num_rus, oai->rx_num_channels/num_rus);
|
|
success = get_config_for_xran(operational_ds, max_num_ant, &ru_session->xran_mplane);
|
|
AssertError(success, return false, "[MPLANE] Unable to retrieve required info for xran from RU \"%s\".\n", ru_session->ru_ip_add);
|
|
|
|
// save the U-plane info
|
|
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");
|
|
|
|
// 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);
|
|
AssertError(success, return false, "[MPLANE] Unable to load yang models.\n");
|
|
|
|
while (1) {
|
|
sleep(5);
|
|
if (!ru_session->ru_notif.ptp_state && !ru_session->ru_notif.hardware.oper_state && !ru_session->ru_notif.hardware.admin_state && !ru_session->ru_notif.hardware.avail_state) {
|
|
char *content = NULL;
|
|
success = configure_ru_from_yang(ru_session, oai, num_rus, &content);
|
|
AssertError(success, return false, "[MPLANE] Unable to create content for <edit-config> RPC for start-up procedure.\n");
|
|
|
|
success = edit_val_commmit_rpc(ru_session, content);
|
|
AssertError(success, return false, "[MPLANE] Unable to continue.\n");
|
|
free(content);
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(operational_ds);
|
|
free(watchdog_answer);
|
|
|
|
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;
|
|
}
|