From 6266239c34e2b440d0af697c3d36eaa31d4539f9 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 15:21:37 +0100 Subject: [PATCH] Add RPC for M-plane --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/init-mplane.c | 12 +++ radio/fhi_72/mplane/subscribe-mplane.c | 133 +++++++++++++++++++++++++ radio/fhi_72/mplane/subscribe-mplane.h | 31 ++++++ 4 files changed, 177 insertions(+) create mode 100644 radio/fhi_72/mplane/subscribe-mplane.c create mode 100644 radio/fhi_72/mplane/subscribe-mplane.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 1d00c26ab2..0092f96698 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -29,6 +29,7 @@ target_sources(oran_fhlib_5g_mplane PRIVATE connect-mplane.c rpc-send-recv.c get-mplane.c + subscribe-mplane.c xml/get-xml.c ) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index e9c91387db..72f6d46701 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -22,6 +22,7 @@ #include "init-mplane.h" #include "radio/fhi_72/oran-params.h" #include "get-mplane.h" +#include "subscribe-mplane.h" #include "xml/get-xml.h" #include @@ -147,6 +148,17 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz ptp_state = true; } + /* 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; + ru_session->ru_notif.ptp_state = ptp_state; + 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"); + free(operational_ds); return true; diff --git a/radio/fhi_72/mplane/subscribe-mplane.c b/radio/fhi_72/mplane/subscribe-mplane.c new file mode 100644 index 0000000000..64215c0aba --- /dev/null +++ b/radio/fhi_72/mplane/subscribe-mplane.c @@ -0,0 +1,133 @@ +/* + * 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 "subscribe-mplane.h" +#include "rpc-send-recv.h" +#include "common/utils/assertions.h" + +#include +#include + +#ifdef MPLANE_V1 +static void recv_notif_v1(const struct nc_notif *notif, ru_notif_t *answer) +{ + const char *node_name = notif->tree->child->attr->name; + const char *value = notif->tree->child->attr->value_str; + if (strcmp(node_name, "sync-state")) { + if (strcmp(value, "LOCKED") == 0) { + answer->ptp_state = true; + } else { + answer->ptp_state = false; + } + } + + // carriers state - to be filled +} + +static void notif_clb_v1(struct nc_session *session, const struct nc_notif *notif) +{ + ru_notif_t *answer = nc_session_get_data(session); + LYD_FORMAT output_format = LYD_JSON; + + char *subs_reply = NULL; + lyd_print_mem(&subs_reply, notif->tree, output_format, LYP_WITHSIBLINGS); + MP_LOG_I("\nReceived notification at (%s)\n%s\n", notif->datetime, subs_reply); + + recv_notif_v1(notif, answer); +} +#elif MPLANE_V2 +static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer) +{ + const char *notif = op->schema->name; + + if (strcmp(notif, "synchronization-state-change") == 0) { + const char *value = lyd_get_value(op->child); + if (strcmp(value, "LOCKED") == 0) { + answer->ptp_state = true; + } else { // "FREERUN" or "HOLDOVER" + answer->ptp_state = false; + } + } else if (strcmp(notif, "rx-array-carriers-state-change") == 0) { + const char *value = lyd_get_value(lyd_child(op->child)->next); + if (strcmp(value, "READY") == 0) { + answer->rx_carrier_state = true; + } else { // "DISABLED" or "BUSY" + answer->rx_carrier_state = false; + } + } else if (strcmp(notif, "tx-array-carriers-state-change") == 0) { + const char *value = lyd_get_value(lyd_child(op->child)->next); + if (strcmp(value, "READY") == 0) { + answer->tx_carrier_state = true; + } else { // "DISABLED" or "BUSY" + answer->tx_carrier_state = false; + } + } +} + +static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op, void *user_data) +{ + ru_notif_t *answer = (ru_notif_t *)user_data; + LYD_FORMAT output_format = LYD_JSON; + + char *subs_reply = NULL; + lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS); + const char *ru_ip_add = nc_session_get_host(session); + 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); +} +#endif + +bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + char *start_time = NULL, *stop_time = NULL; + + MP_LOG_I("RPC request to RU \"%s\" = with stream \"%s\" and filter \"%s\".\n", ru_session->ru_ip_add, stream, filter); + rpc = nc_rpc_subscribe(stream, NULL, start_time, stop_time, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + /* create notification thread so that notifications can immediately be received */ +#ifdef MPLANE_V1 + if (!nc_session_ntf_thread_running(ru_session->session)) { + nc_session_set_data(ru_session->session, answer); + int ret = nc_recv_notif_dispatch(ru_session->session, notif_clb_v1); + AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n"); + } else { + MP_LOG_I("Notification thread is already running for RU %s.\n", ru_session->ru_ip_add); + } +#elif MPLANE_V2 + int ret = nc_recv_notif_dispatch_data(ru_session->session, notif_clb_v2, answer, NULL); + AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n"); +#endif + + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); + AssertError(success, return false, "[MPLANE] Failed to subscribe to: stream \"%s\", filter \"%s\".\n", stream, filter); + + MP_LOG_I("Successfully subscribed to all notifications from RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + + return true; +} diff --git a/radio/fhi_72/mplane/subscribe-mplane.h b/radio/fhi_72/mplane/subscribe-mplane.h new file mode 100644 index 0000000000..c5a6762fe9 --- /dev/null +++ b/radio/fhi_72/mplane/subscribe-mplane.h @@ -0,0 +1,31 @@ +/* + * 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 + */ + +#ifndef SUBSCRIBE_MPLANE_H +#define SUBSCRIBE_MPLANE_H + +#include "ru-mplane-api.h" + +#include + +bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer); + +#endif /* SUBSCRIBE_MPLANE_H */