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"
42 #include "features/web_cut_through/web_cut_through.h"
44 #define NTS_NETWORK_FUNCTION_MODULE "nts-network-function"
45 #define NTS_NETWORK_FUNCTION_SCHEMA_XPATH "/nts-network-function:simulation/network-function"
47 #define POPULATE_RPC_SCHEMA_XPATH "/nts-network-function:datastore-random-populate"
48 #define FEATURE_CONTROL_SCHEMA_XPATH "/nts-network-function:feature-control"
49 #define FAULTS_CLEAR_SCHEMA_XPATH "/nts-network-function:clear-fault-counters"
50 #define FAULTS_LIST_SCHEMA_XPATH "/nts-network-function:simulation/network-function/fault-generation"
51 #define FAULTS_COUNT_LIST_SCHEMA_XPATH "/nts-network-function:simulation/network-function/fault-generation/fault-count"
52 #define FAULTS_NC_ENABLED_SCHEMA_XPATH "/nts-network-function:simulation/network-function/netconf/faults-enabled"
53 #define FAULTS_VES_ENABLED_SCHEMA_XPATH "/nts-network-function:simulation/network-function/ves/faults-enabled"
55 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);
56 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);
57 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);
58 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);
59 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);
61 static int network_function_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);
63 static int faults_update_config(sr_session_ctx_t *session); //not protected by lock
64 static void *faults_thread_routine(void *arg);
66 static pthread_mutex_t nf_function_control_lock;
67 static char *nf_function_control_string = 0;
69 static pthread_t faults_thread;
70 static pthread_mutex_t faults_lock;
72 static pthread_mutex_t mount_point_addressing_method_lock;
73 static char *mount_point_addressing_method_default = 0;
74 static char *mount_point_addressing_method_val = 0;
76 int network_function_run(void) {
79 log_message(1, LOG_COLOR_BOLD_YELLOW"\nrunning as NETWORK FUNCTION daemon...\n"LOG_COLOR_RESET);
81 if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) {
82 log_error("mutex init has failed");
83 return NTS_ERR_FAILED;
87 int rc = sr_rpc_subscribe(session_running, POPULATE_RPC_SCHEMA_XPATH, network_function_populate_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
89 log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
90 return NTS_ERR_FAILED;
94 rc = sr_rpc_subscribe(session_running, FEATURE_CONTROL_SCHEMA_XPATH, network_function_feature_control_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
96 log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
97 return NTS_ERR_FAILED;
101 rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, FAULTS_LIST_SCHEMA_XPATH, network_function_faults_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
102 if(rc != SR_ERR_OK) {
103 log_error("could not subscribe to faults");
107 rc = sr_oper_get_items_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, FAULTS_COUNT_LIST_SCHEMA_XPATH, network_function_faults_count_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
108 if(rc != SR_ERR_OK) {
109 log_error("could not subscribe to oper faults: %s", sr_strerror(rc));
113 rc = sr_rpc_subscribe(session_running, FAULTS_CLEAR_SCHEMA_XPATH, network_function_faults_clear_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
114 if(rc != SR_ERR_OK) {
115 log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
116 return NTS_ERR_FAILED;
119 //subscribe to any changes on the main
120 rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NETWORK_FUNCTION_SCHEMA_XPATH, network_function_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
121 if(rc != SR_ERR_OK) {
122 log_error("could not subscribe to simulation changes");
123 return NTS_ERR_FAILED;
127 if(rc != NTS_ERR_OK) {
128 log_error("faults_init error", sr_strerror(rc));
129 return NTS_ERR_FAILED;
132 if(pthread_mutex_init(&faults_lock, NULL) != 0) {
133 log_error("mutex init has failed");
134 return NTS_ERR_FAILED;
137 if(pthread_create(&faults_thread, 0, faults_thread_routine, 0)) {
138 log_error("could not create thread for heartbeat");
139 return NTS_ERR_FAILED;
142 if(pthread_mutex_init(&mount_point_addressing_method_lock, NULL) != 0) {
143 log_error("mutex init has failed");
144 return NTS_ERR_FAILED;
147 while(!framework_sigint) {
148 pthread_mutex_lock(&mount_point_addressing_method_lock);
149 if(mount_point_addressing_method_val) {
150 rc = sr_set_item_str(session_running, NTS_NETWORK_FUNCTION_SCHEMA_XPATH"/mount-point-addressing-method", mount_point_addressing_method_val, 0, 0);
151 if(rc != SR_ERR_OK) {
152 log_error("sr_set_item_str failed");
155 rc = sr_apply_changes(session_running, 0, 0);
156 if(rc != SR_ERR_OK) {
157 log_error("sr_apply_changes failed");
160 mount_point_addressing_method_val = 0;
162 pthread_mutex_unlock(&mount_point_addressing_method_lock);
164 pthread_mutex_lock(&nf_function_control_lock);
165 if(nf_function_control_string) {
166 if(strstr(nf_function_control_string, "ves-file-ready") != 0) {
167 // start feature for handling the fileReady VES message
168 rc = ves_file_ready_feature_start(session_running);
170 log_error("ves_file_ready_feature_start() failed");
174 if(strstr(nf_function_control_string, "ves-pnf-registration") != 0) {
175 // check if PNF registration is enabled and send PNF registration message if so
176 rc = ves_pnf_registration_feature_start(session_running);
178 log_error("ves_pnf_registration_feature_start() failed");
182 if(strstr(nf_function_control_string, "ves-heartbeat") != 0) {
183 // start feature for handling the heartbeat VES message
184 rc = ves_heartbeat_feature_start(session_running);
186 log_error("ves_heartbeat_feature_start() failed");
190 if(strstr(nf_function_control_string, "manual-notification-generation") != 0) {
191 // start feature for manual notification
192 rc = manual_notification_feature_start(session_running);
194 log_error("manual_notification_feature_start() failed");
198 if(strstr(nf_function_control_string, "netconf-call-home") != 0) {
199 // start feature for NETCONF Call Home
200 rc = netconf_call_home_feature_start(session_running);
202 log_error("netconf_call_home_feature_start() failed");
206 if(strstr(nf_function_control_string, "web-cut-through") != 0) {
207 // start feature for NETCONF Call Home
208 rc = web_cut_through_feature_start(session_running);
210 log_error("web_cut_through_feature_start() failed");
214 free(nf_function_control_string);
215 nf_function_control_string = 0;
217 pthread_mutex_unlock(&nf_function_control_lock);
227 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) {
231 rc = sr_new_values(*output_cnt, output);
232 if(SR_ERR_OK != rc) {
236 rc = sr_val_set_xpath(output[0], POPULATE_RPC_SCHEMA_XPATH"/status");
237 if(SR_ERR_OK != rc) {
241 rc = schema_populate();
242 if(rc != NTS_ERR_OK) {
243 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
246 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
252 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) {
254 int total_errors = 0;
257 rc = sr_new_values(*output_cnt, output);
258 if(SR_ERR_OK != rc) {
262 rc = sr_val_set_xpath(output[0], FEATURE_CONTROL_SCHEMA_XPATH"/status");
263 if(SR_ERR_OK != rc) {
267 if(total_errors != 0) {
268 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
271 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
274 pthread_mutex_lock(&nf_function_control_lock);
275 nf_function_control_string = strdup(input[0].data.bits_val);
276 pthread_mutex_unlock(&nf_function_control_lock);
281 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) {
285 rc = sr_new_values(*output_cnt, output);
286 if(SR_ERR_OK != rc) {
290 rc = sr_val_set_xpath(output[0], FAULTS_CLEAR_SCHEMA_XPATH"/status");
291 if(SR_ERR_OK != rc) {
295 pthread_mutex_lock(&faults_lock);
296 faults_counters_clear();
297 pthread_mutex_unlock(&faults_lock);
299 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
303 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) {
306 if(event == SR_EV_DONE) {
307 pthread_mutex_lock(&faults_lock);
308 rc = faults_update_config(session);
309 pthread_mutex_unlock(&faults_lock);
310 if(rc != NTS_ERR_OK) {
311 log_error("faults_update_config failed");
312 return SR_ERR_VALIDATION_FAILED;
319 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) {
320 pthread_mutex_lock(&faults_lock);
321 fault_counters_t counters = faults_counters_get();
322 pthread_mutex_unlock(&faults_lock);
325 *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), FAULTS_COUNT_LIST_SCHEMA_XPATH, 0, 0, 0);
327 return SR_ERR_OPERATION_FAILED;
330 sprintf(value, "%d", counters.normal);
331 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/normal", value, 0, 0) == 0) {
332 return SR_ERR_OPERATION_FAILED;
335 sprintf(value, "%d", counters.warning);
336 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/warning", value, 0, 0) == 0) {
337 return SR_ERR_OPERATION_FAILED;
340 sprintf(value, "%d", counters.minor);
341 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/minor", value, 0, 0) == 0) {
342 return SR_ERR_OPERATION_FAILED;
345 sprintf(value, "%d", counters.major);
346 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/major", value, 0, 0) == 0) {
347 return SR_ERR_OPERATION_FAILED;
350 sprintf(value, "%d", counters.critical);
351 if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/critical", value, 0, 0) == 0) {
352 return SR_ERR_OPERATION_FAILED;
358 static int faults_update_config(sr_session_ctx_t *session) {
362 int ret = NTS_ERR_OK;
365 struct lyd_node *data;
366 rc = sr_get_subtree(session, FAULTS_LIST_SCHEMA_XPATH, 0, &data);
367 if(rc != SR_ERR_OK) {
368 log_error("sr_get_subtree failed");
369 ret = NTS_ERR_FAILED;
372 faults_fault_list_clear();
373 faults_counters_clear();
374 if(data->child == 0) {
375 goto faults_update_config_free;
378 struct lyd_node *chd = 0;
379 LY_TREE_FOR(data->child, chd) {
380 if(strcmp(chd->schema->name, "fault-delay-list") == 0) {
381 struct lyd_node *delay_list_entry = 0;
382 LY_TREE_FOR(chd->child, delay_list_entry) {
383 if(strcmp(delay_list_entry->schema->name, "delay-period") == 0) {
384 rc = faults_fault_list_add(((const struct lyd_node_leaf_list *)delay_list_entry)->value.uint16);
385 if(rc != NTS_ERR_OK) {
386 log_error("faults_fault_list_add failed");
387 ret = NTS_ERR_FAILED;
388 goto faults_update_config_free;
396 faults_update_config_free:
402 static void *faults_thread_routine(void *arg) {
405 sr_session_ctx_t *current_session_running = 0;
406 rc = sr_session_start(session_connection, SR_DS_RUNNING, ¤t_session_running);
407 if (rc != SR_ERR_OK) {
408 log_error("sr_session_start failed");
412 sr_session_ctx_t *current_session_operational = 0;
413 rc = sr_session_start(session_connection, SR_DS_OPERATIONAL, ¤t_session_operational);
414 if (rc != SR_ERR_OK) {
415 log_error("sr_session_start failed");
419 pthread_mutex_lock(&faults_lock);
420 rc = faults_update_config(current_session_running);
421 if(rc != NTS_ERR_OK) {
422 log_error("faults_update_config failed");
425 pthread_mutex_unlock(&faults_lock);
427 while(!framework_sigint) {
428 pthread_mutex_lock(&faults_lock);
429 if(faults_fault_list_not_empty()) {
430 uint16_t new_delay = faults_fault_list_get_next();
432 fault_details_t *fault = faults_generate_fault();
434 log_error("faults_generate_fault failed");
435 pthread_mutex_unlock(&faults_lock);
440 rc = faults_counters_increase(fault->severity);
441 if(rc != NTS_ERR_OK) {
442 log_error("faults_counters_increase failed");
444 pthread_mutex_unlock(&faults_lock);
447 bool nc_fault_enabled = false;
448 bool ves_fault_enabled = false;
450 rc = sr_get_item(current_session_running, FAULTS_NC_ENABLED_SCHEMA_XPATH, 0, &val);
451 if(rc == SR_ERR_OK) {
452 nc_fault_enabled = val->data.bool_val;
456 rc = sr_get_item(current_session_running, FAULTS_VES_ENABLED_SCHEMA_XPATH, 0, &val);
457 if(rc == SR_ERR_OK) {
458 ves_fault_enabled = val->data.bool_val;
462 if(nc_fault_enabled) {
463 struct lyd_node *notif = 0;
464 notif = lyd_parse_mem(session_context, fault->yang_notif_processed, LYD_XML, LYD_OPT_NOTIF, 0);
466 log_error("lyd_parse_mem failed");
470 rc = sr_event_notif_send_tree(current_session_running, notif);
472 if(rc != SR_ERR_OK) {
473 log_error("sr_event_notif_send_tree failed");
478 if(ves_fault_enabled) {
479 rc = faults_ves_message_send(current_session_running, fault->condition, fault->object, fault->severity, fault->date_time, fault->specific_problem);
480 if(rc != NTS_ERR_OK) {
481 log_error("faults_ves_message_send failed");
488 pthread_mutex_unlock(&faults_lock);
493 sr_session_stop(current_session_running);
494 sr_session_stop(current_session_operational);
499 static int network_function_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) {
500 sr_change_iter_t *it = 0;
502 sr_change_oper_t oper;
503 sr_val_t *old_value = 0;
504 sr_val_t *new_value = 0;
506 static bool mount_point_addressing_method_set = false;
508 if(event == SR_EV_DONE) {
509 rc = sr_get_changes_iter(session, NTS_NETWORK_FUNCTION_SCHEMA_XPATH"//.", &it);
510 if(rc != SR_ERR_OK) {
511 log_error("sr_get_changes_iter failed");
512 return SR_ERR_VALIDATION_FAILED;
515 while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
516 if(new_value->xpath && (strcmp(new_value->xpath, NTS_NETWORK_FUNCTION_SCHEMA_XPATH"/mount-point-addressing-method") == 0)) {
517 if(mount_point_addressing_method_set == false) {
518 mount_point_addressing_method_set = true;
519 mount_point_addressing_method_default = strdup(new_value->data.string_val);
522 //prevent changing mount_point_addressing_method
523 if(strcmp(new_value->data.string_val, mount_point_addressing_method_default) != 0) {
524 pthread_mutex_lock(&mount_point_addressing_method_lock);
525 mount_point_addressing_method_val = mount_point_addressing_method_default;
526 pthread_mutex_unlock(&mount_point_addressing_method_lock);
531 sr_free_val(old_value);
532 sr_free_val(new_value);
535 sr_free_change_iter(it);