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