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