Fix NFAPI integration

This commit fixes issues introduced by the previous commit.

Summary of work:
- cleanup:
  - fix LOG_XX to be less verbose
  - fix cmake_targets/CMakeLists.txt
  - fix oaienv
  - remove dead code
- bug fixes:
  - in openair1/SCHED/fapi_l1.c we had:
      eNB->pdcch_vars[subframe&1].num_dci           = number_dci;
    should be:
      eNB->pdcch_vars[subframe&1].num_dci           = 0;
    This bug let the PHY send more DCIs than what should have been
    sent because num_dci is incremented later on in the code.
    This fix may be a problem for fapi mode, to be checked.
  - add new T VCD traces
  - revert openair1/PHY/TOOLS/file_output.c to 'develop' version
  - remove thread_id in logRecord/logRecord_mt
  - revert (and adapt) configuration files
  - be careful when doing frame++, we need to % 1024
  - revert target_rx_power in openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
- NFAPI:
  - the open-nFAPI code has been included in the repository. See nfapi/README.
    Maybe we should "git clone" the Cisco repository instead. We have to be
    careful of availability though.

What has been tested:
- monolithic eNB FDD 5/10MHz with one UE, iperf UDP/TCP uplink/downlink

Anything else may fail to work, especially the FAPI mode, which has not
been tested at all.
This commit is contained in:
Cedric Roux
2018-01-15 15:24:50 +01:00
parent 7757b9e7e7
commit 922b5b595a
102 changed files with 48002 additions and 481 deletions
+43
View File
@@ -0,0 +1,43 @@
#
# 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.
#
AUTOMAKE_OPTIONS=subdir-objects
AM_CPPFLAGS = -I$(top_srcdir)/vnf/inc\
-I$(top_srcdir)/vnf/public_inc\
-I$(top_srcdir)/nfapi/public_inc\
-I$(top_srcdir)/common/public_inc\
-Wall -Werror -g
noinst_LIBRARIES = libnfapi_vnf.a
libnfapi_vnf_a_SOURCES = src/vnf.c\
src/vnf_p7.c\
src/vnf_interface.c\
src/vnf_p7_interface.c
LDADD = -lsctp ../common/bin/libnfapi_common.a
libnfapi_vnf_a_CFLAGS =$(AM_CFLAGS)
lib_LTLIBRARIES = libnfapi_vnf.la
libnfapi_vnf_la_SOURCES = src/vnf.c\
src/vnf_p7.c\
src/vnf_interface.c\
src/vnf_p7_interface.c
+46
View File
@@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef _VNF_H_
#define _VNF_H_
#include "nfapi_vnf_interface.h"
typedef struct
{
nfapi_vnf_config_t _public;
uint8_t terminate;
uint8_t sctp;
uint8_t tx_message_buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE];
uint16_t next_phy_id;
} vnf_t;
int vnf_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len);
int vnf_pack_and_send_p4_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len);
int vnf_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf);
void nfapi_vnf_phy_info_list_add(nfapi_vnf_config_t* config, nfapi_vnf_phy_info_t* info);
nfapi_vnf_phy_info_t* nfapi_vnf_phy_info_list_find(nfapi_vnf_config_t* config, uint16_t phy_id);
void nfapi_vnf_pnf_list_add(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* node);
nfapi_vnf_pnf_info_t* nfapi_vnf_pnf_list_find(nfapi_vnf_config_t* config, int p5_idx);
#endif // _VNF_H_
+136
View File
@@ -0,0 +1,136 @@
/*
* 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.
*/
#ifndef _VNF_P7_H_
#define _VNF_P7_H_
#include "nfapi_vnf_interface.h"
#define TIMEHR_SEC(_time_hr) ((uint32_t)(_time_hr) >> 20)
#define TIMEHR_USEC(_time_hr) ((uint32_t)(_time_hr) & 0xFFFFF)
#define TIME2TIMEHR(_time) (((uint32_t)(_time.tv_sec) & 0xFFF) << 20 | ((uint32_t)(_time.tv_usec) & 0xFFFFF))
typedef struct {
uint8_t* buffer;
uint16_t length;
} vnf_p7_rx_message_segment_t;
typedef struct vnf_p7_rx_message vnf_p7_rx_message_t;
typedef struct vnf_p7_rx_message {
uint8_t sequence_number;
uint8_t num_segments_received;
uint8_t num_segments_expected;
// the spec allows of upto 128 segments, this does seem excessive
vnf_p7_rx_message_segment_t segments[128];
uint32_t rx_hr_time;
vnf_p7_rx_message_t* next;
} vnf_p7_rx_message_t;
typedef struct {
vnf_p7_rx_message_t* msg_queue;
} vnf_p7_rx_reassembly_queue_t;
typedef struct nfapi_vnf_p7_connection_info {
/*! The PHY id */
int phy_id;
// this does not belong here...
uint8_t stream_id;
/*! Flag indicating the sync state of the P7 conenction */
uint8_t in_sync;
int dl_out_sync_offset;
int dl_out_sync_period; // ms (as a pow2)
int dl_in_sync_offset;
int dl_in_sync_period; // ms (as a pow2)
uint8_t filtered_adjust;
uint16_t min_sync_cycle_count;
uint32_t latency[8];
uint32_t average_latency;
int32_t sf_offset_filtered;
int32_t sf_offset_trend;
int32_t sf_offset;
uint16_t zero_count;
int32_t adjustment;
int32_t insync_minor_adjustment;
int32_t insync_minor_adjustment_duration;
uint32_t previous_t1;
uint32_t previous_t2;
int32_t previous_sf_offset_filtered;
int sfn_sf;
int socket;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
vnf_p7_rx_reassembly_queue_t reassembly_queue;
uint8_t* reassembly_buffer;
uint32_t reassembly_buffer_size;
uint32_t sequence_number;
struct nfapi_vnf_p7_connection_info* next;
} nfapi_vnf_p7_connection_info_t;
typedef struct {
nfapi_vnf_p7_config_t _public;
// private data
uint8_t terminate;
nfapi_vnf_p7_connection_info_t* p7_connections;
int socket;
uint32_t sf_start_time_hr;
uint8_t* rx_message_buffer; // would this be better put in the p7 conenction info?
uint16_t rx_message_buffer_size;
} vnf_p7_t;
uint32_t vnf_get_current_time_hr(void);
uint16_t increment_sfn_sf(uint16_t sfn_sf);
int vnf_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info);
int send_mac_subframe_indications(vnf_p7_t* config);
int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7 );
void vnf_p7_connection_info_list_add(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* node);
nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_find(vnf_p7_t* vnf_p7, uint16_t phy_id);
nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_delete(vnf_p7_t* vnf_p7, uint16_t phy_id);
int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header);
void vnf_p7_release_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header);
void vnf_p7_release_pdu(vnf_p7_t* vnf_p7, void* pdu);
#endif // _VNF_P7_H_
@@ -0,0 +1,995 @@
/*
* 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.
*/
#ifndef _NFAPI_VNF_INTERFACE_H_
#define _NFAPI_VNF_INTERFACE_H_
#include "nfapi_interface.h"
#include "debug.h"
#include "netinet/in.h"
#if defined(__cplusplus)
extern "C" {
#endif
#define NFAPI_MAX_PACKED_MESSAGE_SIZE 8192
/*! The nfapi VNF phy configuration information
*/
typedef struct nfapi_vnf_phy_info
{
/*! The P5 Index */
int p5_idx; //which p5 connection
/*! The PHY ID */
int phy_id; //phy_id
/*! Timing window */
uint8_t timing_window;
/*! Timing info mode */
uint8_t timing_info_mode;
/*! Timing info period */
uint8_t timing_info_period;
/*! P7 UDP socket information for the pnf */
struct sockaddr_in p7_pnf_address;
/*! P7 UDP socket information for the vnf */
struct sockaddr_in p7_vnf_address;
struct nfapi_vnf_phy_info* next;
} nfapi_vnf_phy_info_t;
/*! The nfapi VNF pnf configuration information
*/
typedef struct nfapi_vnf_pnf_info
{
/*! The P5 Index */
int p5_idx;
/*! The P5 socket */
int p5_sock;
/*! Flag indicating if the pnf is connected */
uint8_t connected;
/*! P5 SCTP socket information for the pnf */
struct sockaddr_in p5_pnf_sockaddr;
/*! Flag indicating if this pnf should be deleted */
uint8_t to_delete;
struct nfapi_vnf_pnf_info* next;
} nfapi_vnf_pnf_info_t;
typedef struct nfapi_vnf_config nfapi_vnf_config_t;
/*! The nfapi VNF configuration information
*/
typedef struct nfapi_vnf_config
{
/*! A user define callback to override the default memory allocation */
void* (*malloc)(size_t size);
/*! A user define callback to override the default memory deallocation */
void (*free)(void*);
/*! A user define callback to handle trace from the pnf */
void (*trace)(nfapi_trace_level_t level, const char* message, ...);
/*! The port the VNF P5 SCTP connection listens on
*
* By default this will be set to 7701. However this can be changed if
* required.
*/
int vnf_p5_port;
// todo : for enabling ipv4/ipv6
int vnf_ipv4;
int vnf_ipv6;
/*! List of connected pnfs */
nfapi_vnf_pnf_info_t* pnf_list;
/*! List of configured phys */
nfapi_vnf_phy_info_t* phy_list;
/*! Configuration options for the p4 p5 pack unpack functions */
nfapi_p4_p5_codec_config_t codec_config;
/*! Optional user defined data that will be avaliable in the callbacks*/
void* user_data;
/*! \brief Callback indicating that a pnf has established connection
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 used to indicate this pnf p5 connection
*
* The client is expected to send the PNF_PARAM.request in response to
* the connection indication
*
* \todo Do we need to send the address information of the PNF?
*/
int (*pnf_connection_indication)(nfapi_vnf_config_t* config, int p5_idx);
/*! \brief Callback indicating that a pnf has lost connection
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 used to indicate this pnf p5 connection
*
* The p5_idx may be used for future new p5 connections
*
* The client is responsiable for communicating to the p7 instance(s) that
* may be associated with this p5 that they should be deleted using the
* nfapi_vnf_p7_del_pnf functon
*
*/
int (*pnf_disconnect_indication)(nfapi_vnf_config_t* config, int p5_idx);
// p5 interface functions
/*! \brief A callback to handle the PNF_PARAM.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded PNF_PARAM.response. This will
* have been allocated on the stack.
* \return not currently used.
*
* The PNF_PARAM.resp contains the capability of the PNF identified by the
* p5_idx.
*
* The client is expected to send the PNF_CONFIG.request after receiving the
* PNF_PARAM.resp. This can be done in the call back.
*
* It is expected that the client when building the PNF_CONFIG.request will
* used the nfapi_vnf_allocate_phy() to allocate unique phy id for each FAPI
* instance the client wishes to create.
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*pnf_param_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_response_t* resp);
/*! A callback for the PNF_CONFIG.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded PNF_CONFIG.response. This will
* have been allocated on the stack.
* \return not currently used.
*
* The PNF_CONFIG.resp contains the result of the PNF_CONFIG.request for the
* PNF identified by the p5_idx.
*
* The client is expected to send the PNF_START.request after receiving the
* PNF_PARAM.resp. This can be done in the call back.
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*pnf_config_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_response_t* resp);
/*! A callback for the PNF_START.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded PNF_START.response. This will
* have been allocated on the stack.
* \return not currently used.
*
* The PNF_START.resp contains the result of the PNF_START.request for the
* PNF identified by the p5_idx.
*
* The client is expected to send the PARAM.request for each FAPI instance
* that has been created in the PNF.
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*pnf_start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_response_t* resp);
/*! A callback for the PNF_STOP.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded PNF_STOP.response. This will
* have been allocated on the stack.
* \return not currently used.
*
* The PNF_STOP.response contains the result of the PNF_STOP.request for the
* PNF identified by the p5_idx.
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*pnf_stop_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_stop_response_t* resp);
/*! A callback for the PARAM.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded PARAM.resposne. This will
* have been allocated on the stack.
* \return not currently used.
*
* The PARAM.request contains the capabilities of the FAPI instance identified
* by the phy_id
*
* The client is expected to send the CONFIG.request after receiving the
* PARAM.response. This can be done in the call back. The PARAM.response
* contains the PNF P7 address (ipv4 or ipv6) and port. This information
* is used when calling the nfapi_vnf_p7_add_pnf()
*
* The client is responsible for identifing the VNF P7 ip address
* (ipv4 or ipv6) and port for the VNF P7 entity which will be sent to the
* PNF P7 entity. That endpoint should be valid before send the
* CONFIG.request.
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*param_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t* resp);
/*! A callback for the CONFIG.response
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded CONFIG.response This will
* have been allocated on the stack.
* \return not currently used.
*
* The CONFIG.response contains the result of the CONFIG.request
*
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*config_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_response_t* resp);
/*! A callback for the START.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded START.response This will
* have been allocated on the stack.
* \return not currently used.
*
* The START.response contains the result of the START.request
*
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_response_t* resp);
/*! A callback for the STOP.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded STOP.response This will
* have been allocated on the stack.
* \return not currently used.
*
* The STOP.response contains the result of the STOP.request
*
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*stop_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_response_t* resp);
/*! A callback for the MEASUREMENT.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded MEASUREMENT.response This will
* have been allocated on the stack.
* \return not currently used.
*
* The MEASUREMENT.response contains the result of the MEASUREMENT.request
*
* The resp may contain pointers to dyanmically allocated sub structures
* such as the vendor_extention. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*measurement_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_response_t* resp);
// p4 interface functions
/*! A callback for the RSSI.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded RSSI.response This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*rssi_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_response_t* resp);
/*! A callback for the RSSI.indication
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded RSSI.indication This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*rssi_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_indication_t* ind);
/*! A callback for the CELL_SEARCH.response
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded CELL_SEARCH.response This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*cell_search_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_response_t* resp);
/*! A callback for the CELL_SEARCH.indication
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded CELL_SEARCH.indication This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*cell_search_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_indication_t* ind);
/*! A callback for the BROADCAST_DETECT.response
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded BROADCAST_DETECT.response This will
* have been allocated on the stack.
* \return not currently used. */
int (*broadcast_detect_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_response_t* resp);
/*! A callback for the BROADCAST_DETECT.indication
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded BROADCAST_DETECT.indication This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*broadcast_detect_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_indication_t* ind);
/*! A callback for the SYSTEM_INFORMATION_SCHEUDLE.response
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded SYSTEM_INFORMATION_SCHEUDLE.response This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*system_information_schedule_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_response_t* resp);
/*! A callback for the SYSTEM_INFORMATION_SCHEUDLE.indication
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded SYSTEM_INFORMATION_SCHEUDLE.indication This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*system_information_schedule_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_indication_t* ind);
/*! A callback for the SYSTEM_INFORMATION.response
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded SYSTEM_INFORMATION.response This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*system_information_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_response_t* resp);
/*! A callback for the SYSTEM_INFORMATION.indication
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded SYSTEM_INFORMATION.indication This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*system_information_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_indication_t* ind);
/*! A callback for the NMM_STOP.response
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded NMM_STOP.response This will
* have been allocated on the stack.
* \return not currently used.
*/
int (*nmm_stop_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_nmm_stop_response_t* resp);
/*! A callback for any vendor extension message received
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param resp A data structure for the decoded vendor extention message
* \return not currently used.
*/
int (*vendor_ext)(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg);
/*! A callback to allocate vendor extension messages
* \param message_id The message is taken from the message header
* \param msg_size The is the vendor extention message that has been allocated.
* The callee must set this value
* \return A pointer to an allocated vendor extention message
*/
nfapi_p4_p5_message_header_t* (*allocate_p4_p5_vendor_ext)(uint16_t message_id, uint16_t* msg_size);
/*! A callback to deallocate vendor extension messages
* \param header A pointer to an allocated vendor extention message
*/
void (*deallocate_p4_p5_vendor_ext)(nfapi_p4_p5_message_header_t* header);
} nfapi_vnf_config_t;
/*! Creates and initialise the vnf config structure before use
* \return A pointer to a vnf config structure
*/
nfapi_vnf_config_t* nfapi_vnf_config_create(void);
/*! Delete an vnf config
*/
void nfapi_vnf_config_destory(nfapi_vnf_config_t* config);
/*! Start the VNF library.
* \param config A pointer to a vnf config
* \return 0 means success, -1 failure
*
* The config should be initailize with port the vnf should listen on and
* the callback set to functions that will be called when a nFAPI message is
* recevied before calling nfapi_vnf_start.
*
* This function will not return untill nfapi_vnf_stop is called
*/
int nfapi_vnf_start(nfapi_vnf_config_t* config);
/*! Stop the VNF library.
* \param config A pointer to a vnf config
* \return 0 means success, -1 failure
*
* This function will cause the nfapi_vnf_start function to return
*/
int nfapi_vnf_stop(nfapi_vnf_config_t* config);
/*! Allocates a PHY ID for the PNF PHY instance managed by this VNF
* \param config A pointer to a vnf config
* \param p5_idx The P5 index return by the callbacks
* \param phy_id A pointer to a phy_id that will be set by this function
* \return 0 means success, -1 failure
*
* Called before nfapi_vnf_config_req to allocate a vnf phy instance. This
* function will return unqiue phy_id to be used for this identify the phy
*
*/
int nfapi_vnf_allocate_phy(nfapi_vnf_config_t* config, int p5_idx, uint16_t* phy_id);
// P5 Request functions
//
/*! Send the PNF_PARAM.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a PNF_PARAM.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_request_t* req);
/*! Send the PNF_CONFIG.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a PNF_CONFIG.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_pnf_config_req(nfapi_vnf_config_t* config,int p5_idx, nfapi_pnf_config_request_t* req);
/*! Send the PNF_START.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a PNF_START.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_pnf_start_req(nfapi_vnf_config_t* config,int p5_idx, nfapi_pnf_start_request_t* req);
/*! Send the PNF_STOP.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a PNF_STOP.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_pnf_stop_req(nfapi_vnf_config_t* config,int p5_idx, nfapi_pnf_stop_request_t* req);
/*! Send the PARAM.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a PARAM.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_request_t* req);
/*! Send the CONFIG.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a CONFIG.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_request_t* req);
/*! Send the START.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a START.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_request_t* req);
/*! Send the STOP.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a STOP.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_request_t* req);
/*! Send the MEASUREMENT.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a MEASUREMENT.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_measurement_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_request_t* req);
// P4 Request functions
/*! Send the RSSI.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a RSSI.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_rssi_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_request_t* req);
/*! Send the CELL_SEARCH.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a CELL_SEARCH.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_cell_search_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_request_t* req);
/*! Send the BROADCAST_DETECT.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a BROADCAST_DETECT.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_broadcast_detect_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_request_t* req);
/*! Send the SYSTEM_INFORMATION_SCHEDULE.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a SYSTEM_INFORMATION_SCHEDULE.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_system_information_schedule_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_request_t* req);
/*! Send the SYSTEM_INFORMATION.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a SYSTEM_INFORMATION.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_system_information_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_request_t* req);
/*! Send the NMM_STOP.request
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param req A pointer to a NMM_STOP.request message structure
* \return 0 means success, -1 failure
*/
int nfapi_vnf_nmm_stop_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_nmm_stop_request_t* req);
/*! Send a vendor extension message
* \param config A pointer to a vnf config
* \param p5_idx The P5 index
* \param msg A poiner to a vendor extention message
* \return 0 means success, -1 failure
*/
int nfapi_vnf_vendor_extension(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg);
//-----------------------------------------------------------------------------
/*! The nfapi VNF P7 connection information
*/
typedef struct nfapi_vnf_p7_config nfapi_vnf_p7_config_t;
/*! The nfapi VNF P7 configuration information
*/
typedef struct nfapi_vnf_p7_config
{
/*! A user define callback to override the default memory allocation
* \param size Size of the memory block to allocate
* \return a pointer to a memory block
*
* If not set the vnf p7 library will use malloc
*/
void* (*malloc)(size_t size);
/*! A user define callback to override the default memory deallocation
* \param ptr Pointer to a memory block to deallocate
*
* If not set the vnf p7 library will use free
*/
void (*free)(void*);
/*! A user define callback to handle trace from the pnf
* \param level The trace level
* \param message The trace string
*/
void (*trace)(nfapi_trace_level_t level, const char* message, ...);
/*! The port the vnf p7 will receive on */
int port;
/*! Flag to indicate of the pnf should use the P7 checksum */
uint8_t checksum_enabled;
/*! The maxium size of a P7 segement. If a message is large that this it
* will be segemented */
uint16_t segment_size;
uint16_t max_num_segments;
/*! Configuration option for the p7 pack unpack functions*/
nfapi_p7_codec_config_t codec_config;
/* ! Call back to indicate the sync state with the PNF PHY
* \param config A pointer to the vnf p7 configuration
* \param sync Indicating if the pnf is in sync or not
* \return not currently used
*
* sync = 0 : in sync
* sync != 0 : out of sync
*/
int (*sync_indication)(struct nfapi_vnf_p7_config* config, uint8_t sync);
/*! A callback for the subframe indication
* \param config A pointer to the vnf p7 configuration
* \param phy_id The ID for the PNF PHY instance
* \param sfn_sf The SFN SF number formated as per the FAPI specification
* \return not currently used
*
* This callback is an indication for the VNF to generate the downlink subframe messages
* for sfn/sf. This indicatoin is called every millisecond
*
* The VNF P7 Lib will adjust the subframe timing to 'catch-up' or 'slow-down' with the PNF PHY's
*
* \todo Need some way the tell the VNF how long it has
*/
int (*subframe_indication)(struct nfapi_vnf_p7_config* config, uint16_t phy_id, uint16_t sfn_sf);
/*! A callback for the HARQ.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded HARQ.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*harq_indication)(struct nfapi_vnf_p7_config* config, nfapi_harq_indication_t* ind);
/*! A callback for the CRC.ind
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded CRC.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*crc_indication)(struct nfapi_vnf_p7_config* config, nfapi_crc_indication_t* ind);
/*! A callback for the RX_ULSCH.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded RX_ULSCH.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*
* Note that the rx_indication may hold one or many uplink pdus in the
* ind.rx_indication_body.rx_pdu_list
*/
int (*rx_indication)(struct nfapi_vnf_p7_config* config, nfapi_rx_indication_t* ind);
/*! A callback for the RACH.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded RACH.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*rach_indication)(struct nfapi_vnf_p7_config* config, nfapi_rach_indication_t* ind);
/*! A callback for the SRS.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded SRS.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*srs_indication)(struct nfapi_vnf_p7_config* config, nfapi_srs_indication_t* ind);
/*! A callback for the RX_SR.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded RX_SR.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*sr_indication)(struct nfapi_vnf_p7_config* config, nfapi_sr_indication_t* ind);
/*! A callback for the RX_CQI.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded RX_CQI.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*cqi_indication)(struct nfapi_vnf_p7_config* config, nfapi_cqi_indication_t* ind);
/*! A callback for the LBT_DL.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded LBT_DL.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*lbt_dl_indication)(struct nfapi_vnf_p7_config* config, nfapi_lbt_dl_indication_t* ind);
/*! A callback for the NB_HARQ.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded LBT_DL.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*nb_harq_indication)(struct nfapi_vnf_p7_config* config, nfapi_nb_harq_indication_t* ind);
/*! A callback for the NRACH.indication
* \param config A pointer to the vnf p7 configuration
* \param ind A data structure for the decoded LBT_DL.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The ind may contain pointers to dyanmically allocated sub structures
* such as the pdu. The dyanmically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*nrach_indication)(struct nfapi_vnf_p7_config* config, nfapi_nrach_indication_t* ind);
/*! A callback for any vendor extension messages
* \param config A pointer to the vnf p7 configuration
* \param msg A data structure for the decoded vendor extention message allocated
* using the allocate_p7_vendor_ext callback
* \return not currently used.
*/
int (*vendor_ext)(struct nfapi_vnf_p7_config* config, nfapi_p7_message_header_t* msg);
/*! Optional userdata that will be passed back in the callbacks*/
void* user_data;
/*! A callback to allocate a memory for a vendor extension message
* \param message_id The message is taken from the p7 message header
* \param msg_size The is the vendor extention message that has been allocated.
* The callee must set this value
* \return A pointer to an allocated vendor extention message
*/
nfapi_p7_message_header_t* (*allocate_p7_vendor_ext)(uint16_t message_id, uint16_t* msg_size);
/*! A callback to deallocate a vendor extension message
* \param header A pointer to an allocated vendor extention message
*/
void (*deallocate_p7_vendor_ext)(nfapi_p7_message_header_t* header);
} nfapi_vnf_p7_config_t;
/*! Creates and initializes the nfapi_vnf_p7_config structure before use
* \return A pointer to an allocated vnf p7 configuration
*/
nfapi_vnf_p7_config_t* nfapi_vnf_p7_config_create(void);
/*! Cleanup and delete nfapi_vnf_p7_config structure
* \param config A pointer to an vnf p7 configuration structure
*
* The pointer to the config will not long be valid after this call
*/
void nfapi_vnf_p7_config_destory(nfapi_vnf_p7_config_t* config);
/*! Start the VNF P7 library.
* \param config A pointer to an vnf p7 configuration structure
* \return A status value. 0 equal success, -1 indicates failure
*
* This function is blocking and will not return until the nfapi_vnf_p7_stop
* function is called.
*/
int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config);
/*! Stop the VNF P7 library.
* \param config A pointer to an vnf p7 configuration structure
* \return A status value. 0 equal success, -1 indicates failure
*
* This function will cause the nfapi_vnf_p7_start function to return
*/
int nfapi_vnf_p7_stop(nfapi_vnf_p7_config_t* config);
/*! Release a P7 message back to the vnf_p7 library. This should be used if the
* callback return 0 in the case where MAC wants to keep the message for
* futher processing.
* This function will release any pdu's is they are non-null. If the uplink
* PDU need to be kept then they pdu pointer should be set to 0 in the message
* and then the nfapi_vnf_p7_release_pdu message can be used to release the
* pdu later.
*/
int nfapi_vnf_p7_release_msg(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t*);
/*! Release a P7 pdu's back to the vnf_p7 library.
*/
int nfapi_vnf_p7_release_pdu(nfapi_vnf_p7_config_t* config, void*);
/*! Add a vnf p7 instance to the vnf p7 module
* \param config A pointer to the vnf p7 configuration
* \param pnf_p7_addr The udp address the pnf p7 entity has chosen
* \param pnf_p7_port The udp port the pnf p7 entity has chosen
* \param phy_id The unique phy id for the pnf p7 entity
* \return A status value. 0 equal success, -1 indicates failure
*
* This function should be used to each pnf p7 entity that is to be added to this
* vnf p7 entity. Once added the vnf p7 entity will start establish sync with the
* pnf p7 entity and that has been sucessfull will generate subframe indications for it
*/
int nfapi_vnf_p7_add_pnf(nfapi_vnf_p7_config_t* config, const char* pnf_p7_addr, int pnf_p7_port, int phy_id);
/*! Delete a vnf p7 instance to the vnf p7 module
* \param config A pointer to the vnf p7 configuration
* \param phy_id The unique phy id for the pnf p7 entity
* \return A status value. 0 equal success, -1 indicates failure
*
* This function should be used to remove a pnf p7 entity from the vnf p7 entity
*/
int nfapi_vnf_p7_del_pnf(nfapi_vnf_p7_config_t* config, int phy_id);
/*! Send the DL_CONFIG.request
* \param config A pointer to the vnf p7 configuration
* \param req A data structure for the decoded DL_CONFIG.request.
* \return A status value. 0 equal success, -1 indicates failure
*
* The caller is responsiable for memory management of any pointers set in the req, which
* may be released after this function call has returned or at a later pointer
*/
int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_request_t* req);
/*! Send the UL_CONFIG.request
* \param config A pointer to the vnf p7 configuration
* \param req A data structure for the decoded UL_CONFIG.request.
* \return A status value. 0 equal success, -1 indicates failure
*
* The caller is responsiable for memory management of any pointers set in the req, which
* may be released after this function call has returned or at a later pointer
*/
int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_request_t* req);
/*! Send the HI_DCI0.request
* \param config A pointer to the vnf p7 configuration
* \param req A data structure for the decoded HI_DCI0.request.
* \return A status value. 0 equal success, -1 indicates failure
*
* The caller is responsiable for memory management of any pointers set in the req, which
* may be released after this function call has returned or at a later pointer
*/
int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_request_t* req);
/*! Send the TX.req
* \param config A pointer to the vnf p7 configuration
* \param req A data structure for the decoded HI_DCI0.request.
* \return A status value. 0 equal success, -1 indicates failure
*
* The caller is responsiable for memory management of any pointers set in the req, which
* may be released after this function call has returned or at a later pointer
*/
int nfapi_vnf_p7_tx_req(nfapi_vnf_p7_config_t* config, nfapi_tx_request_t* req);
/*! Send the LBT_DL_CONFIG.requst
* \param config A pointer to the vnf p7 configuration
* \param req A data structure for the decoded LBT_DL_CONFIG.request.
* \return A status value. 0 equal success, -1 indicates failure
*
* The caller is responsiable for memory management of any pointers set in the req, which
* may be released after this function call has returned or at a later pointer
*/
int nfapi_vnf_p7_lbt_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req);
/*! Send a vendor extension message
* \param config A pointer to the vnf p7 configuration
* \param msg A data structure for the decoded vendor extention message
* \return A status value. 0 equal success, -1 indicates failure
*
* The caller is responsiable for memory management of any pointers set in the req, which
* may be released after this function call has returned or at a later pointer
*/
int nfapi_vnf_p7_vendor_extension(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* msg);
#if defined(__cplusplus)
}
#endif
#endif // _NFAPI_PNF_INTERFACE_H_
File diff suppressed because it is too large Load Diff
+676
View File
@@ -0,0 +1,676 @@
/*
* 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 <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 <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 &(_this->_public);
}
void nfapi_vnf_config_destory(nfapi_vnf_config_t* config)
{
free(config);
}
int nfapi_vnf_start(nfapi_vnf_config_t* config)
{
// Verify that config is not null
if(config == 0)
return -1;
// Make sure to set the defined trace function before using NFAPI_TRACE
if(config->trace)
nfapi_trace_g = (nfapi_trace_fn_t)config->trace;
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_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_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_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_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_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_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_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???
info->timing_info_mode = 0x03;
info->timing_info_period = 128;
nfapi_vnf_phy_info_list_add(config, info);
(*phy_id) = info->phy_id;
return 0;
}
File diff suppressed because it is too large Load Diff
+562
View File
@@ -0,0 +1,562 @@
/*
* 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 <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "vnf_p7.h"
#define FAPI2_IP_DSCP 0
nfapi_vnf_p7_config_t* nfapi_vnf_p7_config_create()
{
vnf_p7_t* _this = (vnf_p7_t*)calloc(1, sizeof(vnf_p7_t));
if(_this == 0)
return 0;
// todo : initialize
_this->_public.segment_size = 1400;
_this->_public.max_num_segments = 8;
_this->_public.checksum_enabled = 1;
_this->_public.malloc = &malloc;
_this->_public.free = &free;
_this->_public.codec_config.allocate = &malloc;
_this->_public.codec_config.deallocate = &free;
return &(_this->_public);
}
void nfapi_vnf_p7_config_destory(nfapi_vnf_p7_config_t* config)
{
free(config);
}
struct timespec timespec_add(struct timespec lhs, struct timespec rhs)
{
struct timespec result;
result.tv_sec = lhs.tv_sec + rhs.tv_sec;
result.tv_nsec = lhs.tv_nsec + rhs.tv_nsec;
if(result.tv_nsec > 1e9)
{
result.tv_sec++;
result.tv_nsec-= 1e9;
}
return result;
}
struct timespec timespec_sub(struct timespec lhs, struct timespec rhs)
{
struct timespec result;
if ((lhs.tv_nsec-rhs.tv_nsec)<0)
{
result.tv_sec = lhs.tv_sec-rhs.tv_sec-1;
result.tv_nsec = 1000000000+lhs.tv_nsec-rhs.tv_nsec;
}
else
{
result.tv_sec = lhs.tv_sec-rhs.tv_sec;
result.tv_nsec = lhs.tv_nsec-rhs.tv_nsec;
}
return result;
}
// monitor the p7 endpoints and the timing loop and
// send indications to mac
int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config)
{
if(config == 0)
return -1;
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__);
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
// Create p7 receive udp port
// todo : this needs updating for Ipv6
NFAPI_TRACE(NFAPI_TRACE_INFO, "Initialising VNF P7 port:%u\n", config->port);
// open the UDP socket
if ((vnf_p7->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno);
return -1;
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 socket created...\n");
// configure the UDP socket options
int iptos_value = FAPI2_IP_DSCP << 2;
if (setsockopt(vnf_p7->socket, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0)
{
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (IP_TOS) errno: %d\n", errno);
return -1;
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 setsockopt succeeded...\n");
// Create the address structure
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(config->port);
addr.sin_addr.s_addr = INADDR_ANY;
// bind to the configured port
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 binding too %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if (bind(vnf_p7->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
//if (sctp_bindx(config->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), 0) < 0)
{
NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno);
return -1;
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 bind succeeded...\n");
//struct timespec original_pselect_timeout;
struct timespec pselect_timeout;
pselect_timeout.tv_sec = 0;
pselect_timeout.tv_nsec = 1000000; // ns in a 1 us
struct timespec pselect_start;
struct timespec pselect_stop;
//struct timespec sf_end;
long last_millisecond = -1;
struct timespec sf_duration;
sf_duration.tv_sec = 0;
sf_duration.tv_nsec = 1e6; // We want 1ms pause
struct timespec sf_start;
clock_gettime(CLOCK_MONOTONIC, &sf_start);
long millisecond = sf_start.tv_nsec / 1e6;
sf_start = timespec_add(sf_start, sf_duration);
NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec);
while(vnf_p7->terminate == 0)
{
fd_set rfds;
int maxSock = 0;
FD_ZERO(&rfds);
int selectRetval = 0;
// Add the p7 socket
FD_SET(vnf_p7->socket, &rfds);
maxSock = vnf_p7->socket;
clock_gettime(CLOCK_MONOTONIC, &pselect_start);
//long millisecond = pselect_start.tv_nsec / 1e6;
if((last_millisecond == -1) || (millisecond == last_millisecond) || (millisecond == (last_millisecond + 1) % 1000) )
{
//NFAPI_TRACE(NFAPI_TRACE_INFO, "pselect_start:%d.%d sf_start:%d.%d\n", pselect_start.tv_sec, pselect_start.tv_nsec, sf_start.tv_sec, sf_start.tv_nsec);
if((pselect_start.tv_sec > sf_start.tv_sec) ||
((pselect_start.tv_sec == sf_start.tv_sec) && (pselect_start.tv_nsec > sf_start.tv_nsec)))
{
// overran the end of the subframe we do not want to wait
pselect_timeout.tv_sec = 0;
pselect_timeout.tv_nsec = 0;
//struct timespec overrun = timespec_sub(pselect_start, sf_start);
//NFAPI_TRACE(NFAPI_TRACE_INFO, "Subframe overrun detected of %d.%d running to catchup\n", overrun.tv_sec, overrun.tv_nsec);
}
else
{
// still time before the end of the subframe wait
pselect_timeout = timespec_sub(sf_start, pselect_start);
#if 0
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sf_start:%d.%ld pselect_start:%d.%ld pseclect_timeout:%d.%ld\n",
__FUNCTION__,
sf_start.tv_sec, sf_start.tv_nsec,
pselect_start.tv_sec, pselect_start.tv_nsec,
pselect_timeout.tv_sec, pselect_timeout.tv_nsec);
#endif
}
//original_pselect_timeout = pselect_timeout;
// detemine how long to sleep in ns before the start of the next 1ms
//pselect_timeout.tv_nsec = 1e6 - (pselect_start.tv_nsec % 1000000);
//uint8_t underrun_possible =0;
// if we are not sleeping until the next milisecond due to the
// insycn minor adjment flag it so we don't consider it an error
//uint8_t underrun_possible =0;
/*
{
nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections;
if(phy && phy->in_sync && phy->insync_minor_adjustment != 0 && phy->insync_minor_adjustment_duration > 0 && pselect_start.tv_nsec != 0)
{
NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] Subframe minor adjustment %d (%d->%d)\n", phy->insync_minor_adjustment,
pselect_timeout.tv_nsec, pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000))
if(phy->insync_minor_adjustment > 0)
{
// todo check we don't go below 0
if((phy->insync_minor_adjustment * 1000) > pselect_timeout.tv_nsec)
pselect_timeout.tv_nsec = 0;
else
pselect_timeout.tv_nsec = pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000);
//underrun_possible = 1;
}
else if(phy->insync_minor_adjustment < 0)
{
// todo check we don't go below 0
pselect_timeout.tv_nsec = pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000);
}
//phy->insync_minor_adjustment = 0;
phy->insync_minor_adjustment_duration--;
}
}
*/
//long wraps = pselect_timeout.tv_nsec % 1e9;
selectRetval = pselect(maxSock+1, &rfds, NULL, NULL, &pselect_timeout, NULL);
clock_gettime(CLOCK_MONOTONIC, &pselect_stop);
nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections;
if (selectRetval==-1 && errno == 22)
{
NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%d.%ld adj[dur:%d adj:%d], sf_dur:%d.%ld\n",
pselect_timeout.tv_sec, pselect_timeout.tv_nsec,
phy->insync_minor_adjustment_duration, phy->insync_minor_adjustment,
sf_duration.tv_sec, sf_duration.tv_nsec);
}
#if 0
if (selectRetval != 0 || phy->insync_minor_adjustment_duration != 0)
NFAPI_TRACE(NFAPI_TRACE_NOTE, "pselect()=%d maxSock:%d vnf_p7->socket:%d pselect_timeout:%u.%u original_pselect_timeout:%u.%u\n",
selectRetval, maxSock, vnf_p7->socket, pselect_timeout.tv_sec, pselect_timeout.tv_nsec,
original_pselect_timeout.tv_sec, original_pselect_timeout.tv_nsec);
#endif
if(selectRetval == 0)
{
// calculate the start of the next subframe
sf_start = timespec_add(sf_start, sf_duration);
//NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec);
if(phy && phy->in_sync && phy->insync_minor_adjustment != 0 && phy->insync_minor_adjustment_duration > 0)
{
long insync_minor_adjustment_ns = (phy->insync_minor_adjustment * 1000);
sf_start.tv_nsec -= insync_minor_adjustment_ns;
#if 1
if (sf_start.tv_nsec > 1e9)
{
sf_start.tv_sec++;
sf_start.tv_nsec-=1e9;
}
else if (sf_start.tv_nsec < 0)
{
sf_start.tv_sec--;
sf_start.tv_nsec+=1e9;
}
#else
//NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] BEFORE adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d\n", phy->insync_minor_adjustment, sf_start.tv_nsec);
if(phy->insync_minor_adjustment > 0)
{
// decrease the subframe duration a little
if (sf_start.tv_nsec > insync_minor_adjustment_ns)
sf_start.tv_nsec -= insync_minor_adjustment_ns;
else
{
NFAPI_TRACE(NFAPI_TRACE_ERROR, "[VNF] Adjustment would make it negative sf:%d.%ld adjust:%ld\n\n\n", sf_start.tv_sec, sf_start.tv_nsec, insync_minor_adjustment_ns);
sf_start.tv_sec--;
sf_start.tv_nsec += 1e9 - insync_minor_adjustment_ns;
}
}
else if(phy->insync_minor_adjustment < 0)
{
// todo check we don't go below 0
// increase the subframe duration a little
sf_start.tv_nsec += insync_minor_adjustment_ns;
if (sf_start.tv_nsec < 0)
{
NFAPI_TRACE(NFAPI_TRACE_ERROR, "[VNF] OVERFLOW %d.%ld\n\n\n\n", sf_start.tv_sec, sf_start.tv_nsec);
sf_start.tv_sec++;
sf_start.tv_nsec += 1e9;
}
}
#endif
//phy->insync_minor_adjustment = 0;
phy->insync_minor_adjustment_duration--;
NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] AFTER adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d duration:%u\n",
phy->insync_minor_adjustment, sf_start.tv_nsec, phy->insync_minor_adjustment_duration);
if (phy->insync_minor_adjustment_duration==0)
{
phy->insync_minor_adjustment = 0;
}
}
/*
long pselect_stop_millisecond = pselect_stop.tv_nsec / 1e6;
if(millisecond == pselect_stop_millisecond)
{
// we have woke up in the same subframe
if(underrun_possible == 0)
NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe pselect underrun %ld (%d.%d)\n", millisecond, pselect_stop.tv_sec, pselect_stop.tv_nsec);
}
else if(((millisecond + 1) % 1000) != pselect_stop_millisecond)
{
// we have overrun the subframe
NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe pselect overrun %ld %ld\n", millisecond, pselect_stop_millisecond);
NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe underrun %ld\n", millisecond);
}
last_millisecond = millisecond;
*/
millisecond ++;
}
}
else
{
// we have overrun the subframe advance to go and collect $200
if((millisecond - last_millisecond) > 3)
NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe overrun %ld %ld (%ld)\n", millisecond, last_millisecond, millisecond - last_millisecond + 1);
last_millisecond = ( last_millisecond + 1 ) % 1000;
selectRetval = 0;
}
if(selectRetval == 0)
{
vnf_p7->sf_start_time_hr = vnf_get_current_time_hr();
// pselect timed out
nfapi_vnf_p7_connection_info_t* curr = vnf_p7->p7_connections;
while(curr != 0)
{
curr->sfn_sf = increment_sfn_sf(curr->sfn_sf);
vnf_sync(vnf_p7, curr);
curr = curr->next;
}
send_mac_subframe_indications(vnf_p7);
}
else if(selectRetval > 0)
{
// have a p7 message
if(FD_ISSET(vnf_p7->socket, &rfds))
{
vnf_p7_read_dispatch_message(vnf_p7);
}
}
else
{
// pselect error
if(selectRetval == -1 && errno == EINTR)
{
// a sigal was received.
}
else
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d orginal:%d.%d last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond);
// should we exit now?
if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration
{
usleep(100000);
}
}
}
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p7 socket\n");
close(vnf_p7->socket);
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() returning\n", __FUNCTION__);
return 0;
}
int nfapi_vnf_p7_stop(nfapi_vnf_p7_config_t* config)
{
if(config == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
vnf_p7->terminate =1;
return 0;
}
int nfapi_vnf_p7_add_pnf(nfapi_vnf_p7_config_t* config, const char* pnf_p7_addr, int pnf_p7_port, int phy_id)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p phy_id:%d pnf_addr:%s pnf_p7_port:%d)\n", __FUNCTION__, config, phy_id, pnf_p7_addr, pnf_p7_port);
if(config == 0)
{
return -1;
}
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
nfapi_vnf_p7_connection_info_t* node = (nfapi_vnf_p7_connection_info_t*)malloc(sizeof(nfapi_vnf_p7_connection_info_t));
memset(node, 0, sizeof(nfapi_vnf_p7_connection_info_t));
node->phy_id = phy_id;
node->in_sync = 0;
node->dl_out_sync_offset = 30;
node->dl_out_sync_period = 10;
node->dl_in_sync_offset = 30;
node->dl_in_sync_period = 512;
node->sfn_sf = 0;
node->min_sync_cycle_count = 8;
// save the remote endpoint information
node->remote_addr.sin_family = AF_INET;
node->remote_addr.sin_port = htons(pnf_p7_port);
node->remote_addr.sin_addr.s_addr = inet_addr(pnf_p7_addr);
vnf_p7_connection_info_list_add(vnf_p7, node);
return 0;
}
int nfapi_vnf_p7_del_pnf(nfapi_vnf_p7_config_t* config, int phy_id)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(phy_id:%d)\n", __FUNCTION__, phy_id);
if(config == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
nfapi_vnf_p7_connection_info_t* to_delete = vnf_p7_connection_info_list_delete(vnf_p7, phy_id);
if(to_delete)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(phy_id:%d) deleting connection info\n", __FUNCTION__, phy_id);
free(to_delete);
}
return 0;
}
int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_request_t* req)
{
//NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p req:%p)\n", __FUNCTION__, config, req);
if(config == 0 || req == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header);
}
int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_request_t* req)
{
if(config == 0 || req == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header);
}
int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_request_t* req)
{
if(config == 0 || req == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header);
}
int nfapi_vnf_p7_tx_req(nfapi_vnf_p7_config_t* config, nfapi_tx_request_t* req)
{
if(config == 0 || req == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header);
}
int nfapi_vnf_p7_lbt_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req)
{
if(config == 0 || req == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header);
}
int nfapi_vnf_p7_vendor_extension(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* header)
{
if(config == 0 || header == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
return vnf_p7_pack_and_send_p7_msg(vnf_p7, header);
}
int nfapi_vnf_p7_release_msg(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* header)
{
if(config == 0 || header == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
vnf_p7_release_msg(vnf_p7, header);
return 0;
}
int nfapi_vnf_p7_release_pdu(nfapi_vnf_p7_config_t* config, void* pdu)
{
if(config == 0 || pdu == 0)
return -1;
vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
vnf_p7_release_pdu(vnf_p7, pdu);
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
#
# 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.
#
#vnf unit test
#AUTOMAKE_OPTIONS=subdir-objects
AM_CPPFLAGS = -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/vnf/public_inc $(CFLAGS_CUNIT) -Wall -Werror
check_PROGRAMS= test_vnf
test_vnf_SOURCES = vnf_cunit_main.c ../..//common/src/debug.c
test_vnf_LDADD=$(top_builddir)/vnf/libnfapi_vnf.a $(top_builddir)/nfapi/libnfapi.a -L$(libdir) -lpthread -lrt -lsctp -lz -lcunit
LOG_DRIVER = $(top_srcdir)/tap-driver.sh
TESTS=test_vnf
EXTRA_DIST = $(TESTS)
File diff suppressed because it is too large Load Diff