Add network emulation 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 static int app_common_populate_info(void);
32 static int app_common_populate_network_emulation_info(void);
33 static int app_common_populate_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);
34
35 int app_common_init(void) {
36     assert_session();
37
38     int rc = app_common_populate_info();
39     if(rc != NTS_ERR_OK) {
40         log_error("app_common_populate_info() failed\n");
41         return NTS_ERR_FAILED;
42     }
43
44     network_emulation_init();
45
46     rc = app_common_populate_network_emulation_info();
47     if(rc != NTS_ERR_OK) {
48         log_error("app_common_populate_network_emulation() failed\n");
49         return NTS_ERR_FAILED;
50     }
51
52     rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH, app_common_populate_network_emulation_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
53     if(rc != SR_ERR_OK) {
54         log_error("could not subscribe to faults");
55         return NTS_ERR_FAILED;
56     }
57
58     return NTS_ERR_OK;
59 }
60
61 static int app_common_populate_info(void) {
62     int rc;
63
64     if (framework_environment.nts.build_time && strlen(framework_environment.nts.build_time) > 0) {
65         rc  = sr_set_item_str(session_operational, NTS_NF_INFO_SCHEMA_XPATH"/build-time", framework_environment.nts.build_time, 0, 0);
66         if(rc != SR_ERR_OK) {
67             log_error("sr_set_item_str failed\n");
68             return NTS_ERR_FAILED;
69         }
70     }
71
72     rc = sr_set_item_str(session_operational, NTS_NF_INFO_SCHEMA_XPATH"/version", framework_environment.nts.version, 0, 0);
73     if(rc != SR_ERR_OK) {
74         log_error("sr_set_item_str failed\n");
75         return NTS_ERR_FAILED;
76     }
77
78     rc = sr_apply_changes(session_operational, 0, 0);
79     if(rc != SR_ERR_OK) {
80         log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
81         return NTS_ERR_FAILED;
82     }
83
84     return NTS_ERR_OK;
85 }
86
87 static int app_common_populate_network_emulation_info(void) {
88     int rc;
89
90     rc  = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/limit", NETWORK_EMULATION_DEFAULT_LIMIT, 0, 0);
91     if(rc != SR_ERR_OK) {
92         log_error("sr_set_item_str failed\n");
93         return NTS_ERR_FAILED;
94     }
95
96     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/time", "0", 0, 0);
97     if(rc != SR_ERR_OK) {
98         log_error("sr_set_item_str failed\n");
99         return NTS_ERR_FAILED;
100     }
101
102     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/jitter", "0", 0, 0);
103     if(rc != SR_ERR_OK) {
104         log_error("sr_set_item_str failed\n");
105         return NTS_ERR_FAILED;
106     }
107
108     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/correlation", "0", 0, 0);
109     if(rc != SR_ERR_OK) {
110         log_error("sr_set_item_str failed\n");
111         return NTS_ERR_FAILED;
112     }
113
114     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/distribution", "normal", 0, 0);
115     if(rc != SR_ERR_OK) {
116         log_error("sr_set_item_str failed\n");
117         return NTS_ERR_FAILED;
118     }
119
120     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/loss", "0", 0, 0);
121     if(rc != SR_ERR_OK) {
122         log_error("sr_set_item_str failed\n");
123         return NTS_ERR_FAILED;
124     }
125
126     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/corruption/percentage", "0", 0, 0);
127     if(rc != SR_ERR_OK) {
128         log_error("sr_set_item_str failed\n");
129         return NTS_ERR_FAILED;
130     }
131
132     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/corruption/correlation", "0", 0, 0);
133     if(rc != SR_ERR_OK) {
134         log_error("sr_set_item_str failed\n");
135         return NTS_ERR_FAILED;
136     }
137
138     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/duplication/percentage", "0", 0, 0);
139     if(rc != SR_ERR_OK) {
140         log_error("sr_set_item_str failed\n");
141         return NTS_ERR_FAILED;
142     }
143
144     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/duplication/correlation", "0", 0, 0);
145     if(rc != SR_ERR_OK) {
146         log_error("sr_set_item_str failed\n");
147         return NTS_ERR_FAILED;
148     }
149
150     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/reordering/percentage", "0", 0, 0);
151     if(rc != SR_ERR_OK) {
152         log_error("sr_set_item_str failed\n");
153         return NTS_ERR_FAILED;
154     }
155
156     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/reordering/correlation", "0", 0, 0);
157     if(rc != SR_ERR_OK) {
158         log_error("sr_set_item_str failed\n");
159         return NTS_ERR_FAILED;
160     }
161
162     rc = sr_set_item_str(session_running, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/rate", "0", 0, 0);
163     if(rc != SR_ERR_OK) {
164         log_error("sr_set_item_str failed\n");
165         return NTS_ERR_FAILED;
166     }
167
168     rc = sr_apply_changes(session_running, 0, 0);
169     if(rc != SR_ERR_OK) {
170         log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
171         return NTS_ERR_FAILED;
172     }
173
174     return NTS_ERR_OK;
175 }
176
177 static int app_common_populate_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) {
178     
179     if(event == SR_EV_UPDATE) {
180         sr_change_iter_t *it = 0;
181         int rc = SR_ERR_OK;
182         sr_change_oper_t oper;
183         sr_val_t *old_value = 0;
184         sr_val_t *new_value = 0;
185
186         rc = sr_get_changes_iter(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"//.", &it);
187         if(rc != SR_ERR_OK) {
188             log_error("sr_get_changes_iter failed\n");
189             return SR_ERR_VALIDATION_FAILED;
190         }
191
192         uint16_t delay_time = 0;
193         uint16_t delay_jitter = 0;
194
195         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
196             if(new_value->xpath && (strstr(new_value->xpath, "/delay/time"))) {
197                 delay_time = new_value->data.uint16_val;
198             }
199
200             if(new_value->xpath && (strstr(new_value->xpath, "/delay/jitter"))) {
201                 delay_jitter = new_value->data.uint16_val;
202             }
203             sr_free_val(old_value);
204             sr_free_val(new_value);
205         }
206
207         sr_free_change_iter(it);
208
209         if((delay_time == 0) || (delay_jitter == 0)) {
210             rc = sr_set_item_str(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/distribution", "normal", 0, 0);
211             if(rc != SR_ERR_OK) {
212                 log_error("sr_set_item failed\n");
213                 return SR_ERR_VALIDATION_FAILED;
214             }
215         }
216
217         if(delay_time == 0) {
218             rc = sr_set_item_str(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/jitter", "0", 0, 0);
219             if(rc != SR_ERR_OK) {
220                 log_error("sr_set_item failed\n");
221                 return SR_ERR_VALIDATION_FAILED;
222             }
223
224             rc = sr_set_item_str(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"/delay/correlation", "0", 0, 0);
225             if(rc != SR_ERR_OK) {
226                 log_error("sr_set_item failed\n");
227                 return SR_ERR_VALIDATION_FAILED;
228             }
229         }
230     }
231     else if(event == SR_EV_DONE) {
232         sr_val_t *values = NULL;
233         size_t count = 0;
234         
235         int rc = sr_get_items(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"//.", 0, 0, &values, &count);
236         if (rc != SR_ERR_OK) {
237             log_error("sr_get_items failed\n");
238             return rc;
239         }
240
241         network_emultation_settings_t s;
242
243         for(size_t i = 0; i < count; i++) {
244             if(strstr(values[i].xpath, "/limit")) {
245                 s.limit = values[i].data.uint16_val;
246             }
247             else if(strstr(values[i].xpath, "/delay/time")) {
248                 s.delay.time = values[i].data.uint16_val;
249             }
250             else if(strstr(values[i].xpath, "/delay/jitter")) {
251                 s.delay.jitter = values[i].data.uint16_val;
252             }
253             else if(strstr(values[i].xpath, "/delay/correlation")) {
254                 s.delay.correlation = values[i].data.uint16_val;
255             }
256             else if(strstr(values[i].xpath, "/delay/distribution")) {
257                 s.delay.distribution = strdup(values[i].data.string_val);
258             }
259             else if(strstr(values[i].xpath, "/loss")) {
260                 s.loss = values[i].data.uint16_val;
261             }
262             else if(strstr(values[i].xpath, "/corruption/percentage")) {
263                 s.corruption.percentage = values[i].data.uint16_val;
264             }
265             else if(strstr(values[i].xpath, "/corruption/correlation")) {
266                 s.corruption.correlation = values[i].data.uint16_val;
267             }
268             else if(strstr(values[i].xpath, "/duplication/percentage")) {
269                 s.duplication.percentage = values[i].data.uint16_val;
270             }
271             else if(strstr(values[i].xpath, "/duplication/correlation")) {
272                 s.duplication.correlation = values[i].data.uint16_val;
273             }
274             else if(strstr(values[i].xpath, "/reordering/percentage")) {
275                 s.reordering.percentage = values[i].data.uint16_val;
276             }
277             else if(strstr(values[i].xpath, "/reordering/correlation")) {
278                 s.reordering.correlation = values[i].data.uint16_val;
279             }
280             else if(strstr(values[i].xpath, "/rate")) {
281                 s.rate = values[i].data.uint16_val;
282             }
283         }
284
285         sr_free_values(values, count);
286         if(network_emulation_update(&s) != NTS_ERR_OK) {
287             log_error("network_emulation_update() failed\n");
288             free(s.delay.distribution);
289             return SR_ERR_OPERATION_FAILED;
290         }
291         free(s.delay.distribution);
292     }
293
294     return SR_ERR_OK;
295 }