Rewrite NTS Framework.
[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 <stdio.h>
24 #include <pthread.h>
25 #include <assert.h>
26
27 #include <sysrepo.h>
28 #include <sysrepo/values.h>
29
30 #include "core/framework.h"
31 #include "core/context.h"
32 #include "core/session.h"
33 #include "core/datastore/populate.h"
34
35 #include "core/faults/faults.h"
36
37 #include "features/ves_pnf_registration/ves_pnf_registration.h"
38 #include "features/ves_heartbeat/ves_heartbeat.h"
39 #include "features/ves_file_ready/ves_file_ready.h"
40 #include "features/manual_notification/manual_notification.h"
41 #include "features/netconf_call_home/netconf_call_home.h"
42
43 #define POPULATE_RPC_SCHEMA_XPATH           "/nts-network-function:datastore-random-populate"
44 #define FEATURE_CONTROL_SCHEMA_XPATH        "/nts-network-function:feature-control"
45 #define FAULTS_CLEAR_SCHEMA_XPATH           "/nts-network-function:clear-fault-counters"
46 #define FAULTS_LIST_SCHEMA_XPATH            "/nts-network-function:simulation/network-function/fault-generation"
47 #define FAULTS_COUNT_LIST_SCHEMA_XPATH      "/nts-network-function:simulation/network-function/fault-generation/fault-count"
48 #define FAULTS_NC_ENABLED_SCHEMA_XPATH      "/nts-network-function:simulation/network-function/netconf/faults-enabled"
49 #define FAULTS_VES_ENABLED_SCHEMA_XPATH     "/nts-network-function:simulation/network-function/ves/faults-enabled"
50
51 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);
52 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);
53 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);
54 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);
55 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);
56
57 static int faults_update_config(sr_session_ctx_t *session);                 //not protected by lock
58 static void *faults_thread_routine(void *arg);
59
60 static pthread_mutex_t nf_function_control_lock;
61 static char *nf_function_control_string = 0;
62
63 static pthread_t faults_thread;
64 static pthread_mutex_t faults_lock;
65
66 int network_function_run(void) {
67     assert_session();
68
69     log_message(1, LOG_COLOR_BOLD_YELLOW"\nrunning as NETWORK FUNCTION daemon...\n"LOG_COLOR_RESET);
70
71     if(pthread_mutex_init(&nf_function_control_lock, NULL) != 0) { 
72         log_error("mutex init has failed"); 
73         return NTS_ERR_FAILED; 
74     }
75
76     //populate
77     int rc = sr_rpc_subscribe(session_running, POPULATE_RPC_SCHEMA_XPATH, network_function_populate_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
78     if(rc != SR_ERR_OK) {
79         log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
80         return NTS_ERR_FAILED;
81     }
82
83     //feature control
84     rc = sr_rpc_subscribe(session_running, FEATURE_CONTROL_SCHEMA_XPATH, network_function_feature_control_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
85     if(rc != SR_ERR_OK) {
86         log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
87         return NTS_ERR_FAILED;
88     }
89
90     //faults
91     rc = sr_module_change_subscribe(session_running, "nts-network-function", FAULTS_LIST_SCHEMA_XPATH, network_function_faults_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
92     if(rc != SR_ERR_OK) {
93         log_error("could not subscribe to faults");
94         return 0;
95     }
96
97     rc = sr_oper_get_items_subscribe(session_running, "nts-network-function", FAULTS_COUNT_LIST_SCHEMA_XPATH, network_function_faults_count_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
98     if(rc != SR_ERR_OK) {
99         log_error("could not subscribe to oper faults: %s", sr_strerror(rc));
100         return 0;
101     }
102
103     rc = sr_rpc_subscribe(session_running, FAULTS_CLEAR_SCHEMA_XPATH, network_function_faults_clear_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
104     if(rc != SR_ERR_OK) {
105         log_error("error from sr_rpc_subscribe: %s", sr_strerror(rc));
106         return NTS_ERR_FAILED;
107     }
108
109     rc = faults_init();
110     if(rc != NTS_ERR_OK) {
111         log_error("faults_init error", sr_strerror(rc));
112         return NTS_ERR_FAILED;
113     }
114
115     if(pthread_mutex_init(&faults_lock, NULL) != 0) { 
116         log_error("mutex init has failed"); 
117         return NTS_ERR_FAILED; 
118     }
119
120     if(pthread_create(&faults_thread, 0, faults_thread_routine, 0)) {
121         log_error("could not create thread for heartbeat");
122         return NTS_ERR_FAILED;
123     }
124
125     while(!framework_sigint) {
126
127         pthread_mutex_lock(&nf_function_control_lock);
128         if(nf_function_control_string) {
129             if(strstr(nf_function_control_string, "ves-file-ready") != 0) {
130                 // start feature for handling the fileReady VES message
131                 rc = ves_file_ready_feature_start(session_running);
132                 if(rc != 0) {
133                     log_error("ves_file_ready_feature_start() failed");
134                 }
135             }
136
137             if(strstr(nf_function_control_string, "ves-pnf-registration") != 0) {
138                 // check if PNF registration is enabled and send PNF registration message if so
139                 rc = ves_pnf_registration_feature_start(session_running);
140                 if(rc != 0) {
141                     log_error("ves_pnf_registration_feature_start() failed");
142                 }
143             }
144
145             if(strstr(nf_function_control_string, "ves-heartbeat") != 0) {
146                 // start feature for handling the heartbeat VES message
147                 rc = ves_heartbeat_feature_start(session_running);
148                 if(rc != 0) {
149                     log_error("ves_heartbeat_feature_start() failed");
150                 }
151             }
152
153             if(strstr(nf_function_control_string, "manual-notification-generation") != 0) {
154                 // start feature for manual notification
155                 rc = manual_notification_feature_start(session_running);
156                 if(rc != 0) {
157                     log_error("manual_notification_feature_start() failed");
158                 }
159             }
160
161             if(strstr(nf_function_control_string, "netconf-call-home") != 0) {
162                 // start feature for NETCONF Call Home
163                 rc = netconf_call_home_feature_start(session_running);
164                 if(rc != 0) {
165                     log_error("netconf_call_home_feature_start() failed");
166                 }
167             }
168
169             free(nf_function_control_string);
170             nf_function_control_string = 0;
171         }
172         pthread_mutex_unlock(&nf_function_control_lock);
173
174         sleep(1);
175     }
176
177     faults_free();
178
179     return NTS_ERR_OK;
180 }
181
182 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) {
183     int rc;
184
185     *output_cnt = 1;
186     rc = sr_new_values(*output_cnt, output);
187     if(SR_ERR_OK != rc) {
188         return rc;
189     }
190
191     rc = sr_val_set_xpath(output[0], POPULATE_RPC_SCHEMA_XPATH"/status");
192     if(SR_ERR_OK != rc) {
193         return rc;
194     }
195
196     rc = schema_populate();
197     if(rc != NTS_ERR_OK) {
198         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
199     }
200     else {
201         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
202     }
203
204     return rc;
205 }
206
207 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) {
208     int rc;
209     int total_errors = 0;
210
211     *output_cnt = 1;
212     rc = sr_new_values(*output_cnt, output);
213     if(SR_ERR_OK != rc) {
214         return rc;
215     }
216
217     rc = sr_val_set_xpath(output[0], FEATURE_CONTROL_SCHEMA_XPATH"/status");
218     if(SR_ERR_OK != rc) {
219         return rc;
220     }
221
222     if(total_errors != 0) {
223         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
224     }
225     else {
226         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
227     }
228
229     pthread_mutex_lock(&nf_function_control_lock);
230     nf_function_control_string = strdup(input[0].data.bits_val);
231     pthread_mutex_unlock(&nf_function_control_lock);
232
233     return rc;
234 }
235
236 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) {
237     int rc;
238
239     *output_cnt = 1;
240     rc = sr_new_values(*output_cnt, output);
241     if(SR_ERR_OK != rc) {
242         return rc;
243     }
244
245     rc = sr_val_set_xpath(output[0], FAULTS_CLEAR_SCHEMA_XPATH"/status");
246     if(SR_ERR_OK != rc) {
247         return rc;
248     }
249
250     pthread_mutex_lock(&faults_lock);
251     faults_counters_clear();
252     pthread_mutex_unlock(&faults_lock);
253
254     rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
255     return rc;
256 }
257
258 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) {
259     int rc = SR_ERR_OK;
260
261     if(event == SR_EV_DONE) {
262         pthread_mutex_lock(&faults_lock);
263         rc = faults_update_config(session);
264         pthread_mutex_unlock(&faults_lock);
265         if(rc != NTS_ERR_OK) {
266             log_error("faults_update_config failed");
267             return SR_ERR_VALIDATION_FAILED;
268         }
269     }
270
271     return SR_ERR_OK;
272 }
273
274 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) {
275     pthread_mutex_lock(&faults_lock);
276     fault_counters_t counters = faults_counters_get();
277     pthread_mutex_unlock(&faults_lock);
278     char value[20];
279
280     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), FAULTS_COUNT_LIST_SCHEMA_XPATH, 0, 0, 0);
281     if(*parent == 0) {
282         return SR_ERR_OPERATION_FAILED;
283     }
284
285     sprintf(value, "%d", counters.normal);
286     if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/normal", value, 0, 0) == 0) {
287         return SR_ERR_OPERATION_FAILED;
288     }
289
290     sprintf(value, "%d", counters.warning);
291     if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/warning", value, 0, 0) == 0) {
292         return SR_ERR_OPERATION_FAILED;
293     }
294
295     sprintf(value, "%d", counters.minor);
296     if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/minor", value, 0, 0) == 0) {
297         return SR_ERR_OPERATION_FAILED;
298     }
299
300     sprintf(value, "%d", counters.major);
301     if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/major", value, 0, 0) == 0) {
302         return SR_ERR_OPERATION_FAILED;
303     }
304
305     sprintf(value, "%d", counters.critical);
306     if(lyd_new_path(*parent, NULL, FAULTS_COUNT_LIST_SCHEMA_XPATH"/critical", value, 0, 0) == 0) {
307         return SR_ERR_OPERATION_FAILED;
308     }
309
310     return SR_ERR_OK;
311 }
312
313 static int faults_update_config(sr_session_ctx_t *session) {
314     assert(session);
315     assert_session();
316
317     int ret = NTS_ERR_OK;
318     
319     int rc;
320     struct lyd_node *data;
321     rc = sr_get_subtree(session, FAULTS_LIST_SCHEMA_XPATH, 0, &data);
322     if(rc != SR_ERR_OK) {
323         log_error("sr_get_subtree failed");
324         ret = NTS_ERR_FAILED;
325     }
326
327     faults_fault_list_clear();
328     faults_counters_clear();
329     if(data->child == 0) {
330         goto faults_update_config_free;
331     }
332
333     struct lyd_node *chd = 0;
334     LY_TREE_FOR(data->child, chd) {
335         if(strcmp(chd->schema->name, "fault-delay-list") == 0) {
336             struct lyd_node *delay_list_entry = 0;
337             LY_TREE_FOR(chd->child, delay_list_entry) {
338                 if(strcmp(delay_list_entry->schema->name, "delay-period") == 0) {
339                     rc = faults_fault_list_add(((const struct lyd_node_leaf_list *)delay_list_entry)->value.uint16);
340                     if(rc != NTS_ERR_OK) {
341                         log_error("faults_fault_list_add failed");
342                         ret = NTS_ERR_FAILED;
343                         goto faults_update_config_free;
344                     }
345                 }
346             }
347         }
348         
349     }
350     
351     faults_update_config_free:
352     lyd_free(data);
353
354     return ret;
355 }
356
357 static void *faults_thread_routine(void *arg) {
358     int rc = 0;
359
360     sr_session_ctx_t *current_session_running = 0;
361     rc = sr_session_start(session_connection, SR_DS_RUNNING, &current_session_running);
362     if (rc != SR_ERR_OK) {
363         log_error("sr_session_start failed");
364         return 0;
365     }
366
367     sr_session_ctx_t *current_session_operational = 0;
368     rc = sr_session_start(session_connection, SR_DS_OPERATIONAL, &current_session_operational);
369     if (rc != SR_ERR_OK) {
370         log_error("sr_session_start failed");
371         return 0;
372     }
373
374     pthread_mutex_lock(&faults_lock);
375     rc = faults_update_config(current_session_running);
376     if(rc != NTS_ERR_OK) {
377         log_error("faults_update_config failed");
378         return 0;
379     }
380     pthread_mutex_unlock(&faults_lock);
381
382     while(!framework_sigint) {
383         pthread_mutex_lock(&faults_lock);
384         if(faults_fault_list_not_empty()) {
385             uint16_t new_delay = faults_fault_list_get_next();
386
387             fault_details_t *fault = faults_generate_fault();
388             if(fault == 0) {
389                 log_error("faults_generate_fault failed");
390                 pthread_mutex_unlock(&faults_lock);
391                 sleep(1);
392                 continue;
393             }
394
395             rc = faults_counters_increase(fault->severity);
396             if(rc != NTS_ERR_OK) {
397                 log_error("faults_counters_increase failed");
398             }
399             pthread_mutex_unlock(&faults_lock);
400
401             sr_val_t *val = 0;
402             bool nc_fault_enabled = false;
403             bool ves_fault_enabled = false;
404
405             rc = sr_get_item(current_session_running, FAULTS_NC_ENABLED_SCHEMA_XPATH, 0, &val);
406             if(rc == SR_ERR_OK) {
407                 nc_fault_enabled = val->data.bool_val;
408                 sr_free_val(val);
409             }
410
411             rc = sr_get_item(current_session_running, FAULTS_VES_ENABLED_SCHEMA_XPATH, 0, &val);
412             if(rc == SR_ERR_OK) {
413                 ves_fault_enabled = val->data.bool_val;
414                 sr_free_val(val);
415             }
416
417             if(nc_fault_enabled) {
418                 struct lyd_node *notif = 0;
419                 notif = lyd_parse_mem(session_context, fault->yang_notif_processed, LYD_XML, LYD_OPT_NOTIF, 0);
420                 if(notif == 0) {
421                     log_error("lyd_parse_mem failed");
422                     goto fault_send_ves;
423                 }
424                 
425                 rc = sr_event_notif_send_tree(current_session_running, notif);
426                 lyd_free(notif);
427                 if(rc != SR_ERR_OK) {
428                     log_error("sr_event_notif_send_tree failed");
429                 }
430             }
431
432             fault_send_ves:
433             if(ves_fault_enabled) {
434                 rc = faults_ves_message_send(current_session_running, fault->condition, fault->object, fault->severity, fault->date_time, fault->specific_problem);
435                 if(rc != NTS_ERR_OK) {
436                     log_error("faults_ves_message_send failed");
437                 }
438             }
439
440             sleep(new_delay);
441         }
442         else {
443             pthread_mutex_unlock(&faults_lock);
444             sleep(1);
445         }
446     }
447
448     sr_session_stop(current_session_running);
449     sr_session_stop(current_session_operational);
450
451     return 0;
452 }