2d6e3a511df3d03922f5599947e12622a041a42b
[sim/o1-interface.git] / ntsimulator / ntsim-ng / features / ves_pnf_registration / ves_pnf_registration.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 "ves_pnf_registration.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/rand_utils.h"
24 #include "utils/http_client.h"
25 #include "utils/nts_utils.h"
26 #include <stdio.h>
27 #include <assert.h>
28
29 #include "core/session.h"
30 #include "core/framework.h"
31
32 #define PNF_REGISTRATION_SCHEMA_XPATH               "/nts-network-function:simulation/network-function/ves/pnf-registration"
33
34 static int ves_pnf_sequence_number = 0;
35
36 static int ves_pnf_registration_send(sr_session_ctx_t *current_session, const char *nf_ip_v4_address, const char *nf_ip_v6_address, int nf_port, nts_mount_point_addressing_method_t mp, bool is_tls);
37 static cJSON* ves_create_pnf_registration_fields(const char *nf_ip_v4_address, const char *nf_ip_v6_address, int nf_port, bool is_tls);
38
39 static int ves_pnf_registration_status = 0;
40
41 int ves_pnf_registration_feature_get_status(void) {
42     return ves_pnf_registration_status;
43 }
44
45 int ves_pnf_registration_feature_start(sr_session_ctx_t *current_session) {
46     assert(current_session);
47
48     ves_pnf_sequence_number = 0;
49
50     sr_val_t *value = 0;
51     int rc = NTS_ERR_OK;
52     bool pnf_registration_enabled = false;
53     rc = sr_get_item(current_session, PNF_REGISTRATION_SCHEMA_XPATH, 0, &value);
54     if(rc == SR_ERR_OK) {
55         pnf_registration_enabled = value->data.bool_val;
56         sr_free_val(value);
57     }
58     else if(rc != SR_ERR_NOT_FOUND) {
59         log_error("sr_get_item failed\n");
60         return NTS_ERR_FAILED;
61     }
62     else {
63         // if value is not set yet, feature enable means we want to start pnf-registration
64         if(strlen(framework_environment.nts.nf_standalone_start_features)) {
65             pnf_registration_enabled = true;
66         }
67     }
68
69     if(pnf_registration_enabled == false) {
70         log_add_verbose(2, "PNF registration is disabled\n");
71         return NTS_ERR_OK;
72     }
73
74     int ssh_base_port = 0;
75     int tls_base_port = 0;
76     char nf_ip_v4_address[128];
77     char nf_ip_v6_address[128];
78
79     nf_ip_v4_address[0] = 0;
80     nf_ip_v6_address[0] = 0;
81     
82     nts_mount_point_addressing_method_t mp = nts_mount_point_addressing_method_get(current_session);
83     if(mp == UNKNOWN_MAPPING) {
84         log_error("mount-point-addressing-method failed\n");
85         return NTS_ERR_FAILED;
86     }
87     else if(mp == DOCKER_MAPPING) {
88         if (framework_environment.settings.ip_v4 != 0) {
89             strcpy(nf_ip_v4_address, framework_environment.settings.ip_v4);
90         }
91         if (framework_environment.settings.ip_v6) {
92             strcpy(nf_ip_v6_address, framework_environment.settings.ip_v6);
93         }
94
95         ssh_base_port = STANDARD_NETCONF_PORT;
96         tls_base_port = ssh_base_port + framework_environment.settings.ssh_connections;
97     }
98     else {
99         if(framework_environment.settings.ip_v6_enabled) {
100             strcpy(nf_ip_v6_address, framework_environment.host.ip);
101         }
102         else {
103             strcpy(nf_ip_v4_address, framework_environment.host.ip);
104         }
105
106         ssh_base_port = framework_environment.host.ssh_base_port;
107         tls_base_port = framework_environment.host.tls_base_port;
108     }
109
110     if((framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections) > 1) {
111         for(int port = ssh_base_port; port < ssh_base_port + framework_environment.settings.ssh_connections; port++) {
112             int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, port, mp, false);
113             if(rc != NTS_ERR_OK) {
114                 log_error("could not send pnfRegistration message for IPv4=%s and IPv6=%s and port=%d and protocol SSH\n", nf_ip_v4_address, nf_ip_v6_address, port);
115             }
116         }
117
118         for(int port = tls_base_port; port < tls_base_port + framework_environment.settings.tls_connections; port++) {
119             int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, port, mp, true);
120             if(rc != NTS_ERR_OK) {
121                 log_error("could not send pnfRegistration message for IPv4=%s and IPv6=%s and port=%d and protocol TLS\n", nf_ip_v4_address, nf_ip_v6_address, port);
122             }
123         }
124     }
125     else {
126         bool tls;
127         int port;
128         if(framework_environment.settings.tls_connections == 0) {
129             tls = false;
130             port = ssh_base_port;
131         }
132         else {
133             tls = true;
134             port = tls_base_port;
135         }
136
137         int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, 0, mp, tls);
138         if(rc != NTS_ERR_OK) {
139             log_error("could not send pnfRegistration message for IPv4=%s and IPv6=%s\n", nf_ip_v4_address, nf_ip_v6_address, port);
140         }
141     }
142
143     log_add_verbose(2, "PNF registration enabled\n");
144     ves_pnf_registration_status = 1;
145
146     return NTS_ERR_OK;
147 }
148
149 static int ves_pnf_registration_send(sr_session_ctx_t *current_session, const char *nf_ip_v4_address, const char *nf_ip_v6_address, int nf_port, nts_mount_point_addressing_method_t mp, bool is_tls) {
150     assert(current_session);
151
152     cJSON *post_data_json = cJSON_CreateObject();
153     if(post_data_json == 0) {
154         log_error("could not create cJSON object\n");
155         return NTS_ERR_FAILED;
156     }
157
158     cJSON *event = cJSON_CreateObject();
159     if(event == 0) {
160         log_error("could not create cJSON object\n");
161         cJSON_Delete(post_data_json);
162         return NTS_ERR_FAILED;
163     }
164     
165     if(cJSON_AddItemToObject(post_data_json, "event", event) == 0) {
166         log_error("cJSON_AddItemToObject failed\n");
167         cJSON_Delete(post_data_json);
168         return NTS_ERR_FAILED;
169     }
170
171     char *hostname_string = framework_environment.settings.hostname;
172     cJSON *common_event_header = ves_create_common_event_header("pnfRegistration", "EventType5G", hostname_string, nf_port, "Normal", ves_pnf_sequence_number++);
173     if(common_event_header == 0) {
174         log_error("could not create cJSON object\n");
175         cJSON_Delete(post_data_json);
176         return NTS_ERR_FAILED;
177     }
178
179     if(nf_port == 0) {
180         if(mp == DOCKER_MAPPING) {
181             nf_port = STANDARD_NETCONF_PORT;
182         }
183         else {
184             if(is_tls) {
185                 nf_port = framework_environment.host.tls_base_port;
186             }
187             else {
188                 nf_port = framework_environment.host.ssh_base_port;
189             }
190         }
191     }
192     
193     if(cJSON_AddItemToObject(event, "commonEventHeader", common_event_header) == 0) {
194         log_error("cJSON_AddItemToObject failed\n");
195         cJSON_Delete(post_data_json);
196         return NTS_ERR_FAILED;
197     }
198
199         cJSON *pnf_registration_fields = ves_create_pnf_registration_fields(nf_ip_v4_address, nf_ip_v6_address, nf_port, is_tls);
200     if(pnf_registration_fields == 0) {
201         log_error("could not create cJSON object\n");
202         cJSON_Delete(post_data_json);
203         return NTS_ERR_FAILED;
204     }
205     
206     if(cJSON_AddItemToObject(event, "pnfRegistrationFields", pnf_registration_fields) == 0) {
207         log_error("cJSON_AddItemToObject failed\n");
208         cJSON_Delete(post_data_json);
209         return NTS_ERR_FAILED;
210     }
211
212     char *post_data = cJSON_PrintUnformatted(post_data_json);
213     cJSON_Delete(post_data_json);
214     if(post_data == 0) {
215         log_error("cJSON_PrintUnformatted failed\n");
216         return NTS_ERR_FAILED;
217     }
218
219
220     ves_details_t *ves_details = ves_endpoint_details_get(current_session);
221     if(!ves_details) {
222         log_error("ves_endpoint_details_get failed\n");
223         free(post_data);
224         return NTS_ERR_FAILED;
225     }
226     
227     int rc = http_request(ves_details->url, ves_details->username, ves_details->password, "POST", post_data, 0, 0);
228     ves_details_free(ves_details);
229     free(post_data);
230     
231     if(rc != NTS_ERR_OK) {
232         log_error("http_request failed\n");
233         return NTS_ERR_FAILED;
234     }
235
236     return NTS_ERR_OK;
237 }
238
239 static cJSON* ves_create_pnf_registration_fields(const char *nf_ip_v4_address, const char *nf_ip_v6_address, int nf_port, bool is_tls) {
240
241     //checkAL aici n-ar trebui niste valori "adevarate" ?
242
243     cJSON *pnf_registration_fields = cJSON_CreateObject();
244     if(pnf_registration_fields == 0) {
245         log_error("could not create JSON object\n");
246         return 0;
247     }
248
249     if(cJSON_AddStringToObject(pnf_registration_fields, "pnfRegistrationFieldsVersion", "2.0") == 0) {
250         log_error("cJSON_AddItemToObject failed\n");
251         cJSON_Delete(pnf_registration_fields);
252         return 0;
253     }
254
255     if(cJSON_AddStringToObject(pnf_registration_fields, "lastServiceDate", "2019-08-16") == 0) {
256         log_error("cJSON_AddItemToObject failed\n");
257         cJSON_Delete(pnf_registration_fields);
258         return 0;
259     }
260
261     char *mac_addr = rand_mac_address();
262     if(mac_addr == 0) {
263         log_error("rand_mac_address failed\n")
264         cJSON_Delete(pnf_registration_fields);
265         return 0;
266     }
267
268     if(cJSON_AddStringToObject(pnf_registration_fields, "macAddress", mac_addr) == 0) {
269         log_error("cJSON_AddItemToObject failed\n");
270         cJSON_Delete(pnf_registration_fields);
271         free(mac_addr);
272         return 0;
273     }
274     free(mac_addr);
275
276     if(cJSON_AddStringToObject(pnf_registration_fields, "manufactureDate", "2019-08-16") == 0) {
277         log_error("cJSON_AddItemToObject failed\n");
278         cJSON_Delete(pnf_registration_fields);
279         return 0;
280     }
281
282     if(cJSON_AddStringToObject(pnf_registration_fields, "modelNumber", "Simulated Device Melacon") == 0) {
283         log_error("cJSON_AddItemToObject failed\n");
284         cJSON_Delete(pnf_registration_fields);
285         return 0;
286     }
287
288     if (nf_ip_v4_address != 0 && strlen(nf_ip_v4_address) > 0) {
289         if(cJSON_AddStringToObject(pnf_registration_fields, "oamV4IpAddress", nf_ip_v4_address) == 0) {
290             log_error("cJSON_AddItemToObject failed\n");
291             cJSON_Delete(pnf_registration_fields);
292             return 0;
293         }
294     }
295
296     if (nf_ip_v6_address != 0 && strlen(nf_ip_v6_address) > 0) {
297         if(cJSON_AddStringToObject(pnf_registration_fields, "oamV6IpAddress", nf_ip_v6_address) == 0) {
298             log_error("cJSON_AddItemToObject failed\n");
299             cJSON_Delete(pnf_registration_fields);
300             return 0;
301         }
302     }
303
304     char serial_number[512];
305     sprintf(serial_number, "%s-%s-%d-Simulated Device Melacon", framework_environment.settings.hostname, nf_ip_v4_address, nf_port);
306
307     if(cJSON_AddStringToObject(pnf_registration_fields, "serialNumber", serial_number) == 0) {
308         log_error("cJSON_AddItemToObject failed\n");
309         cJSON_Delete(pnf_registration_fields);
310         return 0;
311     }
312
313     if(cJSON_AddStringToObject(pnf_registration_fields, "softwareVersion", "2.3.5") == 0) {
314         log_error("cJSON_AddItemToObject failed\n");
315         cJSON_Delete(pnf_registration_fields);
316         return 0;
317     }
318
319     if(cJSON_AddStringToObject(pnf_registration_fields, "unitFamily", "Simulated Device") == 0) {
320         log_error("cJSON_AddItemToObject failed\n");
321         cJSON_Delete(pnf_registration_fields);
322         return 0;
323     }
324
325     if(cJSON_AddStringToObject(pnf_registration_fields, "unitType", "O-RAN-sim") == 0) {
326         log_error("cJSON_AddItemToObject failed\n");
327         cJSON_Delete(pnf_registration_fields);
328         return 0;
329     }
330
331     if(cJSON_AddStringToObject(pnf_registration_fields, "vendorName", "Melacon") == 0) {
332         log_error("cJSON_AddItemToObject failed\n");
333         cJSON_Delete(pnf_registration_fields);
334         return 0;
335     }
336
337     cJSON *additional_fields = cJSON_CreateObject();
338     if(additional_fields == 0) {
339         log_error("could not create JSON object\n");
340         cJSON_Delete(pnf_registration_fields);
341         return 0;
342     }
343     cJSON_AddItemToObject(pnf_registration_fields, "additionalFields", additional_fields);
344
345     char port_string[10];
346     sprintf(port_string, "%d", nf_port);
347
348     if(cJSON_AddStringToObject(additional_fields, "oamPort", port_string) == 0) {
349         log_error("cJSON_AddItemToObject failed\n");
350         cJSON_Delete(pnf_registration_fields);
351         return 0;
352     }
353
354     if(is_tls) {
355         //TLS specific configuration
356         if(cJSON_AddStringToObject(additional_fields, "protocol", "TLS") == 0) {
357             log_error("cJSON_AddItemToObject failed\n");
358             cJSON_Delete(pnf_registration_fields);
359             return 0;
360         }
361
362         if(cJSON_AddStringToObject(additional_fields, "username", "netconf") == 0) {
363             log_error("cJSON_AddItemToObject failed\n");
364             cJSON_Delete(pnf_registration_fields);
365             return 0;
366         }
367
368         if(cJSON_AddStringToObject(additional_fields, "keyId", KS_KEY_NAME) == 0) {
369             log_error("cJSON_AddItemToObject failed\n");
370             cJSON_Delete(pnf_registration_fields);
371             return 0;
372         }
373     }
374     else {
375         //SSH specific configuration
376         if(cJSON_AddStringToObject(additional_fields, "protocol", "SSH") == 0) {
377             log_error("cJSON_AddItemToObject failed\n");
378             cJSON_Delete(pnf_registration_fields);
379             return 0;
380         }
381
382         if(cJSON_AddStringToObject(additional_fields, "username", "netconf") == 0) {
383             log_error("cJSON_AddItemToObject failed\n");
384             cJSON_Delete(pnf_registration_fields);
385             return 0;
386         }
387
388         // hardcoded password here
389         if(cJSON_AddStringToObject(additional_fields, "password", "netconf!") == 0) {
390             log_error("cJSON_AddItemToObject failed\n");
391             cJSON_Delete(pnf_registration_fields);
392             return 0;
393         }
394     }
395
396     if(cJSON_AddStringToObject(additional_fields, "reconnectOnChangedSchema", "false") == 0) {
397         log_error("cJSON_AddItemToObject failed\n");
398         cJSON_Delete(pnf_registration_fields);
399         return 0;
400     }
401
402     if(cJSON_AddStringToObject(additional_fields, "sleep-factor", "1.5") == 0) {
403         log_error("cJSON_AddItemToObject failed\n");
404         cJSON_Delete(pnf_registration_fields);
405         return 0;
406     }
407
408     if(cJSON_AddStringToObject(additional_fields, "tcpOnly", "false") == 0) {
409         log_error("cJSON_AddItemToObject failed\n");
410         cJSON_Delete(pnf_registration_fields);
411         return 0;
412     }
413
414     if(cJSON_AddStringToObject(additional_fields, "connectionTimeout", "20000") == 0) {
415         log_error("cJSON_AddItemToObject failed\n");
416         cJSON_Delete(pnf_registration_fields);
417         return 0;
418     }
419
420     if(cJSON_AddStringToObject(additional_fields, "maxConnectionAttempts", "100") == 0) {
421         log_error("cJSON_AddItemToObject failed\n");
422         cJSON_Delete(pnf_registration_fields);
423         return 0;
424     }
425
426     if(cJSON_AddStringToObject(additional_fields, "betweenAttemptsTimeout", "2000") == 0) {
427         log_error("cJSON_AddItemToObject failed\n");
428         cJSON_Delete(pnf_registration_fields);
429         return 0;
430     }
431
432     if(cJSON_AddStringToObject(additional_fields, "keepaliveDelay", "120") == 0) {
433         log_error("cJSON_AddItemToObject failed\n");
434         cJSON_Delete(pnf_registration_fields);
435         return 0;
436     }
437
438     return pnf_registration_fields;
439 }