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