Add NETCONF CallHome via TLS feature.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / app / app_common.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 "supervisor.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/network_emulation.h"
24 #include <stdio.h>
25 #include <assert.h>
26
27 #include "core/session.h"
28 #include "core/xpath.h"
29 #include "core/framework.h"
30
31 #include <sysrepo.h>
32 #include <sysrepo/values.h>
33
34 static int app_common_populate_info(void);
35
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);
38
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);
41
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);
43
44 static uint32_t netconf_delay = 0;
45
46 int app_common_init(void) {
47     assert_session();
48
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;
53     }
54
55     network_emulation_init();
56
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;
61     }
62
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);
64     if(rc != SR_ERR_OK) {
65         log_error("could not subscribe to network emulation\n");
66         return NTS_ERR_FAILED;
67     }
68
69
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);
71     if(rc != SR_ERR_OK) {
72         log_error("could not subscribe to hardware emulation changes\n");
73         return NTS_ERR_FAILED;
74     }
75
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);
77     if(rc != SR_ERR_OK) {
78         log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
79         return 0;
80     }
81
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);
83     if(rc != SR_ERR_OK) {
84         log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
85         return NTS_ERR_FAILED;
86     }
87
88     return NTS_ERR_OK;
89 }
90
91 static int app_common_populate_info(void) {
92     int rc;
93     char aux[9];
94
95     struct lys_module *module = (struct lys_module *)ly_ctx_get_module(session_context, NTS_NETWORK_FUNCTION_MODULE, 0, 0);
96     if(module == 0) {
97         log_error("could not get module %s from context\n", NTS_NETWORK_FUNCTION_MODULE);
98         return NTS_ERR_FAILED;
99     }
100
101     struct lyd_node *info = lyd_new(0, module, "info");
102     if(info == 0) {
103         log_error("lyd_new failed\n");
104         return NTS_ERR_FAILED;
105     }
106
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);
110         if(node == 0) {
111             log_error("lyd_new_leaf failed\n");
112             return NTS_ERR_FAILED;
113         }
114     }
115
116     node  = lyd_new_leaf(info, module, "version", framework_environment.nts.version);
117     if(node == 0) {
118         log_error("lyd_new_leaf failed\n");
119         return NTS_ERR_FAILED;
120     }
121
122     sprintf(aux, "%d", framework_environment.settings.ssh_connections);
123     node  = lyd_new_leaf(info, module, "ssh-connections", aux);
124     if(node == 0) {
125         log_error("lyd_new_leaf failed\n");
126         return NTS_ERR_FAILED;
127     }
128
129     sprintf(aux, "%d", framework_environment.settings.tls_connections);
130     node  = lyd_new_leaf(info, module, "tls-connections", aux);
131     if(node == 0) {
132         log_error("lyd_new_leaf failed\n");
133         return NTS_ERR_FAILED;
134     }
135
136     node  = lyd_new_leaf(info, module, "hostname", framework_environment.settings.hostname);
137     if(node == 0) {
138         log_error("lyd_new_leaf failed\n");
139         return NTS_ERR_FAILED;
140     }
141
142     //netconf ssh ports
143     for(int k = 0; k < framework_environment.settings.ssh_connections; k++) {
144         char value[128];
145         
146         struct lyd_node *ports = lyd_new(info, module, "docker-ports");
147         if(ports == 0) {
148             log_error("lyd_new failed\n");
149             return NTS_ERR_FAILED;
150         }
151
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;
156         }
157
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;
161         }
162     }
163
164     //netconf tls ports
165     for(int k = 0; k < framework_environment.settings.tls_connections; k++) {
166         char value[128];
167         
168         struct lyd_node *ports = lyd_new(info, module, "docker-ports");
169         if(ports == 0) {
170             log_error("lyd_new failed\n");
171             return NTS_ERR_FAILED;
172         }
173
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;
178         }
179
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;
183         }
184     }
185
186     //ftp ports
187     for(int k = 0; k < framework_environment.settings.ftp_connections; k++) {
188         char value[128];
189         
190         struct lyd_node *ports = lyd_new(info, module, "docker-ports");
191         if(ports == 0) {
192             log_error("lyd_new failed\n");
193             return NTS_ERR_FAILED;
194         }
195
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;
200         }
201
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;
205         }
206     }
207
208     //sftp ports
209     for(int k = 0; k < framework_environment.settings.sftp_connections; k++) {
210         char value[128];
211         
212         struct lyd_node *ports = lyd_new(info, module, "docker-ports");
213         if(ports == 0) {
214             log_error("lyd_new failed\n");
215             return NTS_ERR_FAILED;
216         }
217
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;
222         }
223
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;
227         }
228     }
229
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;
234     }
235
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;
240     }
241
242     return NTS_ERR_OK;
243 }
244
245 static int app_common_populate_network_emulation_info(void) {
246     int rc;
247
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;
252     }
253
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;
258     }
259
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;
264     }
265
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;
270     }
271
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;
276     }
277
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;
282     }
283
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;
288     }
289
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;
294     }
295
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;
300     }
301
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;
306     }
307
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;
312     }
313
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;
318     }
319
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;
324     }
325
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;
330     }
331
332     return NTS_ERR_OK;
333 }
334
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) {
336     
337     if(event == SR_EV_UPDATE) {
338         sr_change_iter_t *it = 0;
339         int rc = SR_ERR_OK;
340         sr_change_oper_t oper;
341         sr_val_t *old_value = 0;
342         sr_val_t *new_value = 0;
343
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;
348         }
349
350         uint16_t delay_time = 0;
351         uint16_t delay_jitter = 0;
352
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;
356             }
357
358             if(new_value->xpath && (strstr(new_value->xpath, "/delay/jitter"))) {
359                 delay_jitter = new_value->data.uint16_val;
360             }
361             sr_free_val(old_value);
362             sr_free_val(new_value);
363         }
364
365         sr_free_change_iter(it);
366
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;
372             }
373         }
374
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;
380             }
381
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;
386             }
387         }
388     }
389     else if(event == SR_EV_DONE) {
390         sr_val_t *values = NULL;
391         size_t count = 0;
392         
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");
396             return rc;
397         }
398
399         network_emultation_settings_t s;
400
401         for(size_t i = 0; i < count; i++) {
402             if(strstr(values[i].xpath, "/limit")) {
403                 s.limit = values[i].data.uint16_val;
404             }
405             else if(strstr(values[i].xpath, "/delay/time")) {
406                 s.delay.time = values[i].data.uint16_val;
407             }
408             else if(strstr(values[i].xpath, "/delay/jitter")) {
409                 s.delay.jitter = values[i].data.uint16_val;
410             }
411             else if(strstr(values[i].xpath, "/delay/correlation")) {
412                 s.delay.correlation = values[i].data.uint16_val;
413             }
414             else if(strstr(values[i].xpath, "/delay/distribution")) {
415                 s.delay.distribution = strdup(values[i].data.string_val);
416             }
417             else if(strstr(values[i].xpath, "/loss")) {
418                 s.loss = values[i].data.uint16_val;
419             }
420             else if(strstr(values[i].xpath, "/corruption/percentage")) {
421                 s.corruption.percentage = values[i].data.uint16_val;
422             }
423             else if(strstr(values[i].xpath, "/corruption/correlation")) {
424                 s.corruption.correlation = values[i].data.uint16_val;
425             }
426             else if(strstr(values[i].xpath, "/duplication/percentage")) {
427                 s.duplication.percentage = values[i].data.uint16_val;
428             }
429             else if(strstr(values[i].xpath, "/duplication/correlation")) {
430                 s.duplication.correlation = values[i].data.uint16_val;
431             }
432             else if(strstr(values[i].xpath, "/reordering/percentage")) {
433                 s.reordering.percentage = values[i].data.uint16_val;
434             }
435             else if(strstr(values[i].xpath, "/reordering/correlation")) {
436                 s.reordering.correlation = values[i].data.uint16_val;
437             }
438             else if(strstr(values[i].xpath, "/rate")) {
439                 s.rate = values[i].data.uint16_val;
440             }
441         }
442
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;
448         }
449         free(s.delay.distribution);
450     }
451
452     return SR_ERR_OK;
453 }
454
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) {
456     bool delay = false;
457
458     if(event == SR_EV_UPDATE) {
459         sr_change_iter_t *it = 0;
460         int rc = SR_ERR_OK;
461         sr_change_oper_t oper;
462         sr_val_t *old_value = 0;
463         sr_val_t *new_value = 0;
464
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;
469         }
470
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"))) {
473                 delay = true;
474             }
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;
480                 }
481                 
482                 delay = true;
483             }
484
485             sr_free_val(old_value);
486             sr_free_val(new_value);
487         }
488
489         if(delay) {
490             delay = false;
491
492             int32_t sec = netconf_delay / 1000;
493             uint32_t usec = (netconf_delay % 1000) * 1000;
494
495             usleep(usec);
496             if(sec > 0) {
497                 sleep(sec);
498             }
499         }
500
501         sr_free_change_iter(it);
502     }
503
504     if(event == SR_EV_DONE) {
505         sr_val_t *values = NULL;
506         size_t count = 0;
507         
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");
511             return rc;
512         }
513
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;
517             }
518         }
519
520         sr_free_values(values, count);
521     }
522
523     return SR_ERR_OK;
524 }
525
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) {
527
528     char aux[9];
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);
531     if(container == 0) {
532         return SR_ERR_OPERATION_FAILED;
533     }
534
535     //get test leaf
536     lyd_new_leaf(container, container->schema->module, "get-test", aux);
537
538     //get test list
539     sr_val_t *values = NULL;
540     size_t count = 0;
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");
544         return rc;
545     }
546     for(size_t i = 0; i < count; i++) {
547         struct lyd_node *listitem = lyd_new(container, container->schema->module, "get-test-list");
548         if(listitem) {
549             lyd_new_leaf(listitem, container->schema->module, "value", values[i].data.string_val);
550         }
551     }
552
553     sr_free_values(values, count);
554
555
556
557     uint32_t sec = netconf_delay / 1000;
558     uint32_t usec = (netconf_delay % 1000) * 1000;
559
560     usleep(usec);
561     if(sec > 0) {
562         sleep(sec);
563     }
564
565     *parent = container;
566     return SR_ERR_OK;
567 }
568
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) {
570     int rc;
571
572     *output_cnt = 1;
573     rc = sr_new_values(*output_cnt, output);
574     if(SR_ERR_OK != rc) {
575         return rc;
576     }
577
578     rc = sr_val_set_xpath(output[0], NTS_NF_RPC_EMULATE_TOTAL_LOSS_SCHEMA_XPATH"/status");
579     if(SR_ERR_OK != rc) {
580         return rc;
581     }
582
583     sr_val_t *values = NULL;
584     size_t count = 0;
585     
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");
589         return rc;
590     }
591
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;
596         }
597         else if(strstr(values[i].xpath, "/delay/time")) {
598             s.delay.time = values[i].data.uint16_val;
599         }
600         else if(strstr(values[i].xpath, "/delay/jitter")) {
601             s.delay.jitter = values[i].data.uint16_val;
602         }
603         else if(strstr(values[i].xpath, "/delay/correlation")) {
604             s.delay.correlation = values[i].data.uint16_val;
605         }
606         else if(strstr(values[i].xpath, "/delay/distribution")) {
607             s.delay.distribution = strdup(values[i].data.string_val);
608         }
609         else if(strstr(values[i].xpath, "/loss")) {
610             s.loss = values[i].data.uint16_val;
611         }
612         else if(strstr(values[i].xpath, "/corruption/percentage")) {
613             s.corruption.percentage = values[i].data.uint16_val;
614         }
615         else if(strstr(values[i].xpath, "/corruption/correlation")) {
616             s.corruption.correlation = values[i].data.uint16_val;
617         }
618         else if(strstr(values[i].xpath, "/duplication/percentage")) {
619             s.duplication.percentage = values[i].data.uint16_val;
620         }
621         else if(strstr(values[i].xpath, "/duplication/correlation")) {
622             s.duplication.correlation = values[i].data.uint16_val;
623         }
624         else if(strstr(values[i].xpath, "/reordering/percentage")) {
625             s.reordering.percentage = values[i].data.uint16_val;
626         }
627         else if(strstr(values[i].xpath, "/reordering/correlation")) {
628             s.reordering.correlation = values[i].data.uint16_val;
629         }
630         else if(strstr(values[i].xpath, "/rate")) {
631             s.rate = values[i].data.uint16_val;
632         }
633     }
634
635     uint16_t old_loss = s.loss;
636     s.loss = 100;   //100 percent loss
637
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;
643     }
644
645     int delay = input->data.uint32_val;
646     int32_t sec = delay / 1000;
647     uint32_t usec = (delay % 1000) * 1000;
648
649     usleep(usec);
650     if(sec > 0) {
651         sleep(sec);
652     }
653
654     s.loss = old_loss;
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;
659     }
660     free(s.delay.distribution);
661
662     rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
663     return rc;
664 }