Bug fix for NTS YANGs.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / app / network_function.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
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 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "network_function.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include <stdio.h>
24 #include <pthread.h>
25 #include <assert.h>
26
27 #include <sysrepo.h>
28 #include <sysrepo/values.h>
29
30 #include "core/framework.h"
31 #include "core/context.h"
32 #include "core/session.h"
33 #include "core/datastore/populate.h"
34
35 #include "core/faults/faults.h"
36
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"
43
44 #define NTS_NETWORK_FUNCTION_MODULE         "nts-network-function"
45 #define NTS_NETWORK_FUNCTION_SCHEMA_XPATH   "/nts-network-function:simulation/network-function"
46
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"
54
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);
60
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);
62
63 static int faults_update_config(sr_session_ctx_t *session);                 //not protected by lock
64 static void *faults_thread_routine(void *arg);
65
66 static pthread_mutex_t nf_function_control_lock;
67 static char *nf_function_control_string = 0;
68
69 static pthread_t faults_thread;
70 static pthread_mutex_t faults_lock;
71
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;
75
76 int network_function_run(void) {
77     assert_session();
78
79     log_message(1, LOG_COLOR_BOLD_YELLOW"\nrunning as NETWORK FUNCTION daemon...\n"LOG_COLOR_RESET);
80
81     if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) { 
82         log_error("mutex init has failed"); 
83         return NTS_ERR_FAILED; 
84     }
85
86     //populate
87     int rc = sr_rpc_subscribe(session_running, POPULATE_RPC_SCHEMA_XPATH, network_function_populate_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
88     if(rc != SR_ERR_OK) {
89         log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
90         return NTS_ERR_FAILED;
91     }
92
93     //feature control
94     rc = sr_rpc_subscribe(session_running, FEATURE_CONTROL_SCHEMA_XPATH, network_function_feature_control_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
95     if(rc != SR_ERR_OK) {
96         log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
97         return NTS_ERR_FAILED;
98     }
99
100     //faults
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");
104         return 0;
105     }
106
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));
110         return 0;
111     }
112
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;
117     }
118
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;
124     }
125
126     rc = faults_init();
127     if(rc != NTS_ERR_OK) {
128         log_error("faults_init error", sr_strerror(rc));
129         return NTS_ERR_FAILED;
130     }
131
132     if(pthread_mutex_init(&faults_lock, NULL) != 0) { 
133         log_error("mutex init has failed"); 
134         return NTS_ERR_FAILED; 
135     }
136
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;
140     }
141
142     if(pthread_mutex_init(&mount_point_addressing_method_lock, NULL) != 0) { 
143         log_error("mutex init has failed"); 
144         return NTS_ERR_FAILED; 
145     }
146
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");
153             }
154
155             rc = sr_apply_changes(session_running, 0, 0);
156             if(rc != SR_ERR_OK) {
157                 log_error("sr_apply_changes failed");
158             }
159
160             mount_point_addressing_method_val = 0;
161         }
162         pthread_mutex_unlock(&mount_point_addressing_method_lock);
163
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);
169                 if(rc != 0) {
170                     log_error("ves_file_ready_feature_start() failed");
171                 }
172             }
173
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);
177                 if(rc != 0) {
178                     log_error("ves_pnf_registration_feature_start() failed");
179                 }
180             }
181
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);
185                 if(rc != 0) {
186                     log_error("ves_heartbeat_feature_start() failed");
187                 }
188             }
189
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);
193                 if(rc != 0) {
194                     log_error("manual_notification_feature_start() failed");
195                 }
196             }
197
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);
201                 if(rc != 0) {
202                     log_error("netconf_call_home_feature_start() failed");
203                 }
204             }
205
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);
209                 if(rc != 0) {
210                     log_error("web_cut_through_feature_start() failed");
211                 }
212             }
213
214             free(nf_function_control_string);
215             nf_function_control_string = 0;
216         }
217         pthread_mutex_unlock(&nf_function_control_lock);
218
219         sleep(1);
220     }
221
222     faults_free();
223
224     return NTS_ERR_OK;
225 }
226
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) {
228     int rc;
229
230     *output_cnt = 1;
231     rc = sr_new_values(*output_cnt, output);
232     if(SR_ERR_OK != rc) {
233         return rc;
234     }
235
236     rc = sr_val_set_xpath(output[0], POPULATE_RPC_SCHEMA_XPATH"/status");
237     if(SR_ERR_OK != rc) {
238         return rc;
239     }
240
241     rc = schema_populate();
242     if(rc != NTS_ERR_OK) {
243         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
244     }
245     else {
246         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
247     }
248
249     return rc;
250 }
251
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) {
253     int rc;
254     int total_errors = 0;
255
256     *output_cnt = 1;
257     rc = sr_new_values(*output_cnt, output);
258     if(SR_ERR_OK != rc) {
259         return rc;
260     }
261
262     rc = sr_val_set_xpath(output[0], FEATURE_CONTROL_SCHEMA_XPATH"/status");
263     if(SR_ERR_OK != rc) {
264         return rc;
265     }
266
267     if(total_errors != 0) {
268         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
269     }
270     else {
271         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
272     }
273
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);
277
278     return rc;
279 }
280
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) {
282     int rc;
283
284     *output_cnt = 1;
285     rc = sr_new_values(*output_cnt, output);
286     if(SR_ERR_OK != rc) {
287         return rc;
288     }
289
290     rc = sr_val_set_xpath(output[0], FAULTS_CLEAR_SCHEMA_XPATH"/status");
291     if(SR_ERR_OK != rc) {
292         return rc;
293     }
294
295     pthread_mutex_lock(&faults_lock);
296     faults_counters_clear();
297     pthread_mutex_unlock(&faults_lock);
298
299     rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
300     return rc;
301 }
302
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) {
304     int rc = SR_ERR_OK;
305
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;
313         }
314     }
315
316     return SR_ERR_OK;
317 }
318
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);
323     char value[20];
324
325     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), FAULTS_COUNT_LIST_SCHEMA_XPATH, 0, 0, 0);
326     if(*parent == 0) {
327         return SR_ERR_OPERATION_FAILED;
328     }
329
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;
333     }
334
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;
338     }
339
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;
343     }
344
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;
348     }
349
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;
353     }
354
355     return SR_ERR_OK;
356 }
357
358 static int faults_update_config(sr_session_ctx_t *session) {
359     assert(session);
360     assert_session();
361
362     int ret = NTS_ERR_OK;
363     
364     int rc;
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;
370     }
371
372     faults_fault_list_clear();
373     faults_counters_clear();
374     if(data->child == 0) {
375         goto faults_update_config_free;
376     }
377
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;
389                     }
390                 }
391             }
392         }
393         
394     }
395     
396     faults_update_config_free:
397     lyd_free(data);
398
399     return ret;
400 }
401
402 static void *faults_thread_routine(void *arg) {
403     int rc = 0;
404
405     sr_session_ctx_t *current_session_running = 0;
406     rc = sr_session_start(session_connection, SR_DS_RUNNING, &current_session_running);
407     if (rc != SR_ERR_OK) {
408         log_error("sr_session_start failed");
409         return 0;
410     }
411
412     sr_session_ctx_t *current_session_operational = 0;
413     rc = sr_session_start(session_connection, SR_DS_OPERATIONAL, &current_session_operational);
414     if (rc != SR_ERR_OK) {
415         log_error("sr_session_start failed");
416         return 0;
417     }
418
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");
423         return 0;
424     }
425     pthread_mutex_unlock(&faults_lock);
426
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();
431
432             fault_details_t *fault = faults_generate_fault();
433             if(fault == 0) {
434                 log_error("faults_generate_fault failed");
435                 pthread_mutex_unlock(&faults_lock);
436                 sleep(1);
437                 continue;
438             }
439
440             rc = faults_counters_increase(fault->severity);
441             if(rc != NTS_ERR_OK) {
442                 log_error("faults_counters_increase failed");
443             }
444             pthread_mutex_unlock(&faults_lock);
445
446             sr_val_t *val = 0;
447             bool nc_fault_enabled = false;
448             bool ves_fault_enabled = false;
449
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;
453                 sr_free_val(val);
454             }
455
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;
459                 sr_free_val(val);
460             }
461
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);
465                 if(notif == 0) {
466                     log_error("lyd_parse_mem failed");
467                     goto fault_send_ves;
468                 }
469                 
470                 rc = sr_event_notif_send_tree(current_session_running, notif);
471                 lyd_free(notif);
472                 if(rc != SR_ERR_OK) {
473                     log_error("sr_event_notif_send_tree failed");
474                 }
475             }
476
477             fault_send_ves:
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");
482                 }
483             }
484
485             sleep(new_delay);
486         }
487         else {
488             pthread_mutex_unlock(&faults_lock);
489             sleep(1);
490         }
491     }
492
493     sr_session_stop(current_session_running);
494     sr_session_stop(current_session_operational);
495
496     return 0;
497 }
498
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;
501     int rc = SR_ERR_OK;
502     sr_change_oper_t oper;
503     sr_val_t *old_value = 0;
504     sr_val_t *new_value = 0;
505
506     static bool mount_point_addressing_method_set = false;
507
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;
513         }
514
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);
520                 }
521                 else {
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);
527                     }
528                 }
529             }
530
531             sr_free_val(old_value);
532             sr_free_val(new_value);
533         }
534
535         sr_free_change_iter(it);
536     }
537
538     return SR_ERR_OK;
539 }