Add RPC send and receive functionalities
This commit is contained in:
@@ -27,6 +27,7 @@ target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE)
|
||||
target_sources(oran_fhlib_5g_mplane PRIVATE
|
||||
init-mplane.c
|
||||
connect-mplane.c
|
||||
rpc-send-recv.c
|
||||
)
|
||||
|
||||
pkg_check_modules(libyang REQUIRED libyang)
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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 "rpc-send-recv.h"
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
static bool recv_v1(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
|
||||
{
|
||||
struct nc_reply *reply;
|
||||
struct nc_reply_data *data_rpl;
|
||||
struct nc_reply_error *error;
|
||||
LYD_FORMAT output_format = LYD_XML;
|
||||
uint32_t ly_wd;
|
||||
|
||||
while (1) {
|
||||
msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, 0, &reply);
|
||||
if (msgtype == NC_MSG_ERROR) {
|
||||
AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n");
|
||||
} else if (msgtype == NC_MSG_WOULDBLOCK) {
|
||||
AssertError(false, return false, "[MPLANE] Timeout for receiving a reply expired.\n");
|
||||
} else if (msgtype == NC_MSG_NOTIF) {
|
||||
/* read again */
|
||||
continue;
|
||||
} else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
|
||||
/* unexpected message, try reading again to get the correct reply */
|
||||
MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n");
|
||||
nc_reply_free(reply);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (reply->type) {
|
||||
case NC_RPL_OK:
|
||||
MP_LOG_I("RPC reply = OK.\n");
|
||||
break;
|
||||
case NC_RPL_DATA:
|
||||
data_rpl = (struct nc_reply_data *)reply;
|
||||
|
||||
switch (wd_mode) {
|
||||
case NC_WD_ALL:
|
||||
ly_wd = LYP_WD_ALL;
|
||||
break;
|
||||
case NC_WD_ALL_TAG:
|
||||
ly_wd = LYP_WD_ALL_TAG;
|
||||
break;
|
||||
case NC_WD_TRIM:
|
||||
ly_wd = LYP_WD_TRIM;
|
||||
break;
|
||||
case NC_WD_EXPLICIT:
|
||||
ly_wd = LYP_WD_EXPLICIT;
|
||||
break;
|
||||
default:
|
||||
ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN
|
||||
break;
|
||||
}
|
||||
|
||||
if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) {
|
||||
AssertError((!data_rpl->data || (data_rpl->data->schema->nodetype != LYS_RPC) || (data_rpl->data->child == NULL)
|
||||
|| (data_rpl->data->child->schema->nodetype != LYS_ANYXML)), return false, "[MPLANE] Cannot get schema.\n");
|
||||
|
||||
struct lyd_node_anydata *any = (struct lyd_node_anydata *)data_rpl->data->child;
|
||||
switch (any->value_type) {
|
||||
case LYD_ANYDATA_CONSTSTRING:
|
||||
case LYD_ANYDATA_STRING:
|
||||
*answer = strdup(any->value.str);
|
||||
break;
|
||||
case LYD_ANYDATA_DATATREE:
|
||||
lyd_print_mem(answer, any->value.tree, output_format, LYP_WITHSIBLINGS);
|
||||
break;
|
||||
case LYD_ANYDATA_XML:
|
||||
lyxml_print_mem(answer, any->value.xml, LYXML_PRINT_SIBLINGS);
|
||||
break;
|
||||
default:
|
||||
AssertError(false, return false, "[MPLANE] Unknown yang type.\n");
|
||||
}
|
||||
break;
|
||||
} else if (nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG || nc_rpc_get_type(rpc) == NC_RPC_GET) {
|
||||
const char *tag = nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG ? "config" : "data";
|
||||
char *buffer = NULL;
|
||||
lyd_print_mem(&buffer, data_rpl->data, output_format, LYP_WITHSIBLINGS | LYP_NETCONF | ly_wd);
|
||||
*answer = calloc(strlen(buffer)+128, sizeof(char));
|
||||
sprintf(*answer, "<%s xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n%s</%s>", tag, buffer, tag);
|
||||
} else {
|
||||
AssertError(false, return false, "[MPLANE] Unknown RPC type.\n");
|
||||
}
|
||||
|
||||
break;
|
||||
case NC_RPL_ERROR:
|
||||
error = (struct nc_reply_error *)reply;
|
||||
for (int i = 0; i < error->count; ++i) {
|
||||
const struct nc_err *err = &error->err[i];
|
||||
MP_LOG_I("RPC reply = ERROR\n\
|
||||
\ttype: %s\n\
|
||||
\ttag: %s\n\
|
||||
\tseverity: %s\n\
|
||||
\tapp-tag: %s\n\
|
||||
\tpath: %s\n\
|
||||
\tmessage: %s\n\
|
||||
\tSID: %s\n",
|
||||
err->type,
|
||||
err->tag,
|
||||
err->severity,
|
||||
err->apptag,
|
||||
err->path,
|
||||
err->message,
|
||||
err->sid);
|
||||
|
||||
for (int j = 0; j < err->attr_count; ++j) {
|
||||
MP_LOG_I("\tbad-attr #%d: %s\n", j + 1, err->attr[j]);
|
||||
}
|
||||
for (int j = 0; j < err->elem_count; ++j) {
|
||||
MP_LOG_I("\tbad-elem #%d: %s\n", j + 1, err->elem[j]);
|
||||
}
|
||||
for (int j = 0; j < err->ns_count; ++j) {
|
||||
MP_LOG_I("\tbad-ns #%d: %s\n", j + 1, err->ns[j]);
|
||||
}
|
||||
for (int j = 0; j < err->other_count; ++j) {
|
||||
char *str = NULL;
|
||||
lyxml_print_mem(&str, err->other[j], 0);
|
||||
MP_LOG_I("\tother #%d:\n%s\n", j + 1, str);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
AssertError(false, return false, "[MPLANE] Unable to continue.\n");
|
||||
break;
|
||||
default:
|
||||
AssertError(false, return false, "[MPLANE] Internal error.\n");
|
||||
nc_reply_free(reply);
|
||||
}
|
||||
nc_reply_free(reply);
|
||||
|
||||
return true;
|
||||
}
|
||||
#elif defined MPLANE_V2
|
||||
static bool recv_v2(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
|
||||
{
|
||||
struct lyd_node *envp, *op, *err;
|
||||
LYD_FORMAT output_format = LYD_XML;
|
||||
uint32_t ly_wd;
|
||||
|
||||
while (1) {
|
||||
msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, &envp, &op);
|
||||
if (msgtype == NC_MSG_ERROR) {
|
||||
AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n");
|
||||
} else if (msgtype == NC_MSG_WOULDBLOCK) {
|
||||
AssertError(false, return false, "[MPLANE] Timeout for receiving a reply for RPC expired.\n");
|
||||
} else if (msgtype == NC_MSG_NOTIF) { // for SUBSCRIBE
|
||||
/* read again */
|
||||
continue;
|
||||
} else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
|
||||
/* unexpected message, try reading again to get the correct reply */
|
||||
MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n");
|
||||
lyd_free_tree(envp);
|
||||
lyd_free_tree(op);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* get functionality */
|
||||
if (op) {
|
||||
/* data reply */
|
||||
if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) {
|
||||
/* special case */
|
||||
if (!lyd_child(op) || (lyd_child(op)->schema->nodetype != LYS_ANYXML)) {
|
||||
AssertError(false, return false, "[MPLANE] Cannot get schema.");
|
||||
}
|
||||
struct lyd_node_any *any = (struct lyd_node_any *)lyd_child(op);
|
||||
switch (any->value_type) {
|
||||
case LYD_ANYDATA_STRING:
|
||||
case LYD_ANYDATA_XML:
|
||||
*answer = strdup(any->value.str);
|
||||
break;
|
||||
case LYD_ANYDATA_DATATREE:
|
||||
lyd_print_mem(answer, any->value.tree, output_format, LYD_PRINT_WITHSIBLINGS);
|
||||
break;
|
||||
default:
|
||||
AssertError(false, return false, "[MPLANE] Unexpected yang type.");
|
||||
}
|
||||
} else {
|
||||
switch (wd_mode) {
|
||||
case NC_WD_ALL:
|
||||
ly_wd = LYD_PRINT_WD_ALL;
|
||||
break;
|
||||
case NC_WD_ALL_TAG:
|
||||
ly_wd = LYD_PRINT_WD_ALL_TAG;
|
||||
break;
|
||||
case NC_WD_TRIM:
|
||||
ly_wd = LYD_PRINT_WD_TRIM;
|
||||
break;
|
||||
case NC_WD_EXPLICIT:
|
||||
ly_wd = LYD_PRINT_WD_EXPLICIT;
|
||||
break;
|
||||
default:
|
||||
ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN
|
||||
break;
|
||||
}
|
||||
lyd_print_mem(answer, lyd_child(op), output_format, LYD_PRINT_WITHSIBLINGS | ly_wd);
|
||||
}
|
||||
/* edit/validate/commit functionalities */
|
||||
} else if (!strcmp(LYD_NAME(lyd_child(envp)), "ok")) {
|
||||
MP_LOG_I("RPC reply = OK.\n");
|
||||
} else {
|
||||
LY_LIST_FOR(lyd_child(envp), err) {
|
||||
struct lyd_node *type, *tag, *severity, *app_tag, *path, *er_msg, *info = NULL;
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &type);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &tag);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-severity", &severity);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &app_tag);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &path);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &er_msg);
|
||||
|
||||
MP_LOG_I("RPC reply = ERROR\n\
|
||||
\ttype: %s\n\
|
||||
\ttag: %s\n\
|
||||
\tseverity: %s\n\
|
||||
\tapp-tag: %s\n\
|
||||
\tpath: %s\n\
|
||||
\tmessage: %s\n",
|
||||
(type ? ((struct lyd_node_opaq *)type)->value : NULL),
|
||||
(tag ? ((struct lyd_node_opaq *)tag)->value : NULL),
|
||||
(severity ? ((struct lyd_node_opaq *)severity)->value : NULL),
|
||||
(app_tag ? ((struct lyd_node_opaq *)app_tag)->value : NULL),
|
||||
(path ? ((struct lyd_node_opaq *)path)->value : NULL),
|
||||
(er_msg ? ((struct lyd_node_opaq *)er_msg)->value : NULL));
|
||||
|
||||
info = lyd_child(err);
|
||||
while (!lyd_find_sibling_opaq_next(info, "error-info", &info)) {
|
||||
char *str = NULL;
|
||||
lyd_print_mem(&str, lyd_child(info), output_format, LYD_PRINT_WITHSIBLINGS);
|
||||
MP_LOG_I("\tinfo: %s\n", str);
|
||||
info = info->next;
|
||||
free(str);
|
||||
}
|
||||
lyd_free_tree(type);
|
||||
lyd_free_tree(tag);
|
||||
lyd_free_tree(severity);
|
||||
lyd_free_tree(app_tag);
|
||||
lyd_free_tree(path);
|
||||
lyd_free_tree(er_msg);
|
||||
lyd_free_tree(info);
|
||||
}
|
||||
lyd_free_tree(envp);
|
||||
lyd_free_tree(op);
|
||||
AssertError(false, return false, "[MPLANE] Unable to continue.\n");
|
||||
}
|
||||
|
||||
lyd_free_tree(envp);
|
||||
lyd_free_tree(op);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
|
||||
{
|
||||
uint64_t msgid;
|
||||
NC_MSG_TYPE msgtype;
|
||||
|
||||
msgtype = nc_send_rpc(session, rpc, 1000, &msgid);
|
||||
if (msgtype == NC_MSG_ERROR) {
|
||||
AssertError(false, return false, "[MPLANE] Failed to send the RPC.\n");
|
||||
} else if (msgtype == NC_MSG_WOULDBLOCK) {
|
||||
AssertError(false, return false, "[MPLANE] Timeout for sending the RPC expired.\n");
|
||||
}
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
return recv_v1(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer);
|
||||
#elif defined MPLANE_V2
|
||||
return recv_v2(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer);
|
||||
#else
|
||||
AssertError(false, return false, "[MPLANE] Unknown M-plane version found. Tried \"MPLANE_V1\" and \"MPLANE_V2\".\n");
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 RPC_SEND_RECEIVE_MPLANE_H
|
||||
#define RPC_SEND_RECEIVE_MPLANE_H
|
||||
|
||||
#include "ru-mplane-api.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <nc_client.h>
|
||||
|
||||
#define CLI_RPC_REPLY_TIMEOUT 60000 // time [ms] to wait for server reply
|
||||
|
||||
bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer);
|
||||
|
||||
#endif /* RPC_SEND_RECEIVE_MPLANE_H */
|
||||
Reference in New Issue
Block a user