1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
20 #include "network_function.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
28 #include <sysrepo/values.h>
30 #include "core/framework.h"
31 #include "core/context.h"
32 #include "core/session.h"
33 #include "core/datastore/populate.h"
35 #include "core/faults/faults.h"
37 #include "features/ves_pnf_registration/ves_pnf_registration.h"
38 #include "features/ves_heartbeat/ves_heartbeat.h"
39 #include "features/ves_file_ready/ves_file_ready.h"
40 #include "features/manual_notification/manual_notification.h"
41 #include "features/netconf_call_home/netconf_call_home.h"
43 #define POPULATE_RPC_SCHEMA_XPATH "/nts-network-function:datastore-random-populate"
44 #define FEATURE_CONTROL_SCHEMA_XPATH "/nts-network-function:feature-control"
45 #define FAULTS_CLEAR_SCHEMA_XPATH "/nts-network-function:clear-fault-counters"
46 #define FAULTS_LIST_SCHEMA_XPATH "/nts-network-function:simulation/network-function/fault-generation"
47 #define FAULTS_COUNT_LIST_SCHEMA_XPATH "/nts-network-function:simulation/network-function/fault-generation/fault-count"
48 #define FAULTS_NC_ENABLED_SCHEMA_XPATH "/nts-network-function:simulation/network-function/netconf/faults-enabled"
49 #define FAULTS_VES_ENABLED_SCHEMA_XPATH "/nts-network-function:simulation/network-function/ves/faults-enabled"
51 static int network_function_populate_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);
52 static int network_function_feature_control_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);
53 static int network_function_faults_clear_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);
54 static int network_function_faults_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data);
55 static int network_function_faults_count_get_items_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data);
57 static int faults_update_config(sr_session_ctx_t *session); //not protected by lock
58 static void *faults_thread_routine(void *arg);
60 static pthread_mutex_t nf_function_control_lock;
61 static char *nf_function_control_string = 0;
63 static pthread_t faults_thread;
64 static pthread_mutex_t faults_lock;
66 int network_function_run(void) {
69 log_message(1, LOG_COLOR_BOLD_YELLOW"\nrunning as NETWORK FUNCTION daemon...\n"LOG_COLOR_RESET);
71 if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) {
72 log_error("mutex init has failed");
73 return NTS_ERR_FAILED;
77 int rc = sr_rpc_subscribe(session_running, POPULATE_RPC_SCHEMA_XPATH, network_function_populate_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
79 log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
80 return NTS_ERR_FAILED;
84 rc = sr_rpc_subscribe(session_running, FEATURE_CONTROL_SCHEMA_XPATH, network_function_feature_control_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
86 log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
87 return NTS_ERR_FAILED;
91 rc = sr_module_change_subscribe(session_running, "nts-network-function", FAULTS_LIST_SCHEMA_XPATH, network_function_faults_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
93 log_error("could not subscribe to faults");
97 rc = sr_oper_get_items_subscribe(session_running, "nts-network-function", FAULTS_COUNT_LIST_SCHEMA_XPATH, network_function_faults_count_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
99 log_error("could not subscribe to oper faults: %s", sr_strerror(rc));
103 rc = sr_rpc_subscribe(session_running, FAULTS_CLEAR_SCHEMA_XPATH, network_function_faults_clear_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
104 if(rc != SR_ERR_OK) {
105 log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
106 return NTS_ERR_FAILED;
110 if(rc != NTS_ERR_OK) {
111 log_error("faults_init error", sr_strerror(rc));
112 return NTS_ERR_FAILED;
115 if(pthread_mutex_init(&faults_lock, NULL) != 0) {
116 log_error("mutex init has failed");
117 return NTS_ERR_FAILED;
120 if(pthread_create(&faults_thread, 0, faults_thread_routine, 0)) {
121 log_error("could not create thread for heartbeat");
122 return NTS_ERR_FAILED;
125 while(!framework_sigint) {
127 pthread_mutex_lock(&nf_function_control_lock);
128 if(nf_function_control_string) {
129 if(strstr(nf_function_control_string, "ves-file-ready") != 0) {
130 // start feature for handling the fileReady VES message
131 rc = ves_file_ready_feature_start(session_running);
133 log_error("ves_file_ready_feature_start() failed");
137 if(strstr(nf_function_control_string, "ves-pnf-registration") != 0) {
138 // check if PNF registration is enabled and send PNF registration message if so
139 rc = ves_pnf_registration_feature_start(session_running);
141 log_error("ves_pnf_registration_feature_start() failed");
145 if(strstr(nf_function_control_string, "ves-heartbeat") != 0) {
146 // start feature for handling the heartbeat VES message
147 rc = ves_heartbeat_feature_start(session_running);
149 log_error("ves_heartbeat_feature_start() failed");
153 if(strstr(nf_function_control_string, "manual-notification-generation") != 0) {
154 // start feature for manual notification
155 rc = manual_notification_feature_start(session_running);
157 log_error("manual_notification_feature_start() failed");
161 if(strstr(nf_function_control_string, "netconf-call-home") != 0) {
162 // start feature for NETCONF Call Home
163 rc = netconf_call_home_feature_start(session_running);
165 log_error("netconf_call_home_feature_start() failed");
169 free(nf_function_control_string);
170 nf_function_control_string = 0;
172 pthread_mutex_unlock(&nf_function_control_lock);
182 static int network_function_populate_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) {
186 rc = sr_new_values(*output_cnt, output);
187 if(SR_ERR_OK != rc) {
191 rc = sr_val_set_xpath(output[0], POPULATE_RPC_SCHEMA_XPATH"/status");
192 if(SR_ERR_OK != rc) {
196 rc = schema_populate();
197 if(rc != NTS_ERR_OK) {
198 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
201 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
207 static int network_function_feature_control_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) {
209 int total_errors = 0;
212 rc = sr_new_values(*output_cnt, output);
213 if(SR_ERR_OK != rc) {
217 rc = sr_val_set_xpath(output[0], FEATURE_CONTROL_SCHEMA_XPATH"/status");
218 if(SR_ERR_OK != rc) {
222 if(total_errors != 0) {
223 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
226 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
229 pthread_mutex_lock(&nf_function_control_lock);
230 nf_function_control_string = strdup(input[0].data.bits_val);
231 pthread_mutex_unlock(&nf_function_control_lock);
236 static int network_function_faults_clear_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) {
240 rc = sr_new_values(*output_cnt, output);
241 if(SR_ERR_OK != rc) {
245 rc = sr_val_set_xpath(output[0], FAULTS_CLEAR_SCHEMA_XPATH"/status");
246 if(SR_ERR_OK != rc) {
250 pthread_mutex_lock(&faults_lock);
251 faults_counters_clear();
252 pthread_mutex_unlock(&faults_lock);
254 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
258 static int network_function_faults_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
261 if(event == SR_EV_DONE) {
262 pthread_mutex_lock(&faults_lock);
263 rc = faults_update_config(session);
264 pthread_mutex_unlock(&faults_lock);
265 if(rc != NTS_ERR_OK) {
266 log_error("faults_update_config failed");
267 return SR_ERR_VALIDATION_FAILED;
274 static int network_function_faults_count_get_items_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data) {
275 pthread_mutex_lock(&faults_lock);
276 fault_counters_t counters = faults_counters_get();
277 pthread_mutex_unlock(&faults_lock);
280 *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), FAULTS_COUNT_LIST_SCHEMA_XPATH, 0, 0, 0);
282 return SR_ERR_OPERATION_FAILED;
285 sprintf(value, "%d", counters.normal);
286 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/normal", value, 0, 0) == 0) {
287 return SR_ERR_OPERATION_FAILED;
290 sprintf(value, "%d", counters.warning);
291 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/warning", value, 0, 0) == 0) {
292 return SR_ERR_OPERATION_FAILED;
295 sprintf(value, "%d", counters.minor);
296 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/minor", value, 0, 0) == 0) {
297 return SR_ERR_OPERATION_FAILED;
300 sprintf(value, "%d", counters.major);
301 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/major", value, 0, 0) == 0) {
302 return SR_ERR_OPERATION_FAILED;
305 sprintf(value, "%d", counters.critical);
306 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/critical", value, 0, 0) == 0) {
307 return SR_ERR_OPERATION_FAILED;
313 static int faults_update_config(sr_session_ctx_t *session) {
317 int ret = NTS_ERR_OK;
320 struct lyd_node *data;
321 rc = sr_get_subtree(session, FAULTS_LIST_SCHEMA_XPATH, 0, &data);
322 if(rc != SR_ERR_OK) {
323 log_error("sr_get_subtree failed");
324 ret = NTS_ERR_FAILED;
327 faults_fault_list_clear();
328 faults_counters_clear();
329 if(data->child == 0) {
330 goto faults_update_config_free;
333 struct lyd_node *chd = 0;
334 LY_TREE_FOR(data->child, chd) {
335 if(strcmp(chd->schema->name, "fault-delay-list") == 0) {
336 struct lyd_node *delay_list_entry = 0;
337 LY_TREE_FOR(chd->child, delay_list_entry) {
338 if(strcmp(delay_list_entry->schema->name, "delay-period") == 0) {
339 rc = faults_fault_list_add(((const struct lyd_node_leaf_list *)delay_list_entry)->value.uint16);
340 if(rc != NTS_ERR_OK) {
341 log_error("faults_fault_list_add failed");
342 ret = NTS_ERR_FAILED;
343 goto faults_update_config_free;
351 faults_update_config_free:
357 static void *faults_thread_routine(void *arg) {
360 sr_session_ctx_t *current_session_running = 0;
361 rc = sr_session_start(session_connection, SR_DS_RUNNING, ¤t_session_running);
362 if (rc != SR_ERR_OK) {
363 log_error("sr_session_start failed");
367 sr_session_ctx_t *current_session_operational = 0;
368 rc = sr_session_start(session_connection, SR_DS_OPERATIONAL, ¤t_session_operational);
369 if (rc != SR_ERR_OK) {
370 log_error("sr_session_start failed");
374 pthread_mutex_lock(&faults_lock);
375 rc = faults_update_config(current_session_running);
376 if(rc != NTS_ERR_OK) {
377 log_error("faults_update_config failed");
380 pthread_mutex_unlock(&faults_lock);
382 while(!framework_sigint) {
383 pthread_mutex_lock(&faults_lock);
384 if(faults_fault_list_not_empty()) {
385 uint16_t new_delay = faults_fault_list_get_next();
387 fault_details_t *fault = faults_generate_fault();
389 log_error("faults_generate_fault failed");
390 pthread_mutex_unlock(&faults_lock);
395 rc = faults_counters_increase(fault->severity);
396 if(rc != NTS_ERR_OK) {
397 log_error("faults_counters_increase failed");
399 pthread_mutex_unlock(&faults_lock);
402 bool nc_fault_enabled = false;
403 bool ves_fault_enabled = false;
405 rc = sr_get_item(current_session_running, FAULTS_NC_ENABLED_SCHEMA_XPATH, 0, &val);
406 if(rc == SR_ERR_OK) {
407 nc_fault_enabled = val->data.bool_val;
411 rc = sr_get_item(current_session_running, FAULTS_VES_ENABLED_SCHEMA_XPATH, 0, &val);
412 if(rc == SR_ERR_OK) {
413 ves_fault_enabled = val->data.bool_val;
417 if(nc_fault_enabled) {
418 struct lyd_node *notif = 0;
419 notif = lyd_parse_mem(session_context, fault->yang_notif_processed, LYD_XML, LYD_OPT_NOTIF, 0);
421 log_error("lyd_parse_mem failed");
425 rc = sr_event_notif_send_tree(current_session_running, notif);
427 if(rc != SR_ERR_OK) {
428 log_error("sr_event_notif_send_tree failed");
433 if(ves_fault_enabled) {
434 rc = faults_ves_message_send(current_session_running, fault->condition, fault->object, fault->severity, fault->date_time, fault->specific_problem);
435 if(rc != NTS_ERR_OK) {
436 log_error("faults_ves_message_send failed");
443 pthread_mutex_unlock(&faults_lock);
448 sr_session_stop(current_session_running);
449 sr_session_stop(current_session_operational);