Add supoprt for D release use-case.
[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, 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         pnf_registration_enabled = true;
65     }
66
67     if(pnf_registration_enabled == false) {
68         log_add_verbose(2, "PNF registration is disabled\n");
69         return NTS_ERR_OK;
70     }
71
72     char nf_ip_v4_address[128];
73     char nf_ip_v6_address[128];
74     int nf_ssh_port;
75     int nf_tls_port;
76
77     nts_mount_point_addressing_method_t mp = nts_mount_point_addressing_method_get(current_session);
78     if(mp == UNKNOWN_MAPPING) {
79         log_error("mount-point-addressing-method failed\n");
80         return NTS_ERR_FAILED;
81     }
82     else if(mp == DOCKER_MAPPING) {
83         if (framework_environment.settings.ip_v4 != 0) {
84             strcpy(nf_ip_v4_address, framework_environment.settings.ip_v4);
85         }
86         if (framework_environment.settings.ip_v6) {
87             strcpy(nf_ip_v6_address, framework_environment.settings.ip_v6);
88         }
89         nf_ssh_port = STANDARD_NETCONF_PORT;
90         nf_tls_port = nf_ssh_port + framework_environment.settings.ssh_connections;
91     }
92     else {
93         if (framework_environment.settings.ip_v6_enabled) {
94             strcpy(nf_ip_v6_address, framework_environment.host.ip);
95         }
96         else {
97             strcpy(nf_ip_v4_address, framework_environment.host.ip);
98         }
99         nf_ssh_port = framework_environment.host.ssh_base_port;
100         nf_tls_port = framework_environment.host.tls_base_port;
101     }
102
103     for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
104         rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, nf_ssh_port + i, false);
105         if(rc != NTS_ERR_OK) {
106             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, nf_ssh_port + i);
107             continue;
108         }
109     }
110
111     for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
112         rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, nf_tls_port + i, true);
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 TLS\n", nf_ip_v4_address, nf_ip_v6_address, nf_tls_port + i);
115             continue;
116         }
117     }
118
119     log_add_verbose(2, "PNF registration enabled\n");
120     ves_pnf_registration_status = 1;
121
122     return NTS_ERR_OK;
123 }
124
125
126 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, bool is_tls) {
127     assert(current_session);
128
129     cJSON *post_data_json = cJSON_CreateObject();
130     if(post_data_json == 0) {
131         log_error("could not create cJSON object\n");
132         return NTS_ERR_FAILED;
133     }
134
135     cJSON *event = cJSON_CreateObject();
136     if(event == 0) {
137         log_error("could not create cJSON object\n");
138         cJSON_Delete(post_data_json);
139         return NTS_ERR_FAILED;
140     }
141     
142     if(cJSON_AddItemToObject(post_data_json, "event", event) == 0) {
143         log_error("cJSON_AddItemToObject failed\n");
144         cJSON_Delete(post_data_json);
145         return NTS_ERR_FAILED;
146     }
147
148     char *hostname_string = framework_environment.settings.hostname;
149     char source_name[100];
150
151     if (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections == 1) {
152         // we don't want to append the port to the mountpoint name if we only expose one port
153         sprintf(source_name, "%s", hostname_string);
154     }
155     else {
156             sprintf(source_name, "%s_%d", hostname_string, nf_port);
157     }
158
159     cJSON *common_event_header = ves_create_common_event_header("pnfRegistration", "EventType5G", source_name, "Normal", ves_pnf_sequence_number++);
160     if(common_event_header == 0) {
161         log_error("could not create cJSON object\n");
162         cJSON_Delete(post_data_json);
163         return NTS_ERR_FAILED;
164     }
165     
166     if(cJSON_AddItemToObject(event, "commonEventHeader", common_event_header) == 0) {
167         log_error("cJSON_AddItemToObject failed\n");
168         cJSON_Delete(post_data_json);
169         return NTS_ERR_FAILED;
170     }
171
172         cJSON *pnf_registration_fields = ves_create_pnf_registration_fields(nf_ip_v4_address, nf_ip_v6_address, nf_port, is_tls);
173     if(pnf_registration_fields == 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(cJSON_AddItemToObject(event, "pnfRegistrationFields", pnf_registration_fields) == 0) {
180         log_error("cJSON_AddItemToObject failed\n");
181         cJSON_Delete(post_data_json);
182         return NTS_ERR_FAILED;
183     }
184
185     char *post_data = cJSON_PrintUnformatted(post_data_json);
186     cJSON_Delete(post_data_json);
187     if(post_data == 0) {
188         log_error("cJSON_PrintUnformatted failed\n");
189         return NTS_ERR_FAILED;
190     }
191
192
193     ves_details_t *ves_details = ves_endpoint_details_get(current_session);
194     if(!ves_details) {
195         log_error("ves_endpoint_details_get failed\n");
196         free(post_data);
197         return NTS_ERR_FAILED;
198     }
199     
200     int rc = http_request(ves_details->url, ves_details->username, ves_details->password, "POST", post_data, 0, 0);
201     ves_details_free(ves_details);
202     free(post_data);
203     
204     if(rc != NTS_ERR_OK) {
205         log_error("http_request failed\n");
206         return NTS_ERR_FAILED;
207     }
208
209     return NTS_ERR_OK;
210 }
211
212 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) {
213
214     //checkAL aici n-ar trebui niste valori "adevarate" ?
215
216     cJSON *pnf_registration_fields = cJSON_CreateObject();
217     if(pnf_registration_fields == 0) {
218         log_error("could not create JSON object\n");
219         return 0;
220     }
221
222     if(cJSON_AddStringToObject(pnf_registration_fields, "pnfRegistrationFieldsVersion", "2.0") == 0) {
223         log_error("cJSON_AddItemToObject failed\n");
224         cJSON_Delete(pnf_registration_fields);
225         return 0;
226     }
227
228     if(cJSON_AddStringToObject(pnf_registration_fields, "lastServiceDate", "2019-08-16") == 0) {
229         log_error("cJSON_AddItemToObject failed\n");
230         cJSON_Delete(pnf_registration_fields);
231         return 0;
232     }
233
234     char *mac_addr = rand_mac_address();
235     if(mac_addr == 0) {
236         log_error("rand_mac_address failed\n")
237         cJSON_Delete(pnf_registration_fields);
238         return 0;
239     }
240
241     if(cJSON_AddStringToObject(pnf_registration_fields, "macAddress", mac_addr) == 0) {
242         log_error("cJSON_AddItemToObject failed\n");
243         cJSON_Delete(pnf_registration_fields);
244         free(mac_addr);
245         return 0;
246     }
247     free(mac_addr);
248
249     if(cJSON_AddStringToObject(pnf_registration_fields, "manufactureDate", "2019-08-16") == 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, "modelNumber", "Simulated Device Melacon") == 0) {
256         log_error("cJSON_AddItemToObject failed\n");
257         cJSON_Delete(pnf_registration_fields);
258         return 0;
259     }
260
261     if (nf_ip_v4_address != 0 && strlen(nf_ip_v4_address) > 0) {
262         if(cJSON_AddStringToObject(pnf_registration_fields, "oamV4IpAddress", nf_ip_v4_address) == 0) {
263             log_error("cJSON_AddItemToObject failed\n");
264             cJSON_Delete(pnf_registration_fields);
265             return 0;
266         }
267     }
268
269     if (nf_ip_v6_address != 0 && strlen(nf_ip_v6_address) > 0) {
270         if(cJSON_AddStringToObject(pnf_registration_fields, "oamV6IpAddress", nf_ip_v6_address) == 0) {
271             log_error("cJSON_AddItemToObject failed\n");
272             cJSON_Delete(pnf_registration_fields);
273             return 0;
274         }
275     }
276
277     char serial_number[512];
278     sprintf(serial_number, "%s-%s-%d-Simulated Device Melacon", framework_environment.settings.hostname, nf_ip_v4_address, nf_port);
279
280     if(cJSON_AddStringToObject(pnf_registration_fields, "serialNumber", serial_number) == 0) {
281         log_error("cJSON_AddItemToObject failed\n");
282         cJSON_Delete(pnf_registration_fields);
283         return 0;
284     }
285
286     if(cJSON_AddStringToObject(pnf_registration_fields, "softwareVersion", "2.3.5") == 0) {
287         log_error("cJSON_AddItemToObject failed\n");
288         cJSON_Delete(pnf_registration_fields);
289         return 0;
290     }
291
292     if(cJSON_AddStringToObject(pnf_registration_fields, "unitFamily", "Simulated Device") == 0) {
293         log_error("cJSON_AddItemToObject failed\n");
294         cJSON_Delete(pnf_registration_fields);
295         return 0;
296     }
297
298     if(cJSON_AddStringToObject(pnf_registration_fields, "unitType", "O-RAN-sim") == 0) {
299         log_error("cJSON_AddItemToObject failed\n");
300         cJSON_Delete(pnf_registration_fields);
301         return 0;
302     }
303
304     if(cJSON_AddStringToObject(pnf_registration_fields, "vendorName", "Melacon") == 0) {
305         log_error("cJSON_AddItemToObject failed\n");
306         cJSON_Delete(pnf_registration_fields);
307         return 0;
308     }
309
310     cJSON *additional_fields = cJSON_CreateObject();
311     if(additional_fields == 0) {
312         log_error("could not create JSON object\n");
313         cJSON_Delete(pnf_registration_fields);
314         return 0;
315     }
316     cJSON_AddItemToObject(pnf_registration_fields, "additionalFields", additional_fields);
317
318     char port_string[10];
319     sprintf(port_string, "%d", nf_port);
320
321     if(cJSON_AddStringToObject(additional_fields, "oamPort", port_string) == 0) {
322         log_error("cJSON_AddItemToObject failed\n");
323         cJSON_Delete(pnf_registration_fields);
324         return 0;
325     }
326
327     if(is_tls) {
328         //TLS specific configuration
329         if(cJSON_AddStringToObject(additional_fields, "protocol", "TLS") == 0) {
330             log_error("cJSON_AddItemToObject failed\n");
331             cJSON_Delete(pnf_registration_fields);
332             return 0;
333         }
334
335         if(cJSON_AddStringToObject(additional_fields, "username", "netconf") == 0) {
336             log_error("cJSON_AddItemToObject failed\n");
337             cJSON_Delete(pnf_registration_fields);
338             return 0;
339         }
340
341         if(cJSON_AddStringToObject(additional_fields, "keyId", KS_KEY_NAME) == 0) {
342             log_error("cJSON_AddItemToObject failed\n");
343             cJSON_Delete(pnf_registration_fields);
344             return 0;
345         }
346     }
347     else {
348         //SSH specific configuration
349         if(cJSON_AddStringToObject(additional_fields, "protocol", "SSH") == 0) {
350             log_error("cJSON_AddItemToObject failed\n");
351             cJSON_Delete(pnf_registration_fields);
352             return 0;
353         }
354
355         if(cJSON_AddStringToObject(additional_fields, "username", "netconf") == 0) {
356             log_error("cJSON_AddItemToObject failed\n");
357             cJSON_Delete(pnf_registration_fields);
358             return 0;
359         }
360
361         // hardcoded password here
362         if(cJSON_AddStringToObject(additional_fields, "password", "netconf!") == 0) {
363             log_error("cJSON_AddItemToObject failed\n");
364             cJSON_Delete(pnf_registration_fields);
365             return 0;
366         }
367     }
368
369     if(cJSON_AddStringToObject(additional_fields, "reconnectOnChangedSchema", "false") == 0) {
370         log_error("cJSON_AddItemToObject failed\n");
371         cJSON_Delete(pnf_registration_fields);
372         return 0;
373     }
374
375     if(cJSON_AddStringToObject(additional_fields, "sleep-factor", "1.5") == 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, "tcpOnly", "false") == 0) {
382         log_error("cJSON_AddItemToObject failed\n");
383         cJSON_Delete(pnf_registration_fields);
384         return 0;
385     }
386
387     if(cJSON_AddStringToObject(additional_fields, "connectionTimeout", "20000") == 0) {
388         log_error("cJSON_AddItemToObject failed\n");
389         cJSON_Delete(pnf_registration_fields);
390         return 0;
391     }
392
393     if(cJSON_AddStringToObject(additional_fields, "maxConnectionAttempts", "100") == 0) {
394         log_error("cJSON_AddItemToObject failed\n");
395         cJSON_Delete(pnf_registration_fields);
396         return 0;
397     }
398
399     if(cJSON_AddStringToObject(additional_fields, "betweenAttemptsTimeout", "2000") == 0) {
400         log_error("cJSON_AddItemToObject failed\n");
401         cJSON_Delete(pnf_registration_fields);
402         return 0;
403     }
404
405     if(cJSON_AddStringToObject(additional_fields, "keepaliveDelay", "120") == 0) {
406         log_error("cJSON_AddItemToObject failed\n");
407         cJSON_Delete(pnf_registration_fields);
408         return 0;
409     }
410
411     return pnf_registration_fields;
412 }