From: Alex Stancu Date: Wed, 3 May 2023 13:05:24 +0000 (+0300) Subject: Monitoring Netconf connectivity feature X-Git-Tag: 1.8.1~9 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=sim%2Fo1-interface.git;a=commitdiff_plain;h=cc4e489a7955506d31fb3f87900a8d1c239bd586 Monitoring Netconf connectivity feature Issue-ID: SIM-111 Change-Id: I99a798296bca6154fd2e07b988edce6661b07ba5 Signed-off-by: Alex Stancu --- diff --git a/ntsimulator/deploy/base/build_ntsim-ng.sh b/ntsimulator/deploy/base/build_ntsim-ng.sh index 096dc3f..cbce07a 100755 --- a/ntsimulator/deploy/base/build_ntsim-ng.sh +++ b/ntsimulator/deploy/base/build_ntsim-ng.sh @@ -34,6 +34,7 @@ files=( "core/app/manager_sysrepo.c" "core/app/network_function.c" "core/app/nf_oran_du.c" + "core/app/nf_oran_ru_supervision.c" "core/app/blank.c" "core/datastore/schema.c" "core/datastore/operations.c" diff --git a/ntsimulator/deploy/o-ran-ru-fh/config.json b/ntsimulator/deploy/o-ran-ru-fh/config.json index 1934a03..4d614cf 100644 --- a/ntsimulator/deploy/o-ran-ru-fh/config.json +++ b/ntsimulator/deploy/o-ran-ru-fh/config.json @@ -1,7 +1,7 @@ { "container-rules": { "excluded-modules": [], - "excluded-features": [] + "excluded-features": ["o-ran-wg4-features:SUPERVISION-WITH-SESSION-ID"] }, "supervisor-rules": { @@ -12,7 +12,7 @@ "stdout": "log/netopeer-stdout.log", "stderr": "log/netopeer-stderr.log" }, - + "sshd": { "path": "/usr/sbin/sshd", "args": ["-D"], @@ -20,7 +20,7 @@ "stdout": "log/sshd-stdout.log", "stderr": "log/sshd-stderr.log" }, - + "ntsim-network-function": { "path": "/opt/dev/ntsim-ng/ntsim-ng", "args": ["-w/opt/dev/ntsim-ng", "-f"], @@ -53,7 +53,7 @@ "o-ran-shared-cell", "nts-network-function" ], - + "default-list-instances": 2, "custom-list-instances" : [ {"/ietf-interfaces:interfaces/interface": 4} @@ -89,7 +89,7 @@ "severity" : "MAJOR", "date-time" : "$$time$$", "specific-problem" : "Interface Fault", - + "fault-id": "30", "fault-severity" : "MAJOR", "affected-object" : "$$hostname$$", @@ -140,4 +140,4 @@ } ] } -} \ No newline at end of file +} diff --git a/ntsimulator/nts-ng-docker-image-build-ubuntu.yaml b/ntsimulator/nts-ng-docker-image-build-ubuntu.yaml index c86d387..e351e4b 100644 --- a/ntsimulator/nts-ng-docker-image-build-ubuntu.yaml +++ b/ntsimulator/nts-ng-docker-image-build-ubuntu.yaml @@ -67,6 +67,8 @@ services: labels: - "description=nts-ng" dockerfile: local.Dockerfile + depends_on: + - nts-ng-base ################################################### ####### O-RAN DU diff --git a/ntsimulator/ntsim-ng/core/app/network_function.c b/ntsimulator/ntsim-ng/core/app/network_function.c index e34d85c..c655dfb 100644 --- a/ntsimulator/ntsim-ng/core/app/network_function.c +++ b/ntsimulator/ntsim-ng/core/app/network_function.c @@ -48,6 +48,7 @@ #include "app_common.h" #include "nf_oran_du.h" +#include "nf_oran_ru_supervision.h" #define NF_FUNCTION_CONTROL_BUFFER_LENGTH 32 @@ -96,9 +97,9 @@ int network_function_run(void) { } } - if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) { - log_error("mutex init has failed\n"); - return NTS_ERR_FAILED; + if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) { + log_error("mutex init has failed\n"); + return NTS_ERR_FAILED; } //ietf-netconf-monitoring schemas populate with modules and submodules (overwrite default Netopeer2 behaviour) @@ -167,9 +168,9 @@ int network_function_run(void) { return NTS_ERR_FAILED; } - if(pthread_mutex_init(&faults_lock, NULL) != 0) { - log_error("mutex init has failed\n"); - return NTS_ERR_FAILED; + if(pthread_mutex_init(&faults_lock, NULL) != 0) { + log_error("mutex init has failed\n"); + return NTS_ERR_FAILED; } if(pthread_create(&faults_thread, 0, faults_thread_routine, 0)) { @@ -188,7 +189,7 @@ int network_function_run(void) { nf_function_control_buffer_in = 0; } - log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"running in NETWORK FUNCTION STANDALONE mode!\n"LOG_COLOR_RESET); + log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"running in NETWORK FUNCTION STANDALONE mode as a %s\n"LOG_COLOR_RESET, framework_environment.nts.function_type); log_add_verbose(1, "Currently enabled features are: %s\n", framework_environment.nts.nf_standalone_start_features); log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"Docker IP:"LOG_COLOR_RESET" %s\n", framework_environment.settings.ip_v6_enabled ? framework_environment.settings.ip_v6 : framework_environment.settings.ip_v4); log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"Docker ports"LOG_COLOR_RESET": "); @@ -222,8 +223,16 @@ int network_function_run(void) { if(strcmp(framework_environment.nts.function_type, "NTS_FUNCTION_TYPE_O_RAN_O_DU") == 0) { rc = nf_oran_du_init(); if(rc != NTS_ERR_OK) { - log_error("nf_oran_du_init failed\n"); - return NTS_ERR_FAILED; + log_error("nf_oran_du_init failed\n"); + return NTS_ERR_FAILED; + } + } + + if(strcmp(framework_environment.nts.function_type, "NTS_FUNCTION_TYPE_O_RAN_O_RU_FH") == 0) { + log_add_verbose(1, "Initializing o-ran-supervision function...\n"); + rc = nf_oran_ru_supervision_init(); + if(rc != NTS_ERR_OK) { + log_error("nf_oran_ru_supervision_init failed, continuing...\n"); } } @@ -397,7 +406,7 @@ static int netconf_monitoring_state_schemas_cb(sr_session_ctx_t *session, const if (!strcmp("sysrepo", mod->name) || !strcmp("sysrepo-monitoring", mod->name) || !strcmp("sysrepo-plugind", mod->name)) { continue; } - + list = lyd_new(root, NULL, "schema"); lyd_new_leaf(list, NULL, "identifier", mod->name); lyd_new_leaf(list, NULL, "version", (mod->rev ? mod->rev[0].date : NULL)); @@ -428,7 +437,7 @@ static int notifications_streams_cb(sr_session_ctx_t *session, const char *modul struct lyd_node *stream = lyd_new_path(root, 0, NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH"/stream[name='NETCONF']", NULL, 0, 0); lyd_new_leaf(stream, stream->schema->module, "description", "Default NETCONF stream containing notifications from all the modules. Replays only notifications for modules that support replay."); lyd_new_leaf(stream, stream->schema->module, "replaySupport", "true"); - + /* all other streams */ struct lyd_node *sr_data; struct lyd_node *sr_mod; @@ -463,7 +472,7 @@ static int notifications_streams_cb(sr_session_ctx_t *session, const char *modul rep_sup = set->set.d[0]; } ly_set_free(set); - + lyd_new_leaf(stream, NULL, "replaySupport", rep_sup ? "true" : "false"); if(rep_sup) { char buf[26]; @@ -594,7 +603,7 @@ static int network_function_feature_control_cb(sr_session_ctx_t *session, const pthread_mutex_unlock(&nf_function_control_lock); } - + return rc; } @@ -689,7 +698,7 @@ static int network_function_info_get_items_cb(sr_session_ctx_t *session, const c if(ves_file_ready_feature_get_status()) { strcat(started_features, "ves-file-ready "); } - + if(ves_pnf_registration_feature_get_status()) { strcat(started_features, "ves-pnf-registration "); } @@ -697,7 +706,7 @@ static int network_function_info_get_items_cb(sr_session_ctx_t *session, const c if(ves_heartbeat_feature_get_status()) { strcat(started_features, "ves-heartbeat "); } - + if(manual_notification_feature_get_status()) { strcat(started_features, "manual-notification-generation "); } @@ -705,7 +714,7 @@ static int network_function_info_get_items_cb(sr_session_ctx_t *session, const c if(netconf_call_home_feature_get_status()) { strcat(started_features, "netconf-call-home "); } - + if(web_cut_through_feature_get_status()) { strcat(started_features, "web-cut-through "); } @@ -738,7 +747,7 @@ static int faults_update_config(sr_session_ctx_t *session) { assert_session(); int ret = NTS_ERR_OK; - + int rc; struct lyd_node *data; rc = sr_get_subtree(session, NTS_NF_FAULT_GENERATION_SCHEMA_XPATH, 0, &data); @@ -771,9 +780,9 @@ static int faults_update_config(sr_session_ctx_t *session) { } } } - + } - + faults_update_config_free: lyd_free(data); @@ -848,7 +857,7 @@ static void *faults_thread_routine(void *arg) { log_error("lyd_parse_mem failed\n"); goto fault_send_ves; } - + rc = sr_event_notif_send_tree(current_session_running, notif); lyd_free(notif); if(rc != SR_ERR_OK) { @@ -894,7 +903,7 @@ static int network_function_change_cb(sr_session_ctx_t *session, const char *mod } while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) { - + if(new_value->xpath && (strcmp(new_value->xpath, NTS_NF_NETWORK_FUNCTION_FTYPE_SCHEMA_XPATH) == 0)) { if(old_value && !old_value->dflt) { rc = sr_set_item(session, old_value->xpath, old_value, 0); diff --git a/ntsimulator/ntsim-ng/core/app/nf_oran_du.c b/ntsimulator/ntsim-ng/core/app/nf_oran_du.c index 2bdd63c..4c429f4 100644 --- a/ntsimulator/ntsim-ng/core/app/nf_oran_du.c +++ b/ntsimulator/ntsim-ng/core/app/nf_oran_du.c @@ -116,7 +116,7 @@ int nf_oran_du_init(void) { if(value_count) { log_add_verbose(2, "pm jobs already found (%d). cleaning up for fresh start...\n", value_count); - for(int i = 0; i < value_count; i++) { + for(int i = 0; i < value_count; i++) { rc = sr_delete_item(session_running, values[i].xpath, 0); if(rc != SR_ERR_OK) { log_error("sr_delete_item failed\n"); @@ -336,7 +336,7 @@ static int pm_jobs_change_cb(sr_session_ctx_t *session, const char *module_name, } } else if(oper == SR_OP_DELETED) { - int job_id = -1; + int job_id = -1; for(int i = 0; i < pm_jobs_count; i++) { if(strcmp(pm_jobs[i]->id, old_value->data.string_val) == 0) { job_id = i; @@ -350,7 +350,7 @@ static int pm_jobs_change_cb(sr_session_ctx_t *session, const char *module_name, pm_job_t *job = pm_jobs[job_id]; job->terminate = 1; - + //remove from list for(int i = job_id; i < pm_jobs_count - 1; i++) { pm_jobs[i] = pm_jobs[i + 1]; @@ -395,7 +395,7 @@ static void *pm_job_thread_routine(void *arg) { sleep(1); } log_add_verbose(1, "pm_job_thread_routine[%s] finished waiting...\n", job->id); - + char *xpath_to_get = 0; asprintf(&xpath_to_get, "%s[id='%s']", NTS_NF_ORAN_DU_PM_JOBS_SCHEMA_XPATH, job->id); if(xpath_to_get == 0) { @@ -461,7 +461,7 @@ static void *pm_job_thread_routine(void *arg) { if(strcmp(chd->schema->name, "performance-metrics") == 0) { const char *val = ((const struct lyd_node_leaf_list *)chd)->value_str; - + job->performance_metrics_count++; job->performance_metrics = (char **)realloc(job->performance_metrics, sizeof(char **) * job->performance_metrics_count); if(job->performance_metrics == 0) { @@ -534,7 +534,7 @@ static void *pm_job_thread_routine(void *arg) { asprintf(&details.field_value[3], "%d", job->granularity_period); details.field_name[4] = strdup("%%job-id%%"); details.field_value[4] = strdup(job->id); - + long int now = get_microseconds_since_epoch() / 1000000; long int start_time = now - (now % job->granularity_period); long int end_time = start_time + job->granularity_period; @@ -546,7 +546,7 @@ static void *pm_job_thread_routine(void *arg) { asprintf(&details.field_value[6], "%lu", end_time); details.field_name[7] = strdup("%%starttime-literal%%"); - + struct tm tm = *localtime(&now); asprintf(&details.field_value[7], "%04d-%02d-%02dT%02d:%02d:%02d.%01dZ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, @@ -604,7 +604,7 @@ static void *pm_job_thread_routine(void *arg) { static void nf_du_template_free(nf_du_template_details_t *details) { assert(details); - + for(int j = 0; j < details->field_count; j++) { free(details->field_name[j]); free(details->field_value[j]); @@ -631,7 +631,7 @@ static char *nf_du_template_process_vars(const char *template, const nf_du_templ char **vars = 0; int vars_count = 0; - + char **funcs = 0; int funcs_count = 0; @@ -831,7 +831,7 @@ static char *nf_du_template_process_function(const char *function, const nf_du_t log_error("str_replace failed\n"); return 0; } - + int nl = strlen(ci) + 2; //\0 and perhaps comma char *ret2 = (char *)malloc(sizeof(char) * (strlen(ret) + nl)); if(ret2 == 0) { @@ -860,7 +860,7 @@ static char *nf_du_template_process_function(const char *function, const nf_du_t } else if(strcmp(function, "$$uint32_counter$$") == 0) { char *ret = 0; - + asprintf(&ret, "%d", details->job->stream->counter); details->job->stream->counter++; return ret; diff --git a/ntsimulator/ntsim-ng/core/app/nf_oran_ru_supervision.c b/ntsimulator/ntsim-ng/core/app/nf_oran_ru_supervision.c new file mode 100644 index 0000000..7d12fce --- /dev/null +++ b/ntsimulator/ntsim-ng/core/app/nf_oran_ru_supervision.c @@ -0,0 +1,159 @@ +/************************************************************************* +* +* Copyright 2021 highstreet technologies GmbH and others +* +* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +* +* 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. +***************************************************************************/ + +#define _GNU_SOURCE + +#include "nf_oran_ru_supervision.h" +#include "utils/log_utils.h" +#include "utils/sys_utils.h" +#include "utils/nts_utils.h" +#include "utils/rand_utils.h" +#include "utils/http_client.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core/framework.h" +#include "core/context.h" +#include "core/session.h" +#include "core/xpath.h" + +int notification_timer_seconds=60; +int supervision_timer_seconds=10; + +static pthread_t o_ran_supervision_thread = NULL; +static void *o_ran_supervision_thread_routine(void *arg); + +static int +supervision_watchdog_reset_rpc_cb(sr_session_ctx_t *session, const char *path, const sr_val_t *input, const size_t input_cnt, + sr_event_t event, uint32_t request_id, sr_val_t **output, size_t *output_cnt, void *private_data) +{ + size_t i; + + (void)session; + (void)event; + (void)request_id; + (void)private_data; + + bool notification_default = true; + bool supervision_default = true; + + for (i = 0; i < input_cnt; ++i) { + if (!strcmp(input[i].xpath, "/o-ran-supervision:supervision-watchdog-reset/supervision-notification-interval")) { + notification_timer_seconds = input[i].data.uint16_val; + notification_default = false; + } + else if (!strcmp(input[i].xpath, "/o-ran-supervision:supervision-watchdog-reset/guard-timer-overhead")) { + supervision_timer_seconds = input[i].data.uint16_val; + supervision_default = false; + } + } + + if (notification_default) { + notification_timer_seconds = 60; + } + if (supervision_default) { + supervision_timer_seconds = 10; + } + + if (!strcmp(path, "/o-ran-supervision:supervision-watchdog-reset")) { + *output = malloc(sizeof **output); + *output_cnt = 1; + + (*output)[0].xpath = strdup("/o-ran-supervision:supervision-watchdog-reset/next-update-at"); + (*output)[0].type = SR_STRING_T; + (*output)[0].dflt = 0; + (*output)[0].data.string_val = get_current_date_and_time_delay_seconds(notification_timer_seconds); + } + + if (o_ran_supervision_thread != NULL) { + pthread_cancel(o_ran_supervision_thread); + o_ran_supervision_thread = NULL; + } + + if(pthread_create(&o_ran_supervision_thread, 0, o_ran_supervision_thread_routine, 0)) { + log_error("could not create thread for o-ran-supervision\n"); + return NTS_ERR_FAILED; + } + + return NTS_ERR_OK; +} + +int nf_oran_ru_supervision_init(void) { + int rc; + + rc = sr_rpc_subscribe(session_running, O_RAN_SUPERVISION_WATCHDOG_RESET_RPC_SCHEMA_XPATH, supervision_watchdog_reset_rpc_cb, NULL, 0, 0, &session_subscription); + if (rc != SR_ERR_OK) { + log_add_verbose(1, "Subscribing for RPC \"%s\" failed.\n", O_RAN_SUPERVISION_WATCHDOG_RESET_RPC_SCHEMA_XPATH); + return NTS_ERR_FAILED; + } + + if(pthread_create(&o_ran_supervision_thread, 0, o_ran_supervision_thread_routine, 0)) { + log_error("could not create thread for o-ran-supervision\n"); + return NTS_ERR_FAILED; + } + + return NTS_ERR_OK; +} + +static void *o_ran_supervision_thread_routine(void *arg) { + int notification_counter = notification_timer_seconds; + int supervision_counter = notification_timer_seconds + supervision_timer_seconds; + int rc; + + log_add_verbose(1, "Starting thread for o-ran-supervision...\n"); + + struct lyd_node *notif = NULL; + notif = lyd_new_path(NULL, session_context, O_RAN_SUPERVISION_NOTIFICATION_SCHEMA_XPATH, NULL, 0, 0); + if (!notif) { + log_error("Creating notification \"%s\" failed.\n", O_RAN_SUPERVISION_NOTIFICATION_SCHEMA_XPATH); + return NTS_ERR_FAILED; + } + + while (supervision_counter > 0) { + sleep(1); + supervision_counter--; + notification_counter--; + + if (notification_counter == 0) { + log_add_verbose(1, "Sending o-ran-supervision supervision-notification..\n"); + rc = sr_event_notif_send_tree(session_running, notif); + if (rc != SR_ERR_OK) { + lyd_free(notif); + return NTS_ERR_FAILED; + } + } + } + + log_add_verbose(1, "Failed to receive watchdog reset, terminating supervision timer for o-ran-supervision...\n"); + pthread_exit((void *)1); +} + +void nf_oran_ru_supervision_free(void) { + +} + diff --git a/ntsimulator/ntsim-ng/core/app/nf_oran_ru_supervision.h b/ntsimulator/ntsim-ng/core/app/nf_oran_ru_supervision.h new file mode 100644 index 0000000..f663d73 --- /dev/null +++ b/ntsimulator/ntsim-ng/core/app/nf_oran_ru_supervision.h @@ -0,0 +1,21 @@ +/************************************************************************* +* +* Copyright 2023 highstreet technologies GmbH and others +* +* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +* +* 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. +***************************************************************************/ + +#pragma once + +int nf_oran_ru_supervision_init(void); +void nf_oran_ru_supervision_free(void); diff --git a/ntsimulator/ntsim-ng/core/xpath.h b/ntsimulator/ntsim-ng/core/xpath.h index 984ed9b..b74bb90 100644 --- a/ntsimulator/ntsim-ng/core/xpath.h +++ b/ntsimulator/ntsim-ng/core/xpath.h @@ -96,3 +96,7 @@ #define NC_NOTIFICATIONS_MODULE "nc-notifications" #define NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH "/nc-notifications:netconf/streams" + +#define O_RAN_SUPERVISION_NOTIFICATION_SCHEMA_XPATH "/o-ran-supervision:supervision-notification" +#define O_RAN_SUPERVISION_NOTIFICATION_SESSION_ID_SCHEMA_XPATH "/o-ran-supervision:supervision-notification/session-id" +#define O_RAN_SUPERVISION_WATCHDOG_RESET_RPC_SCHEMA_XPATH "/o-ran-supervision:supervision-watchdog-reset" diff --git a/ntsimulator/ntsim-ng/utils/sys_utils.c b/ntsimulator/ntsim-ng/utils/sys_utils.c index 2b93d52..66ad6d3 100644 --- a/ntsimulator/ntsim-ng/utils/sys_utils.c +++ b/ntsimulator/ntsim-ng/utils/sys_utils.c @@ -135,6 +135,25 @@ char *get_current_date_and_time(void) { return date_and_time; } +char *get_current_date_and_time_delay_seconds(int seconds) { + char *date_and_time = 0; + + time_t t = time(0); + struct tm tm = *localtime(&t); + struct timeval tv; + + gettimeofday(&tv, 0); + + tm.tm_sec += seconds; + mktime(&tm); + + asprintf(&date_and_time, "%04d-%02d-%02dT%02d:%02d:%02d.0Z", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + return date_and_time; +} + long int get_microseconds_since_epoch(void) { time_t t = time(0); struct timeval tv; diff --git a/ntsimulator/ntsim-ng/utils/sys_utils.h b/ntsimulator/ntsim-ng/utils/sys_utils.h index eea514c..152f395 100644 --- a/ntsimulator/ntsim-ng/utils/sys_utils.h +++ b/ntsimulator/ntsim-ng/utils/sys_utils.h @@ -38,6 +38,7 @@ char *file_read_content(const char *fname); int get_int_from_string_with_default(const char *string, int default_value); char *get_current_date_and_time(void); +char *get_current_date_and_time_delay_seconds(int seconds); long int get_microseconds_since_epoch(void); //networking functions