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