Add NETCONF CallHome via TLS feature.
[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 "utils/nts_utils.h"
24 #include <stdio.h>
25 #include <pthread.h>
26 #include <assert.h>
27
28 #include <sysrepo.h>
29 #include <sysrepo/values.h>
30 #include <libnetconf2/netconf.h>
31
32 #include "core/framework.h"
33 #include "core/context.h"
34 #include "core/session.h"
35 #include "core/xpath.h"
36 #include "core/datastore/populate.h"
37
38 #include "core/faults/faults.h"
39
40 #include "features/ves_pnf_registration/ves_pnf_registration.h"
41 #include "features/ves_heartbeat/ves_heartbeat.h"
42 #include "features/ves_file_ready/ves_file_ready.h"
43 #include "features/manual_notification/manual_notification.h"
44 #include "features/netconf_call_home/netconf_call_home.h"
45 #include "features/web_cut_through/web_cut_through.h"
46
47 #include "app_common.h"
48
49 #define NF_FUNCTION_CONTROL_BUFFER_LENGTH                       32
50
51 static int netconf_monitoring_state_schemas_cb(sr_session_ctx_t *session, const char *module_name, const char *path, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data);
52 static int notifications_streams_cb(sr_session_ctx_t *session, const char *module_name, const char *path, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data);
53
54 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);
55 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);
56 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);
57 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);
58 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);
59 static int network_function_info_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_buffer[NF_FUNCTION_CONTROL_BUFFER_LENGTH];
68 static int nf_function_control_buffer_in;
69 static int nf_function_control_buffer_out;
70
71 static pthread_t faults_thread;
72 static pthread_mutex_t faults_lock;
73
74 int network_function_run(void) {
75     assert_session();
76
77     nf_function_control_buffer_in = 0;
78     nf_function_control_buffer_out = 0;
79
80     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"running as NETWORK FUNCTION daemon...\n"LOG_COLOR_RESET);
81
82     int rc = app_common_init();
83     if(rc != NTS_ERR_OK) {
84         log_error("app_common_init failed\n");
85         return NTS_ERR_FAILED;
86     }
87
88     if(strlen(framework_environment.nts.nf_standalone_start_features)) {
89         rc = nts_utils_populate_info(session_running, framework_environment.nts.function_type);
90         if(rc != NTS_ERR_OK) {
91             log_error("nts_utils_populate_info failed\n");
92             return NTS_ERR_FAILED;
93         }
94     }
95
96     if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) { 
97         log_error("mutex init has failed\n"); 
98         return NTS_ERR_FAILED; 
99     }
100
101     //ietf-netconf-monitoring schemas populate with modules and submodules (overwrite default Netopeer2 behaviour)
102     rc = sr_oper_get_items_subscribe(session_running, IETF_NETCONF_MONITORING_MODULE, IETF_NETCONF_MONITORING_STATE_SCHEMAS_SCHEMA_XPATH, netconf_monitoring_state_schemas_cb, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
103     if(rc != SR_ERR_OK) {
104         log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
105         return 0;
106     }
107
108     //nc-notifications overwrite
109     rc = sr_oper_get_items_subscribe(session_running, NC_NOTIFICATIONS_MODULE, NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH, notifications_streams_cb, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
110     if(rc != SR_ERR_OK) {
111         log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
112         return 0;
113     }
114
115     //populate
116     rc = sr_rpc_subscribe(session_running, NTS_NF_RPC_POPULATE_SCHEMA_XPATH, network_function_populate_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
117     if(rc != SR_ERR_OK) {
118         log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
119         return NTS_ERR_FAILED;
120     }
121
122     //feature control
123     rc = sr_rpc_subscribe(session_running, NTS_NF_RPC_FEATURE_CONTROL_SCHEMA_XPATH, network_function_feature_control_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
124     if(rc != SR_ERR_OK) {
125         log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
126         return NTS_ERR_FAILED;
127     }
128
129     //faults
130     rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_FAULT_GENERATION_SCHEMA_XPATH, network_function_faults_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
131     if(rc != SR_ERR_OK) {
132         log_error("could not subscribe to faults");
133         return NTS_ERR_FAILED;
134     }
135
136     rc = sr_oper_get_items_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH, network_function_faults_count_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
137     if(rc != SR_ERR_OK) {
138         log_error("could not subscribe to oper faults: %s\n", sr_strerror(rc));
139         return NTS_ERR_FAILED;
140     }
141
142     rc = sr_rpc_subscribe(session_running, NTS_NF_RPC_FAULTS_CLEAR_SCHEMA_XPATH, network_function_faults_clear_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
143     if(rc != SR_ERR_OK) {
144         log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
145         return NTS_ERR_FAILED;
146     }
147
148     rc = sr_oper_get_items_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_INFO_SCHEMA_XPATH, network_function_info_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_OPER_MERGE, &session_subscription);
149     if(rc != SR_ERR_OK) {
150         log_error("could not subscribe to oper started-features: %s\n", sr_strerror(rc));
151         return NTS_ERR_FAILED;
152     }
153
154     //subscribe to any changes on the main
155     rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_NETWORK_FUNCTION_SCHEMA_XPATH, network_function_change_cb, NULL, 1, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
156     if(rc != SR_ERR_OK) {
157         log_error("could not subscribe to simulation changes: %s\n", sr_strerror(rc));
158         return NTS_ERR_FAILED;
159     }
160
161     rc = faults_init();
162     if(rc != NTS_ERR_OK) {
163         log_error("faults_init error\n");
164         return NTS_ERR_FAILED;
165     }
166
167     if(pthread_mutex_init(&faults_lock, NULL) != 0) { 
168         log_error("mutex init has failed\n"); 
169         return NTS_ERR_FAILED; 
170     }
171
172     if(pthread_create(&faults_thread, 0, faults_thread_routine, 0)) {
173         log_error("could not create thread for heartbeat\n");
174         return NTS_ERR_FAILED;
175     }
176
177     //check standalone mode
178     if(strlen(framework_environment.nts.nf_standalone_start_features)) {
179         char *start_features = 0;
180
181         asprintf(&start_features, "1 %s", framework_environment.nts.nf_standalone_start_features);
182         nf_function_control_buffer[nf_function_control_buffer_in] = start_features;
183         nf_function_control_buffer_in++;
184         if(nf_function_control_buffer_in >= NF_FUNCTION_CONTROL_BUFFER_LENGTH) {
185             nf_function_control_buffer_in = 0;
186         }
187
188         log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"running in NETWORK FUNCTION STANDALONE mode!\n"LOG_COLOR_RESET);
189         log_add_verbose(1, "Currently enabled features are: %s\n", framework_environment.nts.nf_standalone_start_features);
190         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);
191         log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"Docker ports"LOG_COLOR_RESET": ");
192         if(framework_environment.settings.ssh_connections) {
193             log_add(1, "NETCONF SSH: %d (%d)", STANDARD_NETCONF_PORT, framework_environment.settings.ssh_connections);
194         }
195         else {
196             log_add(1, "NETCONF SSH: disabled");
197         }
198         if(framework_environment.settings.tls_connections) {
199             log_add(1, " | NETCONF TLS: %d (%d)", STANDARD_NETCONF_PORT + framework_environment.settings.ssh_connections, framework_environment.settings.tls_connections);
200         }
201         else {
202             log_add(1, " | NETCONF TLS: disabled");
203         }
204         if(framework_environment.settings.ftp_connections) {
205             log_add(1, " | FTP: %d (%d)", STANDARD_FTP_PORT, framework_environment.settings.ftp_connections);
206         }
207         else {
208             log_add(1, " | FTP: disabled");
209         }
210         if(framework_environment.settings.sftp_connections) {
211             log_add(1, " | SFTP: %d (%d)", STANDARD_SFTP_PORT, framework_environment.settings.sftp_connections);
212         }
213         else {
214             log_add(1, " | SFTP: disabled");
215         }
216         log_add(1,"\n");
217     }
218
219     while(!framework_sigint) {
220         pthread_mutex_lock(&nf_function_control_lock);
221         while(nf_function_control_buffer_in != nf_function_control_buffer_out) {
222             //get current function control string
223             char *nf_function_control_string = nf_function_control_buffer[nf_function_control_buffer_out];
224             nf_function_control_buffer_out++;
225             if(nf_function_control_buffer_out >= NF_FUNCTION_CONTROL_BUFFER_LENGTH) {
226                 nf_function_control_buffer_out = 0;
227             }
228
229             if(strstr(nf_function_control_string, "datastore-populate") != 0) {
230                 rc = datastore_populate(3);
231                 if(rc != NTS_ERR_OK) {
232                     log_error("datastore_populate() failed\n");
233                 }
234             }
235
236             if(strstr(nf_function_control_string, "ves-file-ready") != 0) {
237                 if(nf_function_control_string[0] == '1') {
238                     // start feature for handling the fileReady VES message
239                     rc = ves_file_ready_feature_start(session_running);
240                     if(rc != 0) {
241                         log_error("ves_file_ready_feature_start() failed\n");
242                     }
243                 }
244                 else if(nf_function_control_string[0] == '0') {
245                     // stop feature for handling the fileReady VES message
246                     rc = ves_file_ready_feature_stop();
247                     if(rc != 0) {
248                         log_error("ves_file_ready_feature_stop() failed\n");
249                     }
250                 }
251             }
252
253             if(strstr(nf_function_control_string, "ves-pnf-registration") != 0) {
254                 if(nf_function_control_string[0] == '1') {
255                     // check if PNF registration is enabled and send PNF registration message if so
256                     rc = ves_pnf_registration_feature_start(session_running);
257                     if(rc != 0) {
258                         log_error("ves_pnf_registration_feature_start() failed\n");
259                     }
260                 }
261             }
262
263             if(strstr(nf_function_control_string, "ves-heartbeat") != 0) {
264                 if(nf_function_control_string[0] == '1') {
265                     // start feature for handling the heartbeat VES message
266                     rc = ves_heartbeat_feature_start(session_running);
267                     if(rc != 0) {
268                         log_error("ves_heartbeat_feature_start() failed\n");
269                     }
270                 }
271                 else if(nf_function_control_string[0] == '0') {
272                     // stop feature for handling the heartbeat VES message
273                     rc = ves_heartbeat_feature_stop();
274                     if(rc != 0) {
275                         log_error("ves_heartbeat_feature_stop() failed\n");
276                     }
277                 }
278             }
279
280             if(strstr(nf_function_control_string, "manual-notification-generation") != 0) {
281                 if(nf_function_control_string[0] == '1') {
282                     // start feature for manual notification
283                     rc = manual_notification_feature_start(session_running);
284                     if(rc != 0) {
285                         log_error("manual_notification_feature_start() failed\n");
286                     }
287                 }
288                 else if(nf_function_control_string[0] == '0') {
289                     // stop feature for manual notification
290                     rc = manual_notification_feature_stop();
291                     if(rc != 0) {
292                         log_error("manual_notification_feature_stop() failed\n");
293                     }
294                 }
295             }
296
297             if(strstr(nf_function_control_string, "netconf-call-home") != 0) {
298                 if(nf_function_control_string[0] == '1') {
299                     // start feature for NETCONF Call Home
300                     rc = netconf_call_home_feature_start(session_running);
301                     if(rc != 0) {
302                         log_error("netconf_call_home_feature_start() failed\n");
303                     }
304                 }
305             }
306
307             if(strstr(nf_function_control_string, "web-cut-through") != 0) {
308                 if(nf_function_control_string[0] == '1') {
309                     // start feature for web cut-through
310                     rc = web_cut_through_feature_start(session_running);
311                     if(rc != 0) {
312                         log_error("web_cut_through_feature_start() failed\n");
313                     }
314                 }
315                 else if(nf_function_control_string[0] == '0') {
316                     // stop feature for web cut-through
317                     rc = web_cut_through_feature_stop(session_running);
318                     if(rc != 0) {
319                         log_error("web_cut_through_feature_stop() failed\n");
320                     }
321                 }
322             }
323
324             free(nf_function_control_string);
325             nf_function_control_string = 0;
326         }
327         pthread_mutex_unlock(&nf_function_control_lock);
328
329         sleep(1);
330     }
331
332     faults_free();
333
334     return NTS_ERR_OK;
335 }
336
337 static int netconf_monitoring_state_schemas_cb(sr_session_ctx_t *session, const char *module_name, const char *path, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data) {
338     struct lyd_node *root = 0;
339     root = lyd_new_path(*parent, session_context, IETF_NETCONF_MONITORING_STATE_SCHEMAS_SCHEMA_XPATH, 0, 0, 0);
340
341     struct lyd_node *list = 0;
342     const struct lys_module *mod = 0;
343     const struct lys_submodule *submod = 0;
344     uint32_t i = 0;
345
346     // get all modules from context
347     while ((mod = ly_ctx_get_module_iter(session_context, &i))) {
348         // we skip the internal sysrepo modules
349         if (!strcmp("sysrepo", mod->name) || !strcmp("sysrepo-monitoring", mod->name) || !strcmp("sysrepo-plugind", mod->name)) {
350             continue;
351         }
352         
353         list = lyd_new(root, NULL, "schema");
354         lyd_new_leaf(list, NULL, "identifier", mod->name);
355         lyd_new_leaf(list, NULL, "version", (mod->rev ? mod->rev[0].date : NULL));
356         lyd_new_leaf(list, NULL, "format", "yang");
357         lyd_new_leaf(list, NULL, "namespace", lys_main_module(mod)->ns);
358         lyd_new_leaf(list, NULL, "location", "NETCONF");
359
360         // iterate all the submodules included by a module
361         for (int j = 0; j < mod->inc_size; j++) {
362             submod = mod->inc[j].submodule;
363
364             list = lyd_new(root, NULL, "schema");
365             lyd_new_leaf(list, NULL, "identifier", submod->name);
366             lyd_new_leaf(list, NULL, "version", (submod->rev ? submod->rev[0].date : NULL));
367             lyd_new_leaf(list, NULL, "format", "yang");
368             lyd_new_leaf(list, NULL, "namespace", lys_main_module(mod)->ns);
369             lyd_new_leaf(list, NULL, "location", "NETCONF");
370         }
371     }
372
373     return SR_ERR_OK;
374 }
375
376 static int notifications_streams_cb(sr_session_ctx_t *session, const char *module_name, const char *path, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data) {
377     struct lyd_node *root = lyd_new_path(0, session_context, NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH, 0, 0, 0);
378
379     /* generic stream */
380     struct lyd_node *stream = lyd_new_path(root, 0, NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH"/stream[name='NETCONF']", NULL, 0, 0);
381     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.");
382     lyd_new_leaf(stream, stream->schema->module, "replaySupport", "true");
383     
384     /* all other streams */
385     struct lyd_node *sr_data;
386     struct lyd_node *sr_mod;
387      /* go through all the sysrepo modules */
388     int rc = sr_get_module_info(session_connection, &sr_data);
389     if(rc != SR_ERR_OK) {
390         log_error("sr_get_module_info failed\n");
391         return SR_ERR_OPERATION_FAILED;
392     }
393
394     LY_TREE_FOR(sr_data->child, sr_mod) {
395         const char *mod_name = ((struct lyd_node_leaf_list *)sr_mod->child)->value_str;
396         const struct lys_module *mod = ly_ctx_get_module(session_context, mod_name, 0, 1);
397         int has_notifications = 0;
398         struct lys_node *data = mod->data;
399         while(data) {
400             if(data->nodetype == LYS_NOTIF) {
401                 has_notifications = 1;
402             }
403             data = data->next;
404         }
405
406         if(has_notifications) {
407             /* generate information about the stream/module */
408             stream = lyd_new(root->child, NULL, "stream");
409             lyd_new_leaf(stream, NULL, "name", mod_name);
410             lyd_new_leaf(stream, NULL, "description", "Stream with all notifications of a module.");
411
412             struct lyd_node *rep_sup = 0;
413             struct ly_set *set = lyd_find_path(sr_mod, "replay-support");
414             if(set && (set->number == 1)) {
415                 rep_sup = set->set.d[0];
416             }
417             ly_set_free(set);
418             
419             lyd_new_leaf(stream, NULL, "replaySupport", rep_sup ? "true" : "false");
420             if(rep_sup) {
421                 char buf[26];
422                 nc_time2datetime(((struct lyd_node_leaf_list *)rep_sup)->value.uint64, NULL, buf);
423                 lyd_new_leaf(stream, NULL, "replayLogCreationTime", buf);
424             }
425         }
426     }
427
428     lyd_free_withsiblings(sr_data);
429     *parent = root;
430
431     return SR_ERR_OK;
432 }
433
434 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) {
435     int rc;
436
437     *output_cnt = 1;
438     rc = sr_new_values(*output_cnt, output);
439     if(SR_ERR_OK != rc) {
440         return rc;
441     }
442
443     rc = sr_val_set_xpath(output[0], NTS_NF_RPC_POPULATE_SCHEMA_XPATH"/status");
444     if(SR_ERR_OK != rc) {
445         return rc;
446     }
447
448     pthread_mutex_lock(&nf_function_control_lock);
449     nf_function_control_buffer[nf_function_control_buffer_in] = strdup("datastore-populate");
450     nf_function_control_buffer_in++;
451     if(nf_function_control_buffer_in >= NF_FUNCTION_CONTROL_BUFFER_LENGTH) {
452         nf_function_control_buffer_in = 0;
453     }
454     pthread_mutex_unlock(&nf_function_control_lock);
455
456     rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
457     return rc;
458 }
459
460 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) {
461     int rc;
462     int total_errors = 0;
463
464     char start_features[16][64];
465     int start_features_cnt = 0;
466
467     char stop_features[16][64];
468     int stop_features_cnt = 0;
469
470     char *start_input = 0;
471     char *stop_input = 0;
472
473     for(int i = 0; i < input_cnt; i++) {
474         if(input[i].data.bits_val == 0) {
475             continue;
476         }
477
478         char *val = strdup(input[i].data.bits_val);
479
480         if(strstr(input[i].xpath, "start")) {
481             start_input = input[i].data.bits_val;
482
483             const char *tok = " ";
484             char *token = strtok(val, tok);
485             while(token) {
486                 strcpy(start_features[start_features_cnt++], token);
487                 token = strtok(0, tok);
488             }
489         }
490
491         if(strstr(input[i].xpath, "stop")) {
492             stop_input = input[i].data.bits_val;
493
494             const char *tok = " ";
495             char *token = strtok(val, tok);
496             while(token) {
497                 strcpy(stop_features[stop_features_cnt++], token);
498                 token = strtok(0, tok);
499             }
500         }
501
502         free(val);
503     }
504
505     for(int i = 0; i < start_features_cnt; i++) {
506         for(int j = 0; j < stop_features_cnt; j++) {
507             if(strcmp(start_features[i], stop_features[j]) == 0) {
508                 total_errors++;
509             }
510         }
511     }
512
513     *output_cnt = 1;
514     rc = sr_new_values(*output_cnt, output);
515     if(SR_ERR_OK != rc) {
516         return rc;
517     }
518
519     rc = sr_val_set_xpath(output[0], NTS_NF_RPC_FEATURE_CONTROL_SCHEMA_XPATH"/status");
520     if(SR_ERR_OK != rc) {
521         return rc;
522     }
523
524     if(total_errors != 0) {
525         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
526     }
527     else {
528         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
529
530         pthread_mutex_lock(&nf_function_control_lock);
531         if(start_features_cnt) {
532             asprintf(&nf_function_control_buffer[nf_function_control_buffer_in], "1 %s", start_input);
533             nf_function_control_buffer_in++;
534             if(nf_function_control_buffer_in >= NF_FUNCTION_CONTROL_BUFFER_LENGTH) {
535                 nf_function_control_buffer_in = 0;
536             }
537         }
538
539         if(stop_features_cnt) {
540             asprintf(&nf_function_control_buffer[nf_function_control_buffer_in], "0 %s", stop_input);
541             nf_function_control_buffer_in++;
542             if(nf_function_control_buffer_in >= NF_FUNCTION_CONTROL_BUFFER_LENGTH) {
543                 nf_function_control_buffer_in = 0;
544             }
545         }
546         pthread_mutex_unlock(&nf_function_control_lock);
547     }
548
549     
550
551     return rc;
552 }
553
554 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) {
555     int rc;
556
557     *output_cnt = 1;
558     rc = sr_new_values(*output_cnt, output);
559     if(SR_ERR_OK != rc) {
560         return rc;
561     }
562
563     rc = sr_val_set_xpath(output[0], NTS_NF_RPC_FAULTS_CLEAR_SCHEMA_XPATH"/status");
564     if(SR_ERR_OK != rc) {
565         return rc;
566     }
567
568     pthread_mutex_lock(&faults_lock);
569     faults_counters_clear();
570     pthread_mutex_unlock(&faults_lock);
571
572     rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
573     return rc;
574 }
575
576 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) {
577     int rc = SR_ERR_OK;
578
579     if(event == SR_EV_DONE) {
580         pthread_mutex_lock(&faults_lock);
581         rc = faults_update_config(session);
582         pthread_mutex_unlock(&faults_lock);
583         if(rc != NTS_ERR_OK) {
584             log_error("faults_update_config failed\n");
585             return SR_ERR_VALIDATION_FAILED;
586         }
587     }
588
589     return SR_ERR_OK;
590 }
591
592 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) {
593     pthread_mutex_lock(&faults_lock);
594     fault_counters_t counters = faults_counters_get();
595     pthread_mutex_unlock(&faults_lock);
596     char value[20];
597
598     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH, 0, 0, 0);
599     if(*parent == 0) {
600         log_error("lyd_new_path failed\n");
601         return SR_ERR_OPERATION_FAILED;
602     }
603
604     sprintf(value, "%d", counters.normal);
605     if(lyd_new_path(*parent, NULL, NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH"/normal", value, 0, 0) == 0) {
606         log_error("lyd_new_path failed\n");
607         return SR_ERR_OPERATION_FAILED;
608     }
609
610     sprintf(value, "%d", counters.warning);
611     if(lyd_new_path(*parent, NULL, NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH"/warning", value, 0, 0) == 0) {
612         log_error("lyd_new_path failed\n");
613         return SR_ERR_OPERATION_FAILED;
614     }
615
616     sprintf(value, "%d", counters.minor);
617     if(lyd_new_path(*parent, NULL, NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH"/minor", value, 0, 0) == 0) {
618         log_error("lyd_new_path failed\n");
619         return SR_ERR_OPERATION_FAILED;
620     }
621
622     sprintf(value, "%d", counters.major);
623     if(lyd_new_path(*parent, NULL, NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH"/major", value, 0, 0) == 0) {
624         log_error("lyd_new_path failed\n");
625         return SR_ERR_OPERATION_FAILED;
626     }
627
628     sprintf(value, "%d", counters.critical);
629     if(lyd_new_path(*parent, NULL, NTS_NF_FAULT_COUNT_LIST_SCHEMA_XPATH"/critical", value, 0, 0) == 0) {
630         log_error("lyd_new_path failed\n");
631         return SR_ERR_OPERATION_FAILED;
632     }
633
634     return SR_ERR_OK;
635 }
636
637 static int network_function_info_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) {
638     char started_features[1024];
639     started_features[0] = 0;
640
641     if(ves_file_ready_feature_get_status()) {
642         strcat(started_features, "ves-file-ready ");
643     }
644     
645     if(ves_pnf_registration_feature_get_status()) {
646         strcat(started_features, "ves-pnf-registration ");
647     }
648
649     if(ves_heartbeat_feature_get_status()) {
650         strcat(started_features, "ves-heartbeat ");
651     }
652     
653     if(manual_notification_feature_get_status()) {
654         strcat(started_features, "manual-notification-generation ");
655     }
656
657     if(netconf_call_home_feature_get_status()) {
658         strcat(started_features, "netconf-call-home ");
659     }
660     
661     if(web_cut_through_feature_get_status()) {
662         strcat(started_features, "web-cut-through ");
663     }
664     
665     if(strlen(started_features)) {
666         started_features[strlen(started_features) - 1] = 0;
667     }
668
669     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_NF_INFO_SCHEMA_XPATH, 0, 0, 0);
670     if(*parent == 0) {
671         log_error("lyd_new_path failed\n");
672         return SR_ERR_OPERATION_FAILED;
673     }
674
675     struct lyd_node *n = lyd_new_leaf(*parent, (*parent)->schema->module, "started-features", started_features);
676     if(n == 0) {
677         log_error("lyd_new_leaf failed\n");
678         return SR_ERR_OPERATION_FAILED;
679     }
680
681     return SR_ERR_OK;
682 }
683
684 static int faults_update_config(sr_session_ctx_t *session) {
685     assert(session);
686     assert_session();
687
688     int ret = NTS_ERR_OK;
689     
690     int rc;
691     struct lyd_node *data;
692     rc = sr_get_subtree(session, NTS_NF_FAULT_GENERATION_SCHEMA_XPATH, 0, &data);
693     if(rc != SR_ERR_OK) {
694         log_error("sr_get_subtree failed\n");
695         return NTS_ERR_FAILED;
696     }
697
698     faults_fault_list_clear();
699     if(data == 0) {
700         return NTS_ERR_OK;
701     }
702
703     if(data->child == 0) {
704         goto faults_update_config_free;
705     }
706
707     struct lyd_node *chd = 0;
708     LY_TREE_FOR(data->child, chd) {
709         if(strcmp(chd->schema->name, "fault-delay-list") == 0) {
710             struct lyd_node *delay_list_entry = 0;
711             LY_TREE_FOR(chd->child, delay_list_entry) {
712                 if(strcmp(delay_list_entry->schema->name, "delay-period") == 0) {
713                     rc = faults_fault_list_add(((const struct lyd_node_leaf_list *)delay_list_entry)->value.uint16);
714                     if(rc != NTS_ERR_OK) {
715                         log_error("faults_fault_list_add failed\n");
716                         ret = NTS_ERR_FAILED;
717                         goto faults_update_config_free;
718                     }
719                 }
720             }
721         }
722         
723     }
724     
725     faults_update_config_free:
726     lyd_free(data);
727
728     return ret;
729 }
730
731 static void *faults_thread_routine(void *arg) {
732     int rc = 0;
733
734     sr_session_ctx_t *current_session_running = 0;
735     rc = sr_session_start(session_connection, SR_DS_RUNNING, &current_session_running);
736     if (rc != SR_ERR_OK) {
737         log_error("sr_session_start failed\n");
738         return 0;
739     }
740
741     sr_session_ctx_t *current_session_operational = 0;
742     rc = sr_session_start(session_connection, SR_DS_OPERATIONAL, &current_session_operational);
743     if (rc != SR_ERR_OK) {
744         log_error("sr_session_start failed\n");
745         return 0;
746     }
747
748     pthread_mutex_lock(&faults_lock);
749     rc = faults_update_config(current_session_running);
750     if(rc != NTS_ERR_OK) {
751         log_error("faults_update_config failed\n");
752         return 0;
753     }
754     pthread_mutex_unlock(&faults_lock);
755
756     while(!framework_sigint) {
757         pthread_mutex_lock(&faults_lock);
758         if(faults_fault_list_not_empty()) {
759             uint16_t new_delay = faults_fault_list_get_next();
760
761             fault_details_t *fault = faults_generate_fault();
762             if(fault == 0) {
763                 log_error("faults_generate_fault failed\n");
764                 pthread_mutex_unlock(&faults_lock);
765                 sleep(1);
766                 continue;
767             }
768
769             rc = faults_counters_increase(fault->severity);
770             if(rc != NTS_ERR_OK) {
771                 log_error("faults_counters_increase failed\n");
772             }
773             pthread_mutex_unlock(&faults_lock);
774
775             sr_val_t *val = 0;
776             bool nc_fault_enabled = false;
777             bool ves_fault_enabled = false;
778
779             rc = sr_get_item(current_session_running, NTS_NF_NETCONF_FAULTS_ENABLED_SCHEMA_PATH, 0, &val);
780             if(rc == SR_ERR_OK) {
781                 nc_fault_enabled = val->data.bool_val;
782                 sr_free_val(val);
783             }
784
785             rc = sr_get_item(current_session_running, NTS_NF_VES_FAULTS_ENABLED_SCHEMA_XPATH, 0, &val);
786             if(rc == SR_ERR_OK) {
787                 ves_fault_enabled = val->data.bool_val;
788                 sr_free_val(val);
789             }
790
791             if(nc_fault_enabled) {
792                 struct lyd_node *notif = 0;
793                 log_add_verbose(1, "[faults] notification is '%s'\n", fault->yang_notif_processed);
794                 notif = lyd_parse_mem(session_context, fault->yang_notif_processed, LYD_XML, LYD_OPT_NOTIF, 0);
795                 if(notif == 0) {
796                     log_error("lyd_parse_mem failed\n");
797                     goto fault_send_ves;
798                 }
799                 
800                 rc = sr_event_notif_send_tree(current_session_running, notif);
801                 lyd_free(notif);
802                 if(rc != SR_ERR_OK) {
803                     log_error("sr_event_notif_send_tree failed\n");
804                 }
805             }
806
807             fault_send_ves:
808             if(ves_fault_enabled) {
809                 rc = faults_ves_message_send(current_session_running, fault->condition, fault->object, fault->severity, fault->date_time, fault->specific_problem);
810                 if(rc != NTS_ERR_OK) {
811                     log_error("faults_ves_message_send failed\n");
812                 }
813             }
814
815             log_add_verbose(1, "[faults] delaying %d sec\n", new_delay);
816             sleep(new_delay);
817         }
818         else {
819             pthread_mutex_unlock(&faults_lock);
820             sleep(1);
821         }
822     }
823
824     sr_session_stop(current_session_running);
825     sr_session_stop(current_session_operational);
826
827     return 0;
828 }
829
830 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) {
831     sr_change_iter_t *it = 0;
832     int rc = SR_ERR_OK;
833     sr_change_oper_t oper;
834     sr_val_t *old_value = 0;
835     sr_val_t *new_value = 0;
836
837     if(event == SR_EV_UPDATE) {
838         rc = sr_get_changes_iter(session, NTS_NF_NETWORK_FUNCTION_SCHEMA_XPATH"//.", &it);
839         if(rc != SR_ERR_OK) {
840             log_error("sr_get_changes_iter failed\n");
841             return SR_ERR_VALIDATION_FAILED;
842         }
843
844         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
845             
846             if(new_value->xpath && (strcmp(new_value->xpath, NTS_NF_NETWORK_FUNCTION_FTYPE_SCHEMA_XPATH) == 0)) {
847                 if(old_value && !old_value->dflt) {
848                     rc = sr_set_item(session, old_value->xpath, old_value, 0);
849                     if(rc != SR_ERR_OK) {
850                         log_error("sr_set_item failed\n");
851                         return SR_ERR_VALIDATION_FAILED;
852                     }
853                 }
854             }
855
856             if(new_value->xpath && (strcmp(new_value->xpath, NTS_NF_NETWORK_FUNCTION_MPAM_SCHEMA_XPATH) == 0)) {
857                 if(old_value && !old_value->dflt) {
858                     rc = sr_set_item(session, old_value->xpath, old_value, 0);
859                     if(rc != SR_ERR_OK) {
860                         log_error("sr_set_item failed\n");
861                         return SR_ERR_VALIDATION_FAILED;
862                     }
863                 }
864             }
865
866             sr_free_val(old_value);
867             sr_free_val(new_value);
868         }
869
870         sr_free_change_iter(it);
871     }
872
873     return SR_ERR_OK;
874 }