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