open5gs/lib/sbi/nnrf-handler.c

395 lines
14 KiB
C

/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-sbi.h"
#include "ogs-app.h"
static void handle_smf_info(
ogs_sbi_nf_instance_t *nf_instance, OpenAPI_smf_info_t *SmfInfo)
{
ogs_sbi_nf_info_t *nf_info = NULL;
OpenAPI_list_t *sNssaiSmfInfoList = NULL;
OpenAPI_snssai_smf_info_item_t *sNssaiSmfInfoItem = NULL;
OpenAPI_snssai_t *sNssai = NULL;
OpenAPI_list_t *DnnSmfInfoList = NULL;
OpenAPI_dnn_smf_info_item_t *DnnSmfInfoItem = NULL;
OpenAPI_list_t *TaiList = NULL;
OpenAPI_tai_t *TaiItem = NULL;
OpenAPI_list_t *TaiRangeList = NULL;
OpenAPI_tai_range_t *TaiRangeItem = NULL;
OpenAPI_list_t *TacRangeList = NULL;
OpenAPI_tac_range_t *TacRangeItem = NULL;
OpenAPI_lnode_t *node = NULL, *node2 = NULL;
ogs_assert(nf_instance);
ogs_assert(SmfInfo);
nf_info = ogs_sbi_nf_info_add(
&nf_instance->nf_info_list, OpenAPI_nf_type_SMF);
ogs_assert(nf_info);
sNssaiSmfInfoList = SmfInfo->s_nssai_smf_info_list;
OpenAPI_list_for_each(sNssaiSmfInfoList, node) {
sNssaiSmfInfoItem = node->data;
if (sNssaiSmfInfoItem) {
ogs_assert(nf_info->smf.num_of_slice < OGS_MAX_NUM_OF_SLICE);
DnnSmfInfoList = sNssaiSmfInfoItem->dnn_smf_info_list;
OpenAPI_list_for_each(DnnSmfInfoList, node2) {
DnnSmfInfoItem = node2->data;
if (DnnSmfInfoItem && DnnSmfInfoItem->dnn) {
int dnn_index = nf_info->smf.slice
[nf_info->smf.num_of_slice].num_of_dnn;
ogs_assert(dnn_index < OGS_MAX_NUM_OF_DNN);
nf_info->smf.slice[nf_info->smf.num_of_slice].
dnn[dnn_index] = ogs_strdup(DnnSmfInfoItem->dnn);
nf_info->smf.slice[nf_info->smf.num_of_slice].
num_of_dnn++;
}
}
if (!nf_info->smf.slice[nf_info->smf.num_of_slice].num_of_dnn) {
ogs_error("No DNN");
continue;
}
sNssai = sNssaiSmfInfoItem->s_nssai;
if (sNssai) {
ogs_s_nssai_t *s_nssai = NULL;
s_nssai = &nf_info->smf.
slice[nf_info->smf.num_of_slice].s_nssai;
s_nssai->sst = sNssai->sst;
s_nssai->sd = ogs_s_nssai_sd_from_string(sNssai->sd);
nf_info->smf.num_of_slice++;
}
}
}
if (nf_info->smf.num_of_slice == 0) {
ogs_error("No S-NSSAI(DNN) in smfInfo");
ogs_sbi_nf_info_remove(&nf_instance->nf_info_list, nf_info);
return;
}
TaiList = SmfInfo->tai_list;
OpenAPI_list_for_each(TaiList, node) {
TaiItem = node->data;
if (TaiItem && TaiItem->plmn_id && TaiItem->tac) {
ogs_5gs_tai_t *nr_tai = NULL;
ogs_assert(nf_info->smf.num_of_nr_tai < OGS_MAX_NUM_OF_TAI);
nr_tai = &nf_info->smf.nr_tai[nf_info->smf.num_of_nr_tai];
ogs_assert(nr_tai);
ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id);
nr_tai->tac = ogs_uint24_from_string(TaiItem->tac);
nf_info->smf.num_of_nr_tai++;
}
}
TaiRangeList = SmfInfo->tai_range_list;
OpenAPI_list_for_each(TaiRangeList, node) {
TaiRangeItem = node->data;
if (TaiRangeItem && TaiRangeItem->plmn_id &&
TaiRangeItem->tac_range_list) {
ogs_assert(nf_info->smf.num_of_nr_tai_range <
OGS_MAX_NUM_OF_TAI);
ogs_sbi_parse_plmn_id(
&nf_info->smf.nr_tai_range
[nf_info->smf.num_of_nr_tai_range].plmn_id,
TaiRangeItem->plmn_id);
TacRangeList = TaiRangeItem->tac_range_list;
OpenAPI_list_for_each(TacRangeList, node2) {
TacRangeItem = node2->data;
if (TacRangeItem &&
TacRangeItem->start && TacRangeItem->end) {
int tac_index = nf_info->smf.nr_tai_range
[nf_info->smf.num_of_nr_tai_range].num_of_tac_range;
ogs_assert(tac_index < OGS_MAX_NUM_OF_TAI);
nf_info->smf.nr_tai_range
[nf_info->smf.num_of_nr_tai_range].
start[tac_index] =
ogs_uint24_from_string(TacRangeItem->start);
nf_info->smf.nr_tai_range
[nf_info->smf.num_of_nr_tai_range].
end[tac_index] =
ogs_uint24_from_string(TacRangeItem->end);
nf_info->smf.nr_tai_range
[nf_info->smf.num_of_nr_tai_range].
num_of_tac_range++;
}
}
nf_info->smf.num_of_nr_tai_range++;
}
}
#if 0
ogs_sbi_smf_info_t *smf_info = &nf_info->smf;
int i, j;
for (i = 0; i < smf_info->num_of_slice; i++) {
ogs_fatal("%d, %x", smf_info->slice[i].s_nssai.sst,
smf_info->slice[i].s_nssai.sd.v);
for (j = 0; j < smf_info->slice[i].num_of_dnn; j++)
ogs_fatal(" %s", smf_info->slice[i].dnn[j]);
}
for (i = 0; i < smf_info->num_of_nr_tai; i++) {
ogs_fatal("%d, %d, %x",
ogs_plmn_id_mcc(&smf_info->nr_tai[i].plmn_id),
ogs_plmn_id_mnc(&smf_info->nr_tai[i].plmn_id),
smf_info->nr_tai[i].tac.v);
}
for (i = 0; i < smf_info->num_of_nr_tai_range; i++) {
ogs_fatal("%d, %d",
ogs_plmn_id_mcc(&smf_info->nr_tai[i].plmn_id),
ogs_plmn_id_mnc(&smf_info->nr_tai[i].plmn_id));
for (j = 0; j < smf_info->nr_tai_range[i].num_of_tac_range; j++) {
ogs_fatal(" %d-%d",
smf_info->nr_tai_range[i].start[j].v,
smf_info->nr_tai_range[i].end[j].v);
}
}
#endif
}
bool ogs_sbi_nnrf_handle_nf_profile(ogs_sbi_nf_instance_t *nf_instance,
OpenAPI_nf_profile_t *NFProfile,
ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
{
int rv;
OpenAPI_lnode_t *node;
ogs_sbi_nf_service_t *nf_service = NULL, *next_nf_service = NULL;
ogs_assert(nf_instance);
ogs_assert(NFProfile);
if (!NFProfile) {
ogs_error("No NFProfile");
if (stream)
ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "No NFProfile", NULL);
return false;
}
if (!NFProfile->nf_instance_id) {
ogs_error("No NFProfile.NFInstanceId");
if (stream)
ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "NFProfile", "No NFInstanceId");
return false;
}
if (!NFProfile->nf_type) {
ogs_error("No NFProfile.NFType");
if (stream)
ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "NFProfile", "No NFType");
return false;
}
if (!NFProfile->nf_status) {
ogs_error("No NFProfile.NFStatus");
if (stream)
ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "NFProfile", "No NFStatus");
return false;
}
ogs_list_for_each_safe(&nf_instance->nf_service_list,
next_nf_service, nf_service) {
bool nf_service_should_not_be_deleted = false;
ogs_assert(nf_service->id);
OpenAPI_list_for_each(NFProfile->nf_services, node) {
OpenAPI_nf_service_t *NFService = node->data;
if (!NFService) continue;
if (!NFService->service_instance_id) continue;
if (!NFService->service_name) continue;
if (strcmp(nf_service->id, NFService->service_instance_id) == 0) {
nf_service_should_not_be_deleted = true;
break;
}
}
if (nf_service_should_not_be_deleted == false) {
ogs_warn("NFService[%s:%s] removed",
nf_service->id, nf_service->name);
OpenAPI_list_for_each(NFProfile->nf_services, node) {
OpenAPI_nf_service_t *NFService = node->data;
if (!NFService) continue;
if (!NFService->service_instance_id) continue;
if (!NFService->service_name) continue;
ogs_warn("NFService[%s:%s] will be added",
NFService->service_instance_id, NFService->service_name);
}
ogs_sbi_nf_service_remove(nf_service);
}
}
ogs_sbi_nf_instance_clear(nf_instance);
nf_instance->nf_type = NFProfile->nf_type;
nf_instance->nf_status = NFProfile->nf_status;
nf_instance->time.heartbeat_interval = NFProfile->heart_beat_timer;
if (NFProfile->fqdn)
ogs_fqdn_parse(nf_instance->fqdn,
NFProfile->fqdn, strlen(NFProfile->fqdn));
/* Only one time handles RegisterNFInstance operation */
OpenAPI_list_for_each(NFProfile->ipv4_addresses, node) {
ogs_sockaddr_t *addr = NULL;
if (!node->data) continue;
if (nf_instance->num_of_ipv4 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
rv = ogs_getaddrinfo(&addr, AF_UNSPEC,
node->data, OGS_SBI_HTTPS_PORT, 0);
if (rv != OGS_OK) continue;
nf_instance->ipv4[nf_instance->num_of_ipv4] = addr;
nf_instance->num_of_ipv4++;
}
}
OpenAPI_list_for_each(NFProfile->ipv6_addresses, node) {
ogs_sockaddr_t *addr = NULL;
if (!node->data) continue;
if (nf_instance->num_of_ipv6 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
rv = ogs_getaddrinfo(&addr, AF_UNSPEC,
node->data, OGS_SBI_HTTPS_PORT, 0);
if (rv != OGS_OK) continue;
nf_instance->ipv6[nf_instance->num_of_ipv6] = addr;
nf_instance->num_of_ipv6++;
}
}
OpenAPI_list_for_each(NFProfile->nf_services, node) {
OpenAPI_nf_service_t *NFService = node->data;
OpenAPI_list_t *VersionList = NULL;
OpenAPI_list_t *IpEndPointList = NULL;
OpenAPI_lnode_t *node2 = NULL;
if (!NFService) continue;
if (!NFService->service_instance_id) continue;
if (!NFService->service_name) continue;
VersionList = NFService->versions;
IpEndPointList = NFService->ip_end_points;
nf_service = ogs_sbi_nf_service_find_by_id(nf_instance,
NFService->service_instance_id);
if (!nf_service) {
nf_service = ogs_sbi_nf_service_add(nf_instance,
NFService->service_instance_id,
NFService->service_name, NFService->scheme);
ogs_assert(nf_service);
}
ogs_sbi_nf_service_clear(nf_service);
OpenAPI_list_for_each(VersionList, node2) {
OpenAPI_nf_service_version_t *NFServiceVersion = node2->data;
if (!NFServiceVersion) continue;
ogs_sbi_nf_service_add_version(nf_service,
NFServiceVersion->api_version_in_uri,
NFServiceVersion->api_full_version,
NFServiceVersion->expiry);
}
if (NFService->fqdn)
ogs_fqdn_parse(nf_service->fqdn,
NFService->fqdn, strlen(NFService->fqdn));
OpenAPI_list_for_each(IpEndPointList, node2) {
OpenAPI_ip_end_point_t *IpEndPoint = node2->data;
ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
int port = 0;
if (!IpEndPoint) continue;
if (nf_service->num_of_addr < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
port = IpEndPoint->port;
if (!port) {
if (nf_service->scheme == OpenAPI_uri_scheme_http)
port = OGS_SBI_HTTP_PORT;
else if (nf_service->scheme == OpenAPI_uri_scheme_https)
port = OGS_SBI_HTTPS_PORT;
else
continue;
}
if (IpEndPoint->ipv4_address) {
rv = ogs_getaddrinfo(&addr, AF_UNSPEC,
IpEndPoint->ipv4_address, port, 0);
if (rv != OGS_OK) continue;
}
if (IpEndPoint->ipv6_address) {
rv = ogs_getaddrinfo(&addr6, AF_UNSPEC,
IpEndPoint->ipv6_address, port, 0);
if (rv != OGS_OK) continue;
}
if (addr || addr6) {
nf_service->addr[nf_service->num_of_addr].
port = port;
nf_service->addr[nf_service->num_of_addr].
ipv4 = addr;
nf_service->addr[nf_service->num_of_addr].
ipv6 = addr6;
nf_service->num_of_addr++;
}
}
}
}
ogs_sbi_nf_info_remove_all(&nf_instance->nf_info_list);
if (NFProfile->smf_info)
handle_smf_info(nf_instance, NFProfile->smf_info);
OpenAPI_list_for_each(NFProfile->smf_info_list, node) {
OpenAPI_map_t *SmfInfoMap = node->data;
if (SmfInfoMap && SmfInfoMap->value)
handle_smf_info(nf_instance, SmfInfoMap->value);
}
return true;
}