This implements the STOP.request/indication for all 3 transport mechanisms, the VNF will send the STOP.request to the PNF, indicating it will disconnect, and await a STOP.indication from the PNF The WLS VNF is reworked to be able to start before the PNF, by calling call rte_eal_init and rte_dev_probe to determine if dpdk has been initialized properly, before calling rte_eal_init in the intended process when it is appropriate to do so
771 lines
21 KiB
C
771 lines
21 KiB
C
/*
|
|
* Copyright 2017 Cisco Systems, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "assertions.h"
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/sctp.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "vnf.h"
|
|
|
|
|
|
|
|
nfapi_vnf_config_t* nfapi_vnf_config_create()
|
|
{
|
|
vnf_t* _this = (vnf_t*)calloc(1, sizeof(vnf_t));
|
|
|
|
if(_this == 0)
|
|
return 0;
|
|
|
|
_this->sctp = 1;
|
|
|
|
_this->next_phy_id = 1;
|
|
|
|
// Set the default P5 port
|
|
_this->_public.vnf_p5_port = NFAPI_P5_SCTP_PORT;
|
|
|
|
// set the default memory allocation
|
|
_this->_public.malloc = &malloc;
|
|
_this->_public.free = &free;
|
|
|
|
// set the default memory allocation
|
|
_this->_public.codec_config.allocate = &malloc;
|
|
_this->_public.codec_config.deallocate = &free;
|
|
|
|
|
|
return (nfapi_vnf_config_t* )_this;
|
|
}
|
|
|
|
void nfapi_vnf_config_destory(nfapi_vnf_config_t* config)
|
|
{
|
|
free(config);
|
|
}
|
|
|
|
|
|
int nfapi_vnf_start(nfapi_vnf_config_t* config)
|
|
{
|
|
assert(config != 0);
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__);
|
|
|
|
int p5ListenSock, p5Sock;
|
|
|
|
struct sockaddr_in addr;
|
|
socklen_t addrSize;
|
|
|
|
struct sockaddr_in6 addr6;
|
|
|
|
struct sctp_event_subscribe events;
|
|
struct sctp_initmsg initMsg;
|
|
int noDelay;
|
|
|
|
(void)memset(&addr, 0, sizeof(struct sockaddr_in));
|
|
(void)memset(&addr6, 0, sizeof(struct sockaddr_in6));
|
|
(void)memset(&events, 0, sizeof(struct sctp_event_subscribe));
|
|
(void)memset(&initMsg, 0, sizeof(struct sctp_initmsg));
|
|
|
|
vnf_t* vnf = (vnf_t*)(config);
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 VNF connection on port %u\n", config->vnf_p5_port);
|
|
|
|
/*
|
|
char * host = 0;
|
|
char * port = "4242";
|
|
struct addrinfo hints;
|
|
bzero(&hints, sizeof(struct addrinfo));
|
|
//hints.ai_flags=AI_PASSIVE;
|
|
//hints.ai_flags=AI_DEFAULT;
|
|
hints.ai_family=AF_UNSPEC;
|
|
//hints.ai_family=AF_INET6;
|
|
hints.ai_socktype=SOCK_STREAM;
|
|
//hints.ai_protocol=IPPROTO_SCTP
|
|
|
|
struct addrinfo *aiHead = 0;
|
|
|
|
|
|
|
|
int result = getaddrinfo(host, port, &hints, &aiHead);
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "getaddrinfo return %d %d\n", result, errno);
|
|
|
|
while(aiHead->ai_next != NULL)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "addr info %d (IP %d UDP %d SCTP %d)\n %d (%d)\n",
|
|
aiHead->ai_protocol, IPPROTO_IP, IPPROTO_UDP, IPPROTO_SCTP,
|
|
aiHead->ai_flags, AI_PASSIVE);
|
|
|
|
char hostBfr[ NI_MAXHOST ];
|
|
char servBfr[ NI_MAXSERV ];
|
|
|
|
getnameinfo(aiHead->ai_addr,
|
|
aiHead->ai_addrlen,
|
|
hostBfr,
|
|
sizeof( hostBfr ),
|
|
servBfr,
|
|
sizeof( servBfr ),
|
|
NI_NUMERICHOST | NI_NUMERICSERV );
|
|
|
|
switch(aiHead->ai_family)
|
|
{
|
|
case PF_INET:
|
|
{
|
|
struct sockaddr_in *pSadrIn = (struct sockaddr_in*) aiHead->ai_addr;
|
|
printf(
|
|
" ai_addr = sin_family: %d (AF_INET = %d, "
|
|
"AF_INET6 = %d)\n"
|
|
" sin_addr: %s\n"
|
|
" sin_port: %s\n",
|
|
pSadrIn->sin_family,
|
|
AF_INET,
|
|
AF_INET6,
|
|
hostBfr,
|
|
servBfr );
|
|
}
|
|
break;
|
|
case PF_INET6:
|
|
{
|
|
struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6*) aiHead->ai_addr;
|
|
fprintf( stderr,
|
|
" ai_addr = sin6_family: %d (AF_INET = %d, "
|
|
"AF_INET6 = %d) \n"
|
|
" sin6_addr: %s\n"
|
|
" sin6_port: %s\n"
|
|
" sin6_flowinfo: %d\n"
|
|
" sin6_scope_id: %d\n",
|
|
pSadrIn6->sin6_family,
|
|
AF_INET,
|
|
AF_INET6,
|
|
hostBfr,
|
|
servBfr,
|
|
pSadrIn6->sin6_flowinfo,
|
|
pSadrIn6->sin6_scope_id);
|
|
}
|
|
break;
|
|
default:
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "Not ment to be here\n");
|
|
break;
|
|
}
|
|
|
|
aiHead = aiHead->ai_next;
|
|
}
|
|
*/
|
|
|
|
{
|
|
int protocol;
|
|
int domain;
|
|
|
|
if (vnf->sctp)
|
|
protocol = IPPROTO_SCTP;
|
|
else
|
|
protocol = IPPROTO_IP;
|
|
|
|
if(config->vnf_ipv6)
|
|
{
|
|
domain = PF_INET6;
|
|
}
|
|
else
|
|
{
|
|
domain = AF_INET;
|
|
}
|
|
|
|
// open the SCTP socket
|
|
if ((p5ListenSock = socket(domain, SOCK_STREAM, protocol)) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno);
|
|
return 0;
|
|
}
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "P5 socket created... %d\n", p5ListenSock);
|
|
}
|
|
|
|
if (vnf->sctp)
|
|
{
|
|
// configure for MSG_NOTIFICATION
|
|
if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(struct sctp_event_subscribe)) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_EVENTS) errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
NFAPI_TRACE(NFAPI_TRACE_NOTE, "VNF Setting the SCTP_INITMSG\n");
|
|
// configure the SCTP socket options
|
|
initMsg.sinit_num_ostreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater
|
|
initMsg.sinit_max_instreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater
|
|
if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
noDelay = 1;
|
|
if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (STCP_NODELAY) errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
struct sctp_event_subscribe events;
|
|
memset( (void *)&events, 0, sizeof(events) );
|
|
events.sctp_data_io_event = 1;
|
|
|
|
if(setsockopt(p5ListenSock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events)) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if(config->vnf_ipv6)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV6 binding to port %d %d\n", config->vnf_p5_port, p5ListenSock);
|
|
addr6.sin6_family = AF_INET6;
|
|
addr6.sin6_port = htons(config->vnf_p5_port);
|
|
addr6.sin6_addr = in6addr_any;
|
|
|
|
// bind to the configured address and port
|
|
if (bind(p5ListenSock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
}
|
|
else if(config->vnf_ipv4)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV4 binding to port %d\n", config->vnf_p5_port);
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(config->vnf_p5_port);
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
// bind to the configured address and port
|
|
if (bind(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
|
|
//if (sctp_bindx(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), SCTP_BINDX_ADD_ADDR) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "bind succeeded..%d.\n", p5ListenSock);
|
|
|
|
// put the socket into listen mode
|
|
if (listen(p5ListenSock, 2) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After listen errno: %d\n", errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "listen succeeded...\n");
|
|
|
|
struct timeval tv;
|
|
fd_set read_fd_set;
|
|
|
|
|
|
int p5_idx = 0;
|
|
while(vnf->terminate == 0)
|
|
{
|
|
FD_ZERO(&read_fd_set);
|
|
|
|
FD_SET(p5ListenSock, &read_fd_set);
|
|
int max_fd = p5ListenSock;
|
|
|
|
tv.tv_sec = 5;
|
|
tv.tv_usec = 0;
|
|
|
|
nfapi_vnf_pnf_info_t* pnf = config->pnf_list;
|
|
while(pnf != 0)
|
|
{
|
|
if(pnf->connected)
|
|
{
|
|
FD_SET(pnf->p5_sock, &read_fd_set);
|
|
if (pnf->p5_sock > max_fd)
|
|
{
|
|
max_fd = pnf->p5_sock;
|
|
}
|
|
}
|
|
|
|
pnf = pnf->next;
|
|
}
|
|
|
|
int select_result = select(max_fd + 1, &read_fd_set, 0, 0, &tv);
|
|
|
|
if(select_result == -1)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "select result %d errno %d\n", select_result, errno);
|
|
close(p5ListenSock);
|
|
return 0;
|
|
}
|
|
else if(select_result)
|
|
{
|
|
if(FD_ISSET(p5ListenSock, &read_fd_set))
|
|
{
|
|
addrSize = sizeof(struct sockaddr_in);
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "Accepting connection from PNF...\n");
|
|
|
|
p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize);
|
|
|
|
if (p5Sock < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to accept PNF connection reason:%d\n", errno);
|
|
}
|
|
else
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF connection (fd:%d) accepted from %s:%d \n", p5Sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
|
nfapi_vnf_pnf_info_t* pnf = (nfapi_vnf_pnf_info_t*)malloc(sizeof(nfapi_vnf_pnf_info_t));
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf);
|
|
memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t));
|
|
pnf->p5_sock = p5Sock;
|
|
pnf->p5_idx = p5_idx++;
|
|
pnf->p5_pnf_sockaddr = addr;
|
|
pnf->connected = 1;
|
|
|
|
nfapi_vnf_pnf_list_add(config, pnf);
|
|
|
|
// Inform mac that a pnf connection has been established
|
|
// todo : allow mac to 'accept' the connection. i.e. to
|
|
// reject it.
|
|
if(config->pnf_connection_indication != 0)
|
|
{
|
|
(config->pnf_connection_indication)(config, pnf->p5_idx);
|
|
}
|
|
|
|
|
|
// check the connection status
|
|
{
|
|
struct sctp_status status;
|
|
(void)memset(&status, 0, sizeof(struct sctp_status));
|
|
socklen_t optLen = (socklen_t) sizeof(struct sctp_status);
|
|
if (getsockopt(p5Sock, IPPROTO_SCTP, SCTP_STATUS, &status, &optLen) < 0)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno);
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Association ID = %d\n", status.sstat_assoc_id);
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Receiver window size = %d\n", status.sstat_rwnd);
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF In Streams = %d\n", status.sstat_instrms);
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Out Streams = %d\n", status.sstat_outstrms);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint8_t delete_pnfs = 0;
|
|
|
|
nfapi_vnf_pnf_info_t* pnf = config->pnf_list;
|
|
while(pnf != 0)
|
|
{
|
|
if(FD_ISSET(pnf->p5_sock, &read_fd_set))
|
|
{
|
|
if(vnf_read_dispatch_message(config, pnf) == 0)
|
|
{
|
|
if(config->pnf_disconnect_indication != 0)
|
|
{
|
|
(config->pnf_disconnect_indication)(config, pnf->p5_idx);
|
|
}
|
|
|
|
close(pnf->p5_sock);
|
|
|
|
pnf->to_delete = 1;
|
|
delete_pnfs = 1;
|
|
}
|
|
}
|
|
|
|
pnf = pnf->next;
|
|
}
|
|
|
|
if(delete_pnfs)
|
|
{
|
|
nfapi_vnf_pnf_info_t* pnf = config->pnf_list;
|
|
nfapi_vnf_pnf_info_t* prev = 0;
|
|
while(pnf != 0)
|
|
{
|
|
nfapi_vnf_pnf_info_t* curr = pnf;
|
|
|
|
if(pnf->to_delete == 1)
|
|
{
|
|
if(prev == 0)
|
|
{
|
|
config->pnf_list = pnf->next;
|
|
}
|
|
else
|
|
{
|
|
prev->next = pnf->next;
|
|
}
|
|
|
|
pnf = pnf->next;
|
|
|
|
free(curr);
|
|
}
|
|
else
|
|
{
|
|
prev = pnf;
|
|
pnf = pnf->next;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// timeout
|
|
|
|
// Should we test for socket closure here every second?
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Sock socket's\n");
|
|
{
|
|
nfapi_vnf_pnf_info_t* curr = config->pnf_list;
|
|
while(curr != NULL)
|
|
{
|
|
if(config->pnf_disconnect_indication)
|
|
{
|
|
(config->pnf_disconnect_indication)(config, curr->p5_idx);
|
|
}
|
|
|
|
close(curr->p5_sock);
|
|
curr = curr->next;
|
|
}
|
|
}
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Listen socket\n");
|
|
close(p5ListenSock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int nfapi_vnf_stop(nfapi_vnf_config_t* config)
|
|
{
|
|
// Verify that config is not null
|
|
if(config == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
_this->terminate = 1;
|
|
return 0;
|
|
}
|
|
|
|
int nfapi_nr_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_pnf_param_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_param_request_t));
|
|
}
|
|
|
|
int nfapi_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_param_request_t));
|
|
}
|
|
|
|
int nfapi_nr_vnf_pnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_pnf_config_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_config_request_t));
|
|
}
|
|
|
|
|
|
int nfapi_vnf_pnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_config_request_t));
|
|
}
|
|
|
|
int nfapi_vnf_pnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_start_request_t));
|
|
}
|
|
|
|
int nfapi_nr_vnf_pnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_pnf_start_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_start_request_t));
|
|
}
|
|
|
|
int nfapi_vnf_pnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_stop_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_stop_request_t));
|
|
}
|
|
|
|
int nfapi_nr_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_param_request_scf_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_param_request_scf_t));
|
|
}
|
|
|
|
int nfapi_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_param_request_t));
|
|
}
|
|
|
|
int nfapi_nr_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_config_request_scf_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
#if !defined(ENABLE_WLS) && !defined(ENABLE_AERIAL)
|
|
nfapi_vnf_phy_info_t* phy = nfapi_vnf_phy_info_list_find(config, req->header.phy_id);
|
|
|
|
if(phy == NULL)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_WARN, "%s failed to find phy information phy_id:%d\n", __FUNCTION__, req->header.phy_id);
|
|
return -1;
|
|
}
|
|
|
|
// set the timing parameters
|
|
req->nfapi_config.timing_window.tl.tag = NFAPI_NR_NFAPI_TIMING_WINDOW_TAG;
|
|
req->nfapi_config.timing_window.value = phy->timing_window;
|
|
req->num_tlv++;
|
|
|
|
req->nfapi_config.timing_info_mode.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_MODE_TAG;
|
|
req->nfapi_config.timing_info_mode.value = phy->timing_info_mode;
|
|
req->num_tlv++;
|
|
|
|
req->nfapi_config.timing_info_period.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG;
|
|
req->nfapi_config.timing_info_period.value = phy->timing_info_period;
|
|
req->num_tlv++;
|
|
#endif
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_config_request_scf_t));
|
|
}
|
|
|
|
int nfapi_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
nfapi_vnf_phy_info_t* phy = nfapi_vnf_phy_info_list_find(config, req->header.phy_id);
|
|
|
|
if(phy == NULL)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_WARN, "%s failed to find phy inforation phy_id:%d\n", __FUNCTION__, req->header.phy_id);
|
|
return -1;
|
|
}
|
|
|
|
// set the timing parameters
|
|
req->nfapi_config.timing_window.tl.tag = NFAPI_NFAPI_TIMING_WINDOW_TAG;
|
|
req->nfapi_config.timing_window.value = phy->timing_window;
|
|
req->num_tlv++;
|
|
|
|
req->nfapi_config.timing_info_mode.tl.tag = NFAPI_NFAPI_TIMING_INFO_MODE_TAG;
|
|
req->nfapi_config.timing_info_mode.value = phy->timing_info_mode;
|
|
req->num_tlv++;
|
|
|
|
req->nfapi_config.timing_info_period.tl.tag = NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG;
|
|
req->nfapi_config.timing_info_period.value = phy->timing_info_period;
|
|
req->num_tlv++;
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_config_request_t));
|
|
}
|
|
|
|
int nfapi_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_request_t * req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_start_request_t));
|
|
}
|
|
|
|
int nfapi_nr_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_start_request_scf_t * req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_start_request_scf_t));
|
|
}
|
|
|
|
|
|
int nfapi_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_stop_request_t));
|
|
}
|
|
|
|
int nfapi_nr_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_stop_request_scf_t* req)
|
|
{
|
|
if (config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Sending NFAPI STOP.request\n");
|
|
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_stop_request_scf_t));
|
|
}
|
|
|
|
int nfapi_vnf_measurement_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_measurement_request_t));
|
|
}
|
|
int nfapi_vnf_rssi_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_rssi_request_t));
|
|
}
|
|
int nfapi_vnf_cell_search_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_cell_search_request_t));
|
|
}
|
|
int nfapi_vnf_broadcast_detect_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_broadcast_detect_request_t));
|
|
}
|
|
int nfapi_vnf_system_information_schedule_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_system_information_schedule_request_t));
|
|
}
|
|
int nfapi_vnf_system_information_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_system_information_request_t));
|
|
}
|
|
int nfapi_vnf_nmm_stop_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_nmm_stop_request_t* req)
|
|
{
|
|
if(config == 0 || req == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_nmm_stop_request_t));
|
|
}
|
|
int nfapi_vnf_vendor_extension(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg)
|
|
{
|
|
if(config == 0 || msg == 0)
|
|
return -1;
|
|
|
|
vnf_t* _this = (vnf_t*)(config);
|
|
|
|
return vnf_pack_and_send_p5_message(_this, p5_idx, msg, sizeof(nfapi_p4_p5_message_header_t));
|
|
}
|
|
|
|
int nfapi_vnf_allocate_phy(nfapi_vnf_config_t* config, int p5_idx, uint16_t* phy_id)
|
|
{
|
|
vnf_t* vnf = (vnf_t*)config;
|
|
|
|
nfapi_vnf_phy_info_t* info = (nfapi_vnf_phy_info_t*)calloc(1, sizeof(nfapi_vnf_phy_info_t));
|
|
info->p5_idx = p5_idx;
|
|
info->phy_id = vnf->next_phy_id++;
|
|
|
|
info->timing_window = 30; // This seems to override what gets set by the user - why??? //TODO: Change in NR in terms of microsecends,what should be the value?
|
|
info->timing_info_mode = 0x03;
|
|
info->timing_info_period = 10;
|
|
|
|
nfapi_vnf_phy_info_list_add(config, info);
|
|
|
|
(*phy_id) = info->phy_id;
|
|
|
|
return 0;
|
|
}
|