1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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 ***************************************************************************/
20 #include "supervisor.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/network_emulation.h"
27 #include "core/session.h"
28 #include "core/xpath.h"
29 #include "core/framework.h"
32 #include <sysrepo/values.h>
34 static int app_common_populate_info(void);
36 static int app_common_populate_network_emulation_info(void);
37 static int app_common_network_emulation_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);
39 static int app_common_hardware_emulation_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);
40 static int app_common_hardware_emulation_netconf_delay_oper_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);
42 static int app_common_emulate_total_loss_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);
44 static uint32_t netconf_delay = 0;
46 int app_common_init(void) {
49 int rc = app_common_populate_info();
50 if(rc != NTS_ERR_OK) {
51 log_error("app_common_populate_info() failed\n");
52 return NTS_ERR_FAILED;
55 network_emulation_init();
57 rc = app_common_populate_network_emulation_info();
58 if(rc != NTS_ERR_OK) {
59 log_error("app_common_populate_network_emulation() failed\n");
60 return NTS_ERR_FAILED;
63 rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH, app_common_network_emulation_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
65 log_error("could not subscribe to network emulation\n");
66 return NTS_ERR_FAILED;
70 rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH, app_common_hardware_emulation_change_cb, NULL, 2, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
72 log_error("could not subscribe to hardware emulation changes\n");
73 return NTS_ERR_FAILED;
76 rc = sr_oper_get_items_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH, app_common_hardware_emulation_netconf_delay_oper_cb, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_OPER_MERGE, &session_subscription);
78 log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
82 rc = sr_rpc_subscribe(session_running, NTS_NF_RPC_EMULATE_TOTAL_LOSS_SCHEMA_XPATH, app_common_emulate_total_loss_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
84 log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
85 return NTS_ERR_FAILED;
91 static int app_common_populate_info(void) {
95 struct lys_module *module = (struct lys_module *)ly_ctx_get_module(session_context, NTS_NETWORK_FUNCTION_MODULE, 0, 0);
97 log_error("could not get module %s from context\n", NTS_NETWORK_FUNCTION_MODULE);
98 return NTS_ERR_FAILED;
101 struct lyd_node *info = lyd_new(0, module, "info");
103 log_error("lyd_new failed\n");
104 return NTS_ERR_FAILED;
107 struct lyd_node *node;
108 if (framework_environment.nts.build_time && strlen(framework_environment.nts.build_time) > 0) {
109 node = lyd_new_leaf(info, module, "build-time", framework_environment.nts.build_time);
111 log_error("lyd_new_leaf failed\n");
112 return NTS_ERR_FAILED;
116 node = lyd_new_leaf(info, module, "version", framework_environment.nts.version);
118 log_error("lyd_new_leaf failed\n");
119 return NTS_ERR_FAILED;
122 sprintf(aux, "%d", framework_environment.settings.ssh_connections);
123 node = lyd_new_leaf(info, module, "ssh-connections", aux);
125 log_error("lyd_new_leaf failed\n");
126 return NTS_ERR_FAILED;
129 sprintf(aux, "%d", framework_environment.settings.tls_connections);
130 node = lyd_new_leaf(info, module, "tls-connections", aux);
132 log_error("lyd_new_leaf failed\n");
133 return NTS_ERR_FAILED;
136 node = lyd_new_leaf(info, module, "hostname", framework_environment.settings.hostname);
138 log_error("lyd_new_leaf failed\n");
139 return NTS_ERR_FAILED;
143 for(int k = 0; k < framework_environment.settings.ssh_connections; k++) {
146 struct lyd_node *ports = lyd_new(info, module, "docker-ports");
148 log_error("lyd_new failed\n");
149 return NTS_ERR_FAILED;
152 sprintf(value, "%d", STANDARD_NETCONF_PORT + k);
153 if(lyd_new_leaf(ports, module, "port", value) == 0) {
154 log_error("lyd_new_leaf failed\n");
155 return NTS_ERR_FAILED;
158 if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_SSH") == 0) {
159 log_error("lyd_new_leaf failed\n");
160 return NTS_ERR_FAILED;
165 for(int k = 0; k < framework_environment.settings.tls_connections; k++) {
168 struct lyd_node *ports = lyd_new(info, module, "docker-ports");
170 log_error("lyd_new failed\n");
171 return NTS_ERR_FAILED;
174 sprintf(value, "%d", STANDARD_NETCONF_PORT + framework_environment.settings.ssh_connections + k);
175 if(lyd_new_leaf(ports, module, "port", value) == 0) {
176 log_error("lyd_new_leaf failed\n");
177 return NTS_ERR_FAILED;
180 if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_TLS") == 0) {
181 log_error("lyd_new_leaf failed\n");
182 return NTS_ERR_FAILED;
187 for(int k = 0; k < framework_environment.settings.ftp_connections; k++) {
190 struct lyd_node *ports = lyd_new(info, module, "docker-ports");
192 log_error("lyd_new failed\n");
193 return NTS_ERR_FAILED;
196 sprintf(value, "%d", STANDARD_FTP_PORT + k);
197 if(lyd_new_leaf(ports, module, "port", value) == 0) {
198 log_error("lyd_new_leaf failed\n");
199 return NTS_ERR_FAILED;
202 if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_FTP") == 0) {
203 log_error("lyd_new_leaf failed\n");
204 return NTS_ERR_FAILED;
209 for(int k = 0; k < framework_environment.settings.sftp_connections; k++) {
212 struct lyd_node *ports = lyd_new(info, module, "docker-ports");
214 log_error("lyd_new failed\n");
215 return NTS_ERR_FAILED;
218 sprintf(value, "%d", STANDARD_SFTP_PORT + k);
219 if(lyd_new_leaf(ports, module, "port", value) == 0) {
220 log_error("lyd_new_leaf failed\n");
221 return NTS_ERR_FAILED;
224 if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_SFTP") == 0) {
225 log_error("lyd_new_leaf failed\n");
226 return NTS_ERR_FAILED;
230 rc = sr_edit_batch(session_operational, info, "merge");
231 if(rc != SR_ERR_OK) {
232 log_error("sr_edit_batch failed: %s\n", sr_strerror(rc));
233 return NTS_ERR_FAILED;
236 rc = sr_apply_changes(session_operational, 0, 0);
237 if(rc != SR_ERR_OK) {
238 log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
239 return NTS_ERR_FAILED;
245 static int app_common_populate_network_emulation_info(void) {
248 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/limit", NETWORK_EMULATION_DEFAULT_LIMIT, 0, 0);
249 if(rc != SR_ERR_OK) {
250 log_error("sr_set_item_str failed\n");
251 return NTS_ERR_FAILED;
254 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/time", "0", 0, 0);
255 if(rc != SR_ERR_OK) {
256 log_error("sr_set_item_str failed\n");
257 return NTS_ERR_FAILED;
260 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/jitter", "0", 0, 0);
261 if(rc != SR_ERR_OK) {
262 log_error("sr_set_item_str failed\n");
263 return NTS_ERR_FAILED;
266 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/correlation", "0", 0, 0);
267 if(rc != SR_ERR_OK) {
268 log_error("sr_set_item_str failed\n");
269 return NTS_ERR_FAILED;
272 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/distribution", "normal", 0, 0);
273 if(rc != SR_ERR_OK) {
274 log_error("sr_set_item_str failed\n");
275 return NTS_ERR_FAILED;
278 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/loss", "0", 0, 0);
279 if(rc != SR_ERR_OK) {
280 log_error("sr_set_item_str failed\n");
281 return NTS_ERR_FAILED;
284 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/corruption/percentage", "0", 0, 0);
285 if(rc != SR_ERR_OK) {
286 log_error("sr_set_item_str failed\n");
287 return NTS_ERR_FAILED;
290 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/corruption/correlation", "0", 0, 0);
291 if(rc != SR_ERR_OK) {
292 log_error("sr_set_item_str failed\n");
293 return NTS_ERR_FAILED;
296 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/duplication/percentage", "0", 0, 0);
297 if(rc != SR_ERR_OK) {
298 log_error("sr_set_item_str failed\n");
299 return NTS_ERR_FAILED;
302 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/duplication/correlation", "0", 0, 0);
303 if(rc != SR_ERR_OK) {
304 log_error("sr_set_item_str failed\n");
305 return NTS_ERR_FAILED;
308 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/reordering/percentage", "0", 0, 0);
309 if(rc != SR_ERR_OK) {
310 log_error("sr_set_item_str failed\n");
311 return NTS_ERR_FAILED;
314 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/reordering/correlation", "0", 0, 0);
315 if(rc != SR_ERR_OK) {
316 log_error("sr_set_item_str failed\n");
317 return NTS_ERR_FAILED;
320 rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/rate", "0", 0, 0);
321 if(rc != SR_ERR_OK) {
322 log_error("sr_set_item_str failed\n");
323 return NTS_ERR_FAILED;
326 rc = sr_apply_changes(session_running, 0, 0);
327 if(rc != SR_ERR_OK) {
328 log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
329 return NTS_ERR_FAILED;
335 static int app_common_network_emulation_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) {
337 if(event == SR_EV_UPDATE) {
338 sr_change_iter_t *it = 0;
340 sr_change_oper_t oper;
341 sr_val_t *old_value = 0;
342 sr_val_t *new_value = 0;
344 rc = sr_get_changes_iter(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"//.", &it);
345 if(rc != SR_ERR_OK) {
346 log_error("sr_get_changes_iter failed\n");
347 return SR_ERR_VALIDATION_FAILED;
350 uint16_t delay_time = 0;
351 uint16_t delay_jitter = 0;
353 while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
354 if(new_value->xpath && (strstr(new_value->xpath, "/delay/time"))) {
355 delay_time = new_value->data.uint16_val;
358 if(new_value->xpath && (strstr(new_value->xpath, "/delay/jitter"))) {
359 delay_jitter = new_value->data.uint16_val;
361 sr_free_val(old_value);
362 sr_free_val(new_value);
365 sr_free_change_iter(it);
367 if((delay_time == 0) || (delay_jitter == 0)) {
368 rc = sr_set_item_str(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/distribution", "normal", 0, 0);
369 if(rc != SR_ERR_OK) {
370 log_error("sr_set_item failed\n");
371 return SR_ERR_VALIDATION_FAILED;
375 if(delay_time == 0) {
376 rc = sr_set_item_str(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/jitter", "0", 0, 0);
377 if(rc != SR_ERR_OK) {
378 log_error("sr_set_item failed\n");
379 return SR_ERR_VALIDATION_FAILED;
382 rc = sr_set_item_str(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/correlation", "0", 0, 0);
383 if(rc != SR_ERR_OK) {
384 log_error("sr_set_item failed\n");
385 return SR_ERR_VALIDATION_FAILED;
389 else if(event == SR_EV_DONE) {
390 sr_val_t *values = NULL;
393 int rc = sr_get_items(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"//.", 0, 0, &values, &count);
394 if (rc != SR_ERR_OK) {
395 log_error("sr_get_items failed\n");
399 network_emultation_settings_t s;
401 for(size_t i = 0; i < count; i++) {
402 if(strstr(values[i].xpath, "/limit")) {
403 s.limit = values[i].data.uint16_val;
405 else if(strstr(values[i].xpath, "/delay/time")) {
406 s.delay.time = values[i].data.uint16_val;
408 else if(strstr(values[i].xpath, "/delay/jitter")) {
409 s.delay.jitter = values[i].data.uint16_val;
411 else if(strstr(values[i].xpath, "/delay/correlation")) {
412 s.delay.correlation = values[i].data.uint16_val;
414 else if(strstr(values[i].xpath, "/delay/distribution")) {
415 s.delay.distribution = strdup(values[i].data.string_val);
417 else if(strstr(values[i].xpath, "/loss")) {
418 s.loss = values[i].data.uint16_val;
420 else if(strstr(values[i].xpath, "/corruption/percentage")) {
421 s.corruption.percentage = values[i].data.uint16_val;
423 else if(strstr(values[i].xpath, "/corruption/correlation")) {
424 s.corruption.correlation = values[i].data.uint16_val;
426 else if(strstr(values[i].xpath, "/duplication/percentage")) {
427 s.duplication.percentage = values[i].data.uint16_val;
429 else if(strstr(values[i].xpath, "/duplication/correlation")) {
430 s.duplication.correlation = values[i].data.uint16_val;
432 else if(strstr(values[i].xpath, "/reordering/percentage")) {
433 s.reordering.percentage = values[i].data.uint16_val;
435 else if(strstr(values[i].xpath, "/reordering/correlation")) {
436 s.reordering.correlation = values[i].data.uint16_val;
438 else if(strstr(values[i].xpath, "/rate")) {
439 s.rate = values[i].data.uint16_val;
443 sr_free_values(values, count);
444 if(network_emulation_update(&s) != NTS_ERR_OK) {
445 log_error("network_emulation_update() failed\n");
446 free(s.delay.distribution);
447 return SR_ERR_OPERATION_FAILED;
449 free(s.delay.distribution);
455 static int app_common_hardware_emulation_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) {
458 if(event == SR_EV_UPDATE) {
459 sr_change_iter_t *it = 0;
461 sr_change_oper_t oper;
462 sr_val_t *old_value = 0;
463 sr_val_t *new_value = 0;
465 rc = sr_get_changes_iter(session, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH"//.", &it);
466 if(rc != SR_ERR_OK) {
467 log_error("sr_get_changes_iter failed\n");
468 return SR_ERR_VALIDATION_FAILED;
471 while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
472 if(new_value->xpath && (strstr(new_value->xpath, "/netconf-delay/edit-test-list"))) {
475 else if(new_value->xpath && (strstr(new_value->xpath, "/netconf-delay/edit-test"))) {
476 rc = sr_set_item_str(session, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH"/netconf-delay/edit-test", "0", 0, 0);
477 if(rc != SR_ERR_OK) {
478 log_error("sr_set_item failed\n");
479 return SR_ERR_VALIDATION_FAILED;
485 sr_free_val(old_value);
486 sr_free_val(new_value);
492 int32_t sec = netconf_delay / 1000;
493 uint32_t usec = (netconf_delay % 1000) * 1000;
501 sr_free_change_iter(it);
504 if(event == SR_EV_DONE) {
505 sr_val_t *values = NULL;
508 int rc = sr_get_items(session, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH"//.", 0, 0, &values, &count);
509 if (rc != SR_ERR_OK) {
510 log_error("sr_get_items failed\n");
514 for(size_t i = 0; i < count; i++) {
515 if(strstr(values[i].xpath, "/netconf-delay/delay")) {
516 netconf_delay = values[i].data.uint32_val;
520 sr_free_values(values, count);
526 static int app_common_hardware_emulation_netconf_delay_oper_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) {
529 sprintf(aux, "%d", netconf_delay);
530 struct lyd_node *container = lyd_new_path(0, session_context, NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH, 0, 0, LYD_PATH_OPT_NOPARENTRET);
532 return SR_ERR_OPERATION_FAILED;
536 lyd_new_leaf(container, container->schema->module, "get-test", aux);
539 sr_val_t *values = NULL;
541 int rc = sr_get_items(session_running, NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH"/edit-test-list/*", 0, 0, &values, &count);
542 if (rc != SR_ERR_OK) {
543 log_error("sr_get_items failed\n");
546 for(size_t i = 0; i < count; i++) {
547 struct lyd_node *listitem = lyd_new(container, container->schema->module, "get-test-list");
549 lyd_new_leaf(listitem, container->schema->module, "value", values[i].data.string_val);
553 sr_free_values(values, count);
557 uint32_t sec = netconf_delay / 1000;
558 uint32_t usec = (netconf_delay % 1000) * 1000;
569 static int app_common_emulate_total_loss_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) {
573 rc = sr_new_values(*output_cnt, output);
574 if(SR_ERR_OK != rc) {
578 rc = sr_val_set_xpath(output[0], NTS_NF_RPC_EMULATE_TOTAL_LOSS_SCHEMA_XPATH"/status");
579 if(SR_ERR_OK != rc) {
583 sr_val_t *values = NULL;
586 rc = sr_get_items(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"//.", 0, 0, &values, &count);
587 if (rc != SR_ERR_OK) {
588 log_error("sr_get_items failed\n");
592 network_emultation_settings_t s;
593 for(size_t i = 0; i < count; i++) {
594 if(strstr(values[i].xpath, "/limit")) {
595 s.limit = values[i].data.uint16_val;
597 else if(strstr(values[i].xpath, "/delay/time")) {
598 s.delay.time = values[i].data.uint16_val;
600 else if(strstr(values[i].xpath, "/delay/jitter")) {
601 s.delay.jitter = values[i].data.uint16_val;
603 else if(strstr(values[i].xpath, "/delay/correlation")) {
604 s.delay.correlation = values[i].data.uint16_val;
606 else if(strstr(values[i].xpath, "/delay/distribution")) {
607 s.delay.distribution = strdup(values[i].data.string_val);
609 else if(strstr(values[i].xpath, "/loss")) {
610 s.loss = values[i].data.uint16_val;
612 else if(strstr(values[i].xpath, "/corruption/percentage")) {
613 s.corruption.percentage = values[i].data.uint16_val;
615 else if(strstr(values[i].xpath, "/corruption/correlation")) {
616 s.corruption.correlation = values[i].data.uint16_val;
618 else if(strstr(values[i].xpath, "/duplication/percentage")) {
619 s.duplication.percentage = values[i].data.uint16_val;
621 else if(strstr(values[i].xpath, "/duplication/correlation")) {
622 s.duplication.correlation = values[i].data.uint16_val;
624 else if(strstr(values[i].xpath, "/reordering/percentage")) {
625 s.reordering.percentage = values[i].data.uint16_val;
627 else if(strstr(values[i].xpath, "/reordering/correlation")) {
628 s.reordering.correlation = values[i].data.uint16_val;
630 else if(strstr(values[i].xpath, "/rate")) {
631 s.rate = values[i].data.uint16_val;
635 uint16_t old_loss = s.loss;
636 s.loss = 100; //100 percent loss
638 sr_free_values(values, count);
639 if(network_emulation_update(&s) != NTS_ERR_OK) {
640 log_error("network_emulation_update() failed\n");
641 free(s.delay.distribution);
642 return SR_ERR_OPERATION_FAILED;
645 int delay = input->data.uint32_val;
646 int32_t sec = delay / 1000;
647 uint32_t usec = (delay % 1000) * 1000;
655 if(network_emulation_update(&s) != NTS_ERR_OK) {
656 log_error("network_emulation_update() failed\n");
657 free(s.delay.distribution);
658 return SR_ERR_OPERATION_FAILED;
660 free(s.delay.distribution);
662 rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");