1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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 ***************************************************************************/
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"
30 #include "core/session.h"
31 #include "core/framework.h"
32 #include "core/xpath.h"
34 static int ves_pnf_sequence_number = 0;
35 static pthread_t ves_pnf_registration_thread;
36 static void* ves_pnf_registration_thread_routine(void *arg);
37 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);
38 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);
40 static int ves_pnf_registration_status = 0;
42 int ves_pnf_registration_feature_get_status(void) {
43 return ves_pnf_registration_status;
46 int ves_pnf_registration_feature_start(sr_session_ctx_t *current_session) {
47 assert(current_session);
49 ves_pnf_sequence_number = 0;
53 bool pnf_registration_enabled = false;
54 if(strlen(framework_environment.nts.nf_standalone_start_features)) {
55 pnf_registration_enabled = true;
58 rc = sr_get_item(current_session, NTS_NF_VES_PNF_REGISTRATION_SCHEMA_XPATH, 0, &value);
60 pnf_registration_enabled = value->data.bool_val;
63 else if(rc != SR_ERR_NOT_FOUND) {
64 log_error("sr_get_item failed\n");
65 return NTS_ERR_FAILED;
69 if(pnf_registration_enabled == false) {
70 log_add_verbose(2, "PNF registration is disabled\n");
74 if(pthread_create(&ves_pnf_registration_thread, 0, ves_pnf_registration_thread_routine, current_session)) {
75 log_error("could not create thread for heartbeat\n");
76 return NTS_ERR_FAILED;
82 static void* ves_pnf_registration_thread_routine(void *arg) {
83 sr_session_ctx_t *current_session = arg;
85 int ssh_base_port = 0;
86 int tls_base_port = 0;
87 char nf_ip_v4_address[128];
88 char nf_ip_v6_address[128];
90 nf_ip_v4_address[0] = 0;
91 nf_ip_v6_address[0] = 0;
93 nts_mount_point_addressing_method_t mp = nts_mount_point_addressing_method_get(current_session);
94 if(mp == UNKNOWN_MAPPING) {
95 log_error("mount-point-addressing-method failed\n");
96 return (void*)NTS_ERR_FAILED;
98 else if(mp == DOCKER_MAPPING) {
99 if (framework_environment.settings.ip_v4 != 0) {
100 strcpy(nf_ip_v4_address, framework_environment.settings.ip_v4);
102 if (framework_environment.settings.ip_v6 && framework_environment.settings.ip_v6_enabled) {
103 strcpy(nf_ip_v6_address, framework_environment.settings.ip_v6);
106 ssh_base_port = STANDARD_NETCONF_PORT;
107 tls_base_port = ssh_base_port + framework_environment.settings.ssh_connections;
110 if(framework_environment.settings.ip_v6_enabled) {
111 strcpy(nf_ip_v6_address, framework_environment.host.ip);
114 strcpy(nf_ip_v4_address, framework_environment.host.ip);
117 ssh_base_port = framework_environment.host.ssh_base_port;
118 tls_base_port = framework_environment.host.tls_base_port;
121 uint32_t total_regs = 0;
128 regs = (struct regs_s *)malloc(sizeof(struct regs_s) * (1 + framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections));
130 log_error("malloc failed\n");
131 return (void*)NTS_ERR_FAILED;
135 if((framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections) > 1) {
136 for(int port = ssh_base_port; port < ssh_base_port + framework_environment.settings.ssh_connections; port++) {
137 regs[total_regs].sent = false;
138 regs[total_regs].port = port;
139 regs[total_regs].is_tls = false;
143 for(int port = tls_base_port; port < tls_base_port + framework_environment.settings.tls_connections; port++) {
144 regs[total_regs].sent = false;
145 regs[total_regs].port = port;
146 regs[total_regs].is_tls = true;
152 if(framework_environment.settings.tls_connections == 0) {
159 regs[total_regs].sent = false;
160 regs[total_regs].port = 0;
161 regs[total_regs].is_tls = tls;
165 uint32_t remaining = total_regs;
167 for(int i = 0; i < total_regs; i++) {
168 if(regs[i].sent == false) {
169 uint16_t port = regs[i].port;
170 bool is_tls = regs[i].is_tls;
171 int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, port, mp, is_tls);
172 if(rc == NTS_ERR_OK) {
177 log_error("pnfRegistration failed for ipv4=%s ipv6=%s port=%d is_tls=%d\n", nf_ip_v4_address, nf_ip_v6_address, port, is_tls);
182 log_error("pnfRegistration could not register all ports; retrying in 5 seconds...\n");
187 log_add_verbose(2, "PNF registration finished\n");
188 ves_pnf_registration_status = 1;
193 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) {
194 assert(current_session);
196 cJSON *post_data_json = cJSON_CreateObject();
197 if(post_data_json == 0) {
198 log_error("could not create cJSON object\n");
199 return NTS_ERR_FAILED;
202 cJSON *event = cJSON_CreateObject();
204 log_error("could not create cJSON object\n");
205 cJSON_Delete(post_data_json);
206 return NTS_ERR_FAILED;
209 if(cJSON_AddItemToObject(post_data_json, "event", event) == 0) {
210 log_error("cJSON_AddItemToObject failed\n");
211 cJSON_Delete(post_data_json);
212 return NTS_ERR_FAILED;
215 char *hostname_string = framework_environment.settings.hostname;
216 cJSON *common_event_header = ves_create_common_event_header("pnfRegistration", "EventType5G", hostname_string, nf_port, "Normal", ves_pnf_sequence_number++);
217 if(common_event_header == 0) {
218 log_error("could not create cJSON object\n");
219 cJSON_Delete(post_data_json);
220 return NTS_ERR_FAILED;
224 if(mp == DOCKER_MAPPING) {
225 nf_port = STANDARD_NETCONF_PORT;
229 nf_port = framework_environment.host.tls_base_port;
232 nf_port = framework_environment.host.ssh_base_port;
237 if(cJSON_AddItemToObject(event, "commonEventHeader", common_event_header) == 0) {
238 log_error("cJSON_AddItemToObject failed\n");
239 cJSON_Delete(post_data_json);
240 return NTS_ERR_FAILED;
243 cJSON *pnf_registration_fields = ves_create_pnf_registration_fields(nf_ip_v4_address, nf_ip_v6_address, nf_port, is_tls);
244 if(pnf_registration_fields == 0) {
245 log_error("could not create cJSON object\n");
246 cJSON_Delete(post_data_json);
247 return NTS_ERR_FAILED;
250 if(cJSON_AddItemToObject(event, "pnfRegistrationFields", pnf_registration_fields) == 0) {
251 log_error("cJSON_AddItemToObject failed\n");
252 cJSON_Delete(post_data_json);
253 return NTS_ERR_FAILED;
256 char *post_data = cJSON_PrintUnformatted(post_data_json);
257 cJSON_Delete(post_data_json);
259 log_error("cJSON_PrintUnformatted failed\n");
260 return NTS_ERR_FAILED;
264 ves_details_t *ves_details = ves_endpoint_details_get(current_session, 0);
266 log_error("ves_endpoint_details_get failed\n");
268 return NTS_ERR_FAILED;
271 int rc = http_request(ves_details->url, ves_details->username, ves_details->password, "POST", post_data, 0, 0);
272 ves_details_free(ves_details);
275 if(rc != NTS_ERR_OK) {
276 log_error("http_request failed\n");
277 return NTS_ERR_FAILED;
283 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) {
285 //checkAL aici n-ar trebui niste valori "adevarate" ?
287 cJSON *pnf_registration_fields = cJSON_CreateObject();
288 if(pnf_registration_fields == 0) {
289 log_error("could not create JSON object\n");
293 if(cJSON_AddStringToObject(pnf_registration_fields, "pnfRegistrationFieldsVersion", "2.0") == 0) {
294 log_error("cJSON_AddItemToObject failed\n");
295 cJSON_Delete(pnf_registration_fields);
299 if(cJSON_AddStringToObject(pnf_registration_fields, "lastServiceDate", "2019-08-16") == 0) {
300 log_error("cJSON_AddItemToObject failed\n");
301 cJSON_Delete(pnf_registration_fields);
305 char *mac_addr = rand_mac_address();
307 log_error("rand_mac_address failed\n")
308 cJSON_Delete(pnf_registration_fields);
312 if(cJSON_AddStringToObject(pnf_registration_fields, "macAddress", mac_addr) == 0) {
313 log_error("cJSON_AddItemToObject failed\n");
314 cJSON_Delete(pnf_registration_fields);
320 if(cJSON_AddStringToObject(pnf_registration_fields, "manufactureDate", "2019-08-16") == 0) {
321 log_error("cJSON_AddItemToObject failed\n");
322 cJSON_Delete(pnf_registration_fields);
326 if(cJSON_AddStringToObject(pnf_registration_fields, "modelNumber", "Simulated Device Melacon") == 0) {
327 log_error("cJSON_AddItemToObject failed\n");
328 cJSON_Delete(pnf_registration_fields);
332 if (nf_ip_v4_address != 0 && strlen(nf_ip_v4_address) > 0) {
333 if(cJSON_AddStringToObject(pnf_registration_fields, "oamV4IpAddress", nf_ip_v4_address) == 0) {
334 log_error("cJSON_AddItemToObject failed\n");
335 cJSON_Delete(pnf_registration_fields);
340 if (nf_ip_v6_address != 0 && strlen(nf_ip_v6_address) > 0) {
341 if(cJSON_AddStringToObject(pnf_registration_fields, "oamV6IpAddress", nf_ip_v6_address) == 0) {
342 log_error("cJSON_AddItemToObject failed\n");
343 cJSON_Delete(pnf_registration_fields);
348 char serial_number[512];
349 sprintf(serial_number, "%s-%s-%d-Simulated Device Melacon", framework_environment.settings.hostname, nf_ip_v4_address, nf_port);
351 if(cJSON_AddStringToObject(pnf_registration_fields, "serialNumber", serial_number) == 0) {
352 log_error("cJSON_AddItemToObject failed\n");
353 cJSON_Delete(pnf_registration_fields);
357 if(cJSON_AddStringToObject(pnf_registration_fields, "softwareVersion", "2.3.5") == 0) {
358 log_error("cJSON_AddItemToObject failed\n");
359 cJSON_Delete(pnf_registration_fields);
363 if(cJSON_AddStringToObject(pnf_registration_fields, "unitFamily", "Simulated Device") == 0) {
364 log_error("cJSON_AddItemToObject failed\n");
365 cJSON_Delete(pnf_registration_fields);
369 if(cJSON_AddStringToObject(pnf_registration_fields, "unitType", "O-RAN-sim") == 0) {
370 log_error("cJSON_AddItemToObject failed\n");
371 cJSON_Delete(pnf_registration_fields);
375 if(cJSON_AddStringToObject(pnf_registration_fields, "vendorName", "Melacon") == 0) {
376 log_error("cJSON_AddItemToObject failed\n");
377 cJSON_Delete(pnf_registration_fields);
381 cJSON *additional_fields = cJSON_CreateObject();
382 if(additional_fields == 0) {
383 log_error("could not create JSON object\n");
384 cJSON_Delete(pnf_registration_fields);
387 cJSON_AddItemToObject(pnf_registration_fields, "additionalFields", additional_fields);
389 char port_string[10];
390 sprintf(port_string, "%d", nf_port);
392 if(cJSON_AddStringToObject(additional_fields, "oamPort", port_string) == 0) {
393 log_error("cJSON_AddItemToObject failed\n");
394 cJSON_Delete(pnf_registration_fields);
399 //TLS specific configuration
400 if(cJSON_AddStringToObject(additional_fields, "protocol", "TLS") == 0) {
401 log_error("cJSON_AddItemToObject failed\n");
402 cJSON_Delete(pnf_registration_fields);
406 if(cJSON_AddStringToObject(additional_fields, "username", "netconf") == 0) {
407 log_error("cJSON_AddItemToObject failed\n");
408 cJSON_Delete(pnf_registration_fields);
412 if(cJSON_AddStringToObject(additional_fields, "keyId", KS_KEY_NAME) == 0) {
413 log_error("cJSON_AddItemToObject failed\n");
414 cJSON_Delete(pnf_registration_fields);
419 //SSH specific configuration
420 if(cJSON_AddStringToObject(additional_fields, "protocol", "SSH") == 0) {
421 log_error("cJSON_AddItemToObject failed\n");
422 cJSON_Delete(pnf_registration_fields);
426 if(cJSON_AddStringToObject(additional_fields, "username", "netconf") == 0) {
427 log_error("cJSON_AddItemToObject failed\n");
428 cJSON_Delete(pnf_registration_fields);
432 // hardcoded password here
433 if(cJSON_AddStringToObject(additional_fields, "password", "netconf!") == 0) {
434 log_error("cJSON_AddItemToObject failed\n");
435 cJSON_Delete(pnf_registration_fields);
440 if(cJSON_AddStringToObject(additional_fields, "reconnectOnChangedSchema", "false") == 0) {
441 log_error("cJSON_AddItemToObject failed\n");
442 cJSON_Delete(pnf_registration_fields);
446 if(cJSON_AddStringToObject(additional_fields, "sleep-factor", "1.5") == 0) {
447 log_error("cJSON_AddItemToObject failed\n");
448 cJSON_Delete(pnf_registration_fields);
452 if(cJSON_AddStringToObject(additional_fields, "tcpOnly", "false") == 0) {
453 log_error("cJSON_AddItemToObject failed\n");
454 cJSON_Delete(pnf_registration_fields);
458 if(cJSON_AddStringToObject(additional_fields, "connectionTimeout", "20000") == 0) {
459 log_error("cJSON_AddItemToObject failed\n");
460 cJSON_Delete(pnf_registration_fields);
464 if(cJSON_AddStringToObject(additional_fields, "maxConnectionAttempts", "100") == 0) {
465 log_error("cJSON_AddItemToObject failed\n");
466 cJSON_Delete(pnf_registration_fields);
470 if(cJSON_AddStringToObject(additional_fields, "betweenAttemptsTimeout", "2000") == 0) {
471 log_error("cJSON_AddItemToObject failed\n");
472 cJSON_Delete(pnf_registration_fields);
476 if(cJSON_AddStringToObject(additional_fields, "keepaliveDelay", "120") == 0) {
477 log_error("cJSON_AddItemToObject failed\n");
478 cJSON_Delete(pnf_registration_fields);
482 return pnf_registration_fields;