From: svaidhya Date: Thu, 25 Apr 2024 11:23:16 +0000 (+0530) Subject: [Epic-Id: ODUHIGH-576] [Task-Id: ODUHIGH-586] [SubTask-Id: ODUHIGH-587] PNF P5 Interf... X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=126311f280e74166c87f0061be3220acf3e14fce;p=o-du%2Fl2.git [Epic-Id: ODUHIGH-576] [Task-Id: ODUHIGH-586] [SubTask-Id: ODUHIGH-587] PNF P5 Interface creation and PNF Stub Change-Id: I381a146c16610d765c92403e2e205f8db861f20b Signed-off-by: svaidhya --- diff --git a/build/common/pnf_stub.mak b/build/common/pnf_stub.mak new file mode 100644 index 000000000..4a7c14d1b --- /dev/null +++ b/build/common/pnf_stub.mak @@ -0,0 +1,56 @@ +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# 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. # +################################################################################ + +# This is makefile for PNF STUB + +include ../common/rsys_fancy.mak +include ../common/env.mak +COLOR=$(COLOR_RED) + +SRC_DIR=$(ROOT_DIR)/src/pnf_stub/ +C_SRCS=$(wildcard $(SRC_DIR)/*.c) +C_OBJS=$(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(C_SRCS)) + +# prepare the list of common header files +HDR_FILES+=$(wildcard $(CM_DIR)/env*.[hx]) +HDR_FILES+=$(wildcard $(CM_DIR)/gen*.[hx]) +HDR_FILES+=$(wildcard $(CM_DIR)/ssi*.[hx]) +HDR_FILES+=$(wildcard $(CM_DIR)/cm*.[hx]) + + +lib: $(LIB_DIR)/libpnf.a +include $(COM_BUILD_DIR)/compile.mak + +I_OPTS+=-I$(ROOT_DIR)/src/mt + +#-------------------------------------------------------------# +#Linker macros +#-------------------------------------------------------------# +$(LIB_DIR)/libpnf.a:$(C_OBJS) + @echo -e "Creating Archive $(COLOR) $@ $(REVERT_COLOR)" + $(Q)ar -cr $(LIB_DIR)/libpnf.a $(C_OBJS) + +#-------------------------------------------------------------# +#Clean macros +#-------------------------------------------------------------# +clean: + @echo -e "$(COLOR_RED)Cleaning PNF STUB$(REVERT_COLOR)" + @echo $(SRC_DIR) $(CM_DIR) + $(Q)\rm -f $(LIB_DIR)/libpnf.a $(C_OBJS) + +#********************************************************************** +# End of file +#********************************************************************** diff --git a/build/config/fdd_odu_config.xml b/build/config/fdd_odu_config.xml index d61ad427d..54a110057 100644 --- a/build/config/fdd_odu_config.xml +++ b/build/config/fdd_odu_config.xml @@ -17,10 +17,12 @@ 192.168.130.81 192.168.130.82 192.168.130.80 + 192.168.130.79 38472 36421 - 2 + 7701 + 3 2152 diff --git a/build/config/startup_config.xml b/build/config/startup_config.xml index 045c1c2b4..3a816c133 100644 --- a/build/config/startup_config.xml +++ b/build/config/startup_config.xml @@ -15,5 +15,10 @@ 192.168.130.80 36422 + +pnf +192.168.130.79 +7701 + diff --git a/build/config/tdd_odu_config.xml b/build/config/tdd_odu_config.xml index de19fde55..206303be2 100644 --- a/build/config/tdd_odu_config.xml +++ b/build/config/tdd_odu_config.xml @@ -17,10 +17,12 @@ 192.168.130.81 192.168.130.82 192.168.130.80 + 192.168.130.79 38472 36421 - 2 + 7701 + 3 2152 diff --git a/build/odu/makefile b/build/odu/makefile index e1b0d4005..90860b2c2 100644 --- a/build/odu/makefile +++ b/build/odu/makefile @@ -74,7 +74,7 @@ endif # macro for output file name and makefile name # -PLTFRM_FLAGS=-UMSPD -DODU -DINTEL_FAPI -UODU_MEMORY_DEBUG_LOG -DDEBUG_ASN_PRINT -UDEBUG_PRINT -DERROR_PRINT -USTART_DL_UL_DATA -UNR_DRX -UCALL_FLOW_DEBUG_LOG -UODU_SLOT_IND_DEBUG_LOG -UNFAPI_ENABLED +PLTFRM_FLAGS=-UMSPD -DODU -DINTEL_FAPI -UODU_MEMORY_DEBUG_LOG -DDEBUG_ASN_PRINT -UDEBUG_PRINT -DERROR_PRINT -USTART_DL_UL_DATA -UNR_DRX -UCALL_FLOW_DEBUG_LOG -UODU_SLOT_IND_DEBUG_LOG -DNFAPI_ENABLED ifeq ($(MODE),TDD) PLTFRM_FLAGS += -DNR_TDD @@ -152,13 +152,15 @@ help: @echo -e "$(RULE)odu - Builds all components of ODU$(NORM)" @echo -e "$(RULE)cu_stub - Builds all CU Stub$(NORM)" @echo -e "$(RULE)ric_stub - Builds all RIC_Stub$(NORM)" + @echo -e "$(RULE)pnf_stub - Builds all PNF_Stub$(NORM)" @echo -e "$(RULE)clean_odu - clean up ODU$(NORM)" @echo -e "$(RULE)clean_cu - clean up CU Stub$(NORM)" @echo -e "$(RULE)clean_ric - clean up RIC Stub$(NORM)" + @echo -e "$(RULE)clean_pnf - clean up PNF Stub$(NORM)" @echo -e "$(RULE)clean_all - cleanup everything$(NORM)" @echo -e "$(OPTS)options: $(NORM)" @echo -e "$(OPTS) MACHINE=BIT64/BIT32 - Default is BIT32$(NORM)" - @echo -e "$(OPTS) NODE=TEST_STUB - Mandatory option for cu_stub/ric_stub$(NORM)" + @echo -e "$(OPTS) NODE=TEST_STUB - Mandatory option for cu_stub/ric_stub/pnf_stub$(NORM)" @echo -e "$(OPTS) MODE=TDD - If not specified, MODE=FDD$(NORM)" @echo -e "$(OPTS) PHY=INTEL_L1 - If not specified, Phy stub is used$(NORM)" @echo -e "$(OPTS) PHY_MODE=TIMER - Testing mode for INTEL_L1" @@ -188,6 +190,13 @@ prepare_ric_dirs: $(Q)mkdir -p $(BIN_DIR)/ric_stub $(Q)echo -e "Directories are successfully prepared" +prepare_pnf_dirs: + $(Q)echo -e "Preparing directories for build..." + $(Q)mkdir -p $(BUILD_DIR)/obj/pnf_stub + $(Q)mkdir -p $(LIB_ROOT)/pnf_stub + $(Q)mkdir -p $(BIN_DIR)/pnf_stub + $(Q)echo -e "Directories are successfully prepared" + du: $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/asn_common.mak OBJ_DIR=$(OBJ_ROOT)/odu LIB_DIR=$(LIB_ROOT)/odu LOG_DIR=$(LOG_ROOT)/odu CC='$(CC1)' $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/asn_f1ap.mak OBJ_DIR=$(OBJ_ROOT)/odu LIB_DIR=$(LIB_ROOT)/odu LOG_DIR=$(LOG_ROOT)/odu CC='$(CC1)' @@ -239,7 +248,7 @@ endif $(Q)rm -rf $(ROOT_DIR)/bin/odu $(Q)echo -e "***** ODU CLEAN COMPLETE *****" -clean_all: clean_odu clean_cu clean_ric +clean_all: clean_odu clean_cu clean_ric clean_pnf $(Q)rm -rf $(OBJ_ROOT) $(Q)rm -rf $(LIB_ROOT) $(Q)rm -rf $(LOG_ROOT) @@ -323,6 +332,29 @@ link_ric: $(Q)cp -f ../scripts/start_ric_stub_logging.sh $(ROOT_DIR)/bin/ric_stub $(Q)echo -e "***** RIC STUB BUILD COMPLETE *****" +pnf: + $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/pnf_stub.mak OBJ_DIR=$(OBJ_ROOT)/pnf_stub LIB_DIR=$(LIB_ROOT)/pnf_stub LOG_DIR=$(LOG_ROOT)/pnf_stub CC='$(CC1)' + $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/cm.mak OBJ_DIR=$(OBJ_ROOT)/pnf_stub LIB_DIR=$(LIB_ROOT)/pnf_stub LOG_DIR=$(LOG_ROOT)/pnf_stub CC='$(CC1)' + $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/mt.mak OBJ_DIR=$(OBJ_ROOT)/pnf_stub LIB_DIR=$(LIB_ROOT)/pnf_stub LOG_DIR=$(LOG_ROOT)/pnf_stub CC='$(CC1)' + +clean_pnf: + $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/pnf_stub.mak clean OBJ_DIR=$(OBJ_ROOT)/pnf_stub LIB_DIR=$(LIB_ROOT)/pnf_stub LOG_DIR=$(LOG_ROOT)/pnf_stub CC='$(CC1)' + $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/cm.mak clean OBJ_DIR=$(OBJ_ROOT)/pnf_stub LIB_DIR=$(LIB_ROOT)/pnf_stub LOG_DIR=$(LOG_ROOT)/pnf_stub CC='$(CC1)' + $(Q)$(MAKE) -j -f $(COM_BUILD_DIR)/mt.mak clean OBJ_DIR=$(OBJ_ROOT)/pnf_stub LIB_DIR=$(LIB_ROOT)/pnf_stub LOG_DIR=$(LOG_ROOT)/pnf_stub CC='$(CC1)' + $(Q)rm -rf $(OBJ_ROOT)/pnf_stub/* + $(Q)rm -rf $(LIB_ROOT)/pnf_stub/* + $(Q)rm -rf $(BIN_DIR)/pnf_stub/* + $(Q)rm -rf $(ROOT_DIR)/bin/pnf_stub + $(Q)echo -e "***** PNF STUB CLEAN COMPLETE *****" + + +link_pnf: + $(Q)$(CC1) -g -o $(OBJ_ROOT)/pnf_stub/pnf_stub -Wl,-R../lib/:. $(OBJ_ROOT)/pnf_stub/*.o\ + $(L_OPTS) -L$(LIB_ROOT)/pnf_stub -L$(ROOT_DIR)/libs/pnf_stub + $(Q)cp -f ./obj/pnf_stub/pnf_stub ./bin/pnf_stub + $(Q)cp -rf ./bin/pnf_stub $(ROOT_DIR)/bin/ + $(Q)cp -f ../scripts/start_pnf_stub_logging.sh $(ROOT_DIR)/bin/pnf_stub + $(Q)echo -e "***** PNF STUB BUILD COMPLETE *****" copy_build: link_du $(Q)cp -f ./obj/odu/odu ./bin/odu @@ -335,6 +367,7 @@ copy_build: link_du odu: prepare_dirs copy_build cu_stub: prepare_cu_dirs cu link_cu ric_stub: prepare_ric_dirs ric link_ric +pnf_stub: prepare_pnf_dirs pnf link_pnf #********************************************************************** # End of file diff --git a/build/scripts/start_gnb.sh b/build/scripts/start_gnb.sh index 8c9a47c64..2c08a6c8a 100755 --- a/build/scripts/start_gnb.sh +++ b/build/scripts/start_gnb.sh @@ -30,6 +30,9 @@ make cu_stub NODE=TEST_STUB MACHINE=BIT64 MODE=FDD echo "" echo "***** Building RIC Stub Binary *****" make ric_stub NODE=TEST_STUB MACHINE=BIT64 MODE=FDD +echo "" +echo "***** Building PNF Stub Binary *****" +make pnf_stub NODE=TEST_STUB MACHINE=BIT64 MODE=FDD echo "" echo "***** Assigning IP addresses *****" @@ -38,11 +41,14 @@ INTERFACE="$(echo -e "${INTERFACE}" | tr -d '[:space:]')" ifconfig $INTERFACE:ODU "192.168.130.81" ifconfig $INTERFACE:CU_STUB "192.168.130.82" ifconfig $INTERFACE:RIC_STUB "192.168.130.80" +ifconfig $INTERFACE:PNF_STUB "192.168.130.79" xterm -hold -e "cd $ROOT_DIR/bin/cu_stub; chmod 777 *; ./start_cu_stub_logging.sh && ./cu_stub" & sleep 2 xterm -hold -e "cd $ROOT_DIR/bin/ric_stub; chmod 777 *; ./start_ric_stub_logging.sh && ./ric_stub" & sleep 2 +xterm -hold -e "cd $ROOT_DIR/bin/pnf_stub; chmod 777 *; ./start_pnf_stub_logging.sh && ./pnf_stub" & +sleep 2 xterm -hold -e "cd $ROOT_DIR/bin/odu; chmod 777 *; ./start_du_logging.sh && ./odu" & ################################################################################ diff --git a/build/scripts/start_pnf_stub_logging.sh b/build/scripts/start_pnf_stub_logging.sh new file mode 100755 index 000000000..6b11c2871 --- /dev/null +++ b/build/scripts/start_pnf_stub_logging.sh @@ -0,0 +1,35 @@ +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# 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. # +################################################################################ +# This script is used to log PNF stub +#!/bin/sh + +ROOT_DIR=$PWD +d=`date +%Y_%m_%d_%I_%M_%S` + +touch $ROOT_DIR/"log_pnf_stub_$d.txt" +chmod -c 777 $ROOT_DIR/"log_pnf_stub_$d.txt" +touch /etc/rsyslog.d/rsyslog_loginauth.conf +cp /dev/null /etc/rsyslog.d/rsyslog_loginauth.conf +echo "if \$programname == \"PNF_STUB\" then" >> \ +/etc/rsyslog.d/rsyslog_loginauth.conf +echo "$ROOT_DIR/../pnf_stub/log_pnf_stub_$d.txt" >> \ +/etc/rsyslog.d/rsyslog_loginauth.conf +systemctl restart rsyslog + + +#********************************************************************** +# End of file +#********************************************************************** diff --git a/src/5gnrmac/lwr_mac_ex_ms.c b/src/5gnrmac/lwr_mac_ex_ms.c index fe25953bc..efa92eac9 100644 --- a/src/5gnrmac/lwr_mac_ex_ms.c +++ b/src/5gnrmac/lwr_mac_ex_ms.c @@ -29,6 +29,9 @@ #ifndef INTEL_WLS_MEM #include "lwr_mac_phy_stub_inf.h" #endif +#ifdef NFAPI_ENABLED +#include "lwr_mac_sctp_inf.h" +#endif /************************************************************************** * @brief Task Initiation callback function. @@ -126,6 +129,26 @@ void callFlowlwrMacActvTsk(Pst *pst) break; } #endif + case ENTSCTP: + { + strcpy(sourceTask,"SCTP"); + switch(pst->event) + { +#ifdef NFAPI_ENABLED + case EVENT_PNF_DATA: + { + strcpy(message,"EVENT_PNF_DATA"); + break; + } +#endif + default: + { + strcpy(message,"Invalid Event"); + break; + } + } + break; + } default: { @@ -229,7 +252,24 @@ uint8_t lwrMacActvTsk(Pst *pst, Buffer *mBuf) break; } #endif - + case ENTSCTP: + { + switch(pst->event) + { +#ifdef NFAPI_ENABLED + case EVENT_PNF_DATA: + { + + break; + } +#endif + default: + { + DU_LOG("\nERROR --> LWR_MAC: Invalid event %d received from SCTP", pst->event); + } + } + break; + } default: { ODU_PUT_MSG_BUF(mBuf); diff --git a/src/5gnrmac/lwr_mac_nfapi.h b/src/5gnrmac/lwr_mac_nfapi.h index 995f823ac..e73a04def 100644 --- a/src/5gnrmac/lwr_mac_nfapi.h +++ b/src/5gnrmac/lwr_mac_nfapi.h @@ -16,8 +16,8 @@ ################################################################################ *******************************************************************************/ - #ifndef _LWR_MAC_NFAPI_H_ - #define _LWR_MAC_NFAPI_H_ +#ifndef _LWR_MAC_NFAPI_H_ +#define _LWR_MAC_NFAPI_H_ #include "nfapi_interface.h" diff --git a/src/cm/lwr_mac_sctp_inf.h b/src/cm/lwr_mac_sctp_inf.h new file mode 100644 index 000000000..c7d2cd16f --- /dev/null +++ b/src/cm/lwr_mac_sctp_inf.h @@ -0,0 +1,24 @@ + +/******************************************************************************* +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# 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. # +################################################################################ +*******************************************************************************/ + +#define EVENT_PNF_DATA 11 + +/********************************************************************** + End of file +***********************************************************************/ diff --git a/src/du_app/du_cfg.c b/src/du_app/du_cfg.c index b5d63451f..cb65690e4 100644 --- a/src/du_app/du_cfg.c +++ b/src/du_app/du_cfg.c @@ -206,6 +206,9 @@ uint8_t parseSctpParams(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SctpParams * uint8_t max_du_port = 0; uint16_t f1_sctp_port = 0; uint16_t e2_sctp_port = 0; +#ifdef NFAPI_ENABLED + uint16_t pnf_p5_sctp_port = 0; +#endif memset(sctp, 0, sizeof(SctpParams)); cur = cur->xmlChildrenNode; @@ -220,7 +223,7 @@ uint8_t parseSctpParams(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SctpParams * if ((!xmlStrcmp(cur->name, (const xmlChar *)"MAX_DU_PORT")) && (cur->ns == ns)) { max_du_port = atoi((char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); - if (max_du_port == 2 ) + if (max_du_port >= 2 ) { sctp->duPort[F1_INTERFACE] = f1_sctp_port; /* DU Port idx 0 */ sctp->duPort[E2_INTERFACE] = e2_sctp_port; /* RIC Port idx 1 */ @@ -238,6 +241,20 @@ uint8_t parseSctpParams(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SctpParams * sctp->cuPort = f1_sctp_port; sctp->ricPort = e2_sctp_port; +#endif +#ifdef NFAPI_ENABLED + /*TODO: Need to add PNF_PF Interface's SCTP confg in O1 Module then can be + * moved inside O1_ENABLE flag*/ + if(max_du_port == 3) + { + sctp->duPort[PNF_P5_INTERFACE] = pnf_p5_sctp_port; + } + + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PNF_P5_SCTP_PORT")) && (cur->ns == ns)) + { + pnf_p5_sctp_port = atoi((char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + } + sctp->pnfP5Port = pnf_p5_sctp_port; #endif cur = cur->next; } @@ -5163,6 +5180,10 @@ uint8_t parseDuCfgParams(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) char *duIpV4Addr; char *cuIpV4Addr; char *ricIpV4Addr; +#ifdef NFAPI_ENABLED + char *pnfP5IpV4Addr; + CmInetIpAddr pnfP5Ip; +#endif CmInetIpAddr duIp; CmInetIpAddr cuIp; CmInetIpAddr ricIp; @@ -5237,7 +5258,13 @@ uint8_t parseDuCfgParams(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) cmInetAddr(ricIpV4Addr, &(ricIp)); } #endif - +#ifdef NFAPI_ENABLED + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PNF_P5_IP_V4_ADDR")) && (cur->ns == ns)) + { + pnfP5IpV4Addr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + cmInetAddr(pnfP5IpV4Addr, &(pnfP5Ip)); + } +#endif if ((!xmlStrcmp(cur->name, (const xmlChar *)"SCTP")) && (cur->ns == ns)) { if(parseSctpParams(doc, ns, cur, &duCfgParam.sctpParams) != ROK) @@ -5251,6 +5278,10 @@ uint8_t parseDuCfgParams(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) duCfgParam.sctpParams.cuIpAddr.ipV4Addr = cuIp; duCfgParam.sctpParams.ricIpAddr.ipV4Pres = true; duCfgParam.sctpParams.ricIpAddr.ipV4Addr = ricIp; +#ifdef NFAPI_ENABLED + duCfgParam.sctpParams.pnfP5IpAddr.ipV4Pres = true; + duCfgParam.sctpParams.pnfP5IpAddr.ipV4Addr = pnfP5Ip; +#endif } if ((!xmlStrcmp(cur->name, (const xmlChar *)"EGTP")) && (cur->ns == ns)) @@ -5556,10 +5587,18 @@ void printDuConfig() DU_LOG("CU IP Address %u\n", sctp->cuIpAddr.ipV4Addr); DU_LOG("RIC IPv4 Address present %u\n", sctp->ricIpAddr.ipV4Pres); DU_LOG("RIC IP Address %u\n", sctp->ricIpAddr.ipV4Addr); +#ifdef NFAPI_ENABLED + DU_LOG("PNF P5 IPv4 Address present %u\n", sctp->pnfP5IpAddr.ipV4Pres); + DU_LOG("PNF P5 IP Address %u\n", sctp->pnfP5IpAddr.ipV4Addr); +#endif DU_LOG("SCTP Port at DU for F1 Interface %d\n", sctp->duPort[F1_INTERFACE]); DU_LOG("SCTP Port at CU for F1 Interface %d\n", sctp->cuPort); DU_LOG("SCTP Port at DU for E2 Interface %d\n", sctp->duPort[E2_INTERFACE]); DU_LOG("SCTP Port at RIC for E2 Interface %d\n", sctp->ricPort); +#ifdef NFAPI_ENABLED + DU_LOG("SCTP Port at DU for PNF P5 Interface %d\n", sctp->duPort[PNF_P5_INTERFACE]); + DU_LOG("SCTP Port at PNF for PNF P5 Interface %d\n", sctp->pnfP5Port); +#endif egtp = &duCfgParam.egtpParams; DU_LOG("\n ** EGTP PARAMETER ** \n"); diff --git a/src/du_app/du_cfg.h b/src/du_app/du_cfg.h index b37325300..2cd3cc2c1 100644 --- a/src/du_app/du_cfg.h +++ b/src/du_app/du_cfg.h @@ -101,10 +101,14 @@ #define DU_PROC 0 #define DU_INST 0 #define DU_POOL 1 -#define MAX_DU_PORT 2 +#define MAX_DU_PORT 3 #define F1_INTERFACE 0 #define E2_INTERFACE 1 +#ifdef NFAPI_ENABLED +#define PNF_P5_INTERFACE 2 +#endif + #define SCTP_INST 0 #define EGTP_INST 0 @@ -924,11 +928,15 @@ typedef struct f1Ipaddr typedef struct sctpParams { F1IpAddr duIpAddr; - uint16_t duPort[MAX_DU_PORT]; + uint16_t duPort[MAX_DU_PORT]; F1IpAddr cuIpAddr; - uint16_t cuPort; + uint16_t cuPort; F1IpAddr ricIpAddr; - uint16_t ricPort; + uint16_t ricPort; +#ifdef NFAPI_ENABLED + F1IpAddr pnfP5IpAddr; + uint16_t pnfP5Port; +#endif }SctpParams; typedef struct f1EgtpParams diff --git a/src/du_app/du_msg_hdl.c b/src/du_app/du_msg_hdl.c index 5a179322a..b2ab02818 100644 --- a/src/du_app/du_msg_hdl.c +++ b/src/du_app/du_msg_hdl.c @@ -1398,7 +1398,13 @@ uint8_t duLayerConfigComplete() DU_LOG("\nERROR --> DU_APP : Failed to send AssocReq E2"); ret = RFAILED; } - +#ifdef NFAPI_ENABLED + if((ret = duSctpAssocReq(PNF_P5_INTERFACE)) != ROK) + { + DU_LOG("\nERROR --> DU_APP : Failed to send AssocReq PNF P5"); + ret = RFAILED; + } +#endif return (ret); } diff --git a/src/du_app/du_sctp.c b/src/du_app/du_sctp.c index fbb28e14c..342b1fd31 100644 --- a/src/du_app/du_sctp.c +++ b/src/du_app/du_sctp.c @@ -33,6 +33,8 @@ #include "du_app_rlc_inf.h" #include "du_mgr.h" #include "du_utils.h" +#include "lwr_mac_sctp_inf.h" + /* Global variable declaration */ uint8_t socket_type; /* Socket type */ bool nonblocking; /* Blocking/Non-blocking socket */ @@ -43,6 +45,9 @@ CmInetNetAddrLst remoteAddrLst; /* Global variable declaration */ DuSctpDestCb f1Params; /* SCTP configurations at DU */ DuSctpDestCb ricParams; /* SCTP configurations at DU */ +#ifdef NFAPI_ENABLED +DuSctpDestCb pnfP5Params; /* SCTP configurations for PNF */ +#endif /************************************************************************** * @brief Task Initiation callback function. @@ -74,6 +79,10 @@ uint8_t sctpActvInit(Ent entity, Inst inst, Region region, Reason reason) f1Params.assocId = -1; memset(&ricParams, 0, sizeof(DuSctpDestCb)); ricParams.assocId = -1; +#ifdef NFAPI_ENABLED + memset(&pnfP5Params, 0, sizeof(DuSctpDestCb)); + pnfP5Params.assocId = -1; +#endif nonblocking = FALSE; return ROK; @@ -236,6 +245,18 @@ uint8_t duSctpCfgReq(SctpParams sctpCfg) fillDestNetAddr(&ricParams.destIpNetAddr, &ricParams.destIpAddr); fillAddrLst(&ricParams.destAddrLst, &ricParams.destIpAddr); +#ifdef NFAPI_ENABLED +/* Fill PNF Params */ + pnfP5Params.destIpAddr.ipV4Pres = sctpCfg.pnfP5IpAddr.ipV4Pres; + pnfP5Params.destIpAddr.ipV4Addr = sctpCfg.pnfP5IpAddr.ipV4Addr; + pnfP5Params.destPort = sctpCfg.pnfP5Port; + pnfP5Params.itfState = DU_SCTP_DOWN; + pnfP5Params.srcPort = sctpCfg.duPort[PNF_P5_INTERFACE]; + memset (&pnfP5Params.sockFd, -1, sizeof(CmInetFd)); + fillDestNetAddr(&pnfP5Params.destIpNetAddr, &pnfP5Params.destIpAddr); + fillAddrLst(&pnfP5Params.destAddrLst, &pnfP5Params.destIpAddr); +#endif + /* Fill AddressList */ fillAddrLst(&localAddrLst, &sctpCfg.duIpAddr); @@ -422,6 +443,14 @@ uint8_t duSctpAssocReq(uint8_t itfType) ret = establishReq(paramPtr); break; } +#ifdef NFAPI_ENABLED + case PNF_P5_INTERFACE: + { + paramPtr = &pnfP5Params; + ret = establishReq(paramPtr); + break; + } +#endif default: { DU_LOG("\nERROR --> SCTP : Invalid Interface Type %d", itfType); @@ -559,9 +588,55 @@ void sendToDuApp(Buffer *mBuf, Event event) if (ODU_POST_TASK(&pst, mBuf) != ROK) { - DU_LOG("\nERROR --> SCTP : ODU_POST_TASK failed in duReadCfg"); + DU_LOG("\nERROR --> SCTP : ODU_POST_TASK failed in sendToDuApp"); + } +} + +#ifdef NFAPI_ENABLED +/******************************************************************* + * + * @brief Post received data/notification to LWR_MAC + * + * @details + * + * Function : sendToLwrMac + * + * Functionality: + * Post received data/notification to LWR_MAC + * + * @params[in] Message buffer + * Message event + * + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +void sendToLwrMac(Buffer *mBuf, Event event) +{ + Pst pst; + DU_LOG("\nDEBUG --> SCTP : Forwarding received message to Lwr MAC"); + ODU_PRINT_MSG(mBuf, 0, 0); + + ODU_GET_MSG_BUF(pst.region, pst.pool, &mBuf); + + memset(&(pst), 0, sizeof(Pst)); + pst.srcEnt = (Ent)ENTSCTP; + pst.srcInst = (Inst)SCTP_INST; + pst.srcProcId = DU_PROC; + pst.dstEnt = (Ent)ENTLWRMAC; + pst.dstInst = 0; + pst.dstProcId = pst.srcProcId; + pst.event = event; + pst.selector = ODU_SELECTOR_LWLC; + pst.pool= DU_POOL; + pst.region = DFLT_REGION; + + if (ODU_POST_TASK(&pst, mBuf) != ROK) + { + DU_LOG("\nERROR --> SCTP : ODU_POST_TASK failed in sendToLwrMac"); } } +#endif /******************************************************************* * @@ -651,25 +726,36 @@ uint8_t sctpNtfyHdlr(CmInetSctpNotification *ntfy, uint8_t *itfState, uint8_t in break; } - /* Pack notification and send to APP */ - DU_LOG("\nDEBUG --> SCTP : Forwarding received message to duApp"); - - memset(&(pst), 0, sizeof(Pst)); - pst.srcEnt = (Ent)ENTSCTP; - pst.srcInst = (Inst)SCTP_INST; - pst.srcProcId = DU_PROC; - pst.dstEnt = (Ent)ENTDUAPP; - pst.dstInst = (Inst)DU_INST; - pst.dstProcId = pst.srcProcId; - pst.event = EVENT_SCTP_NTFY; - pst.selector = ODU_SELECTOR_LC; - pst.pool= DU_POOL; - pst.region = DU_APP_MEM_REGION; - - if(cmPkSctpNtfy(&pst, ntfy) != ROK) +#ifdef NFAPI_ENABLED + if(interface == PNF_P5_INTERFACE) { - DU_LOG("\nERROR --> SCTP : Failed to pack SCTP notification"); - return RFAILED; + /*TODO: Need to check if SCTP Notification for this interface has to be handled*/ + DU_LOG("\nDEBUG --> SCTP : SCTP Notification received for PNF_P5 Interface"); + return ROK; + } + else +#endif + { + /* Pack notification and send to APP */ + DU_LOG("\nDEBUG --> SCTP : Forwarding received message to duApp"); + + memset(&(pst), 0, sizeof(Pst)); + pst.srcEnt = (Ent)ENTSCTP; + pst.srcInst = (Inst)SCTP_INST; + pst.srcProcId = DU_PROC; + pst.dstEnt = (Ent)ENTDUAPP; + pst.dstInst = (Inst)DU_INST; + pst.dstProcId = pst.srcProcId; + pst.event = EVENT_SCTP_NTFY; + pst.selector = ODU_SELECTOR_LC; + pst.pool= DU_POOL; + pst.region = DU_APP_MEM_REGION; + + if(cmPkSctpNtfy(&pst, ntfy) != ROK) + { + DU_LOG("\nERROR --> SCTP : Failed to pack SCTP notification"); + return RFAILED; + } } return ROK; } @@ -710,7 +796,6 @@ uint8_t processPolling(sctpSockPollParams *pollParams, CmInetFd *sockFd, uint32 if(ret != ROK) { DU_LOG("\nERROR --> SCTP: Failed to receive sctp msg for sockFd[%d]\n", sockFd->fd); - ret = RFAILED; } else { @@ -734,6 +819,14 @@ uint8_t processPolling(sctpSockPollParams *pollParams, CmInetFd *sockFd, uint32 DU_LOG("\nDEBUG --> SCTP : AssocId assigned to ricParams from PollParams [%d]\n", ricParams.assocId); ret = sctpNtfyHdlr(&pollParams->ntfy, &ricParams.itfState, E2_INTERFACE); } +#ifdef NFAPI_ENABLED + else if(pollParams->port == pnfP5Params.destPort) + { + pnfP5Params.assocId = pollParams->ntfy.u.assocChange.assocId; + DU_LOG("\nDEBUG --> SCTP : AssocId assigned to PNF_P5 Params from PollParams [%d]\n", pnfP5Params.assocId); + ret = sctpNtfyHdlr(&pollParams->ntfy, &pnfP5Params.itfState, PNF_P5_INTERFACE); + } +#endif else { DU_LOG("\nERROR --> SCTP : Failed to fill AssocId\n"); @@ -752,14 +845,19 @@ uint8_t processPolling(sctpSockPollParams *pollParams, CmInetFd *sockFd, uint32 { sendToDuApp(pollParams->mBuf, EVENT_RIC_DATA); } - +#ifdef NFAPI_ENABLED + else if(pnfP5Params.itfState & (pollParams->port == pnfP5Params.destPort)) + { + sendToLwrMac(pollParams->mBuf, EVENT_PNF_DATA); + } +#endif else { ODU_PUT_MSG_BUF(pollParams->mBuf); } } } - return ret; + return ROK; } /******************************************************************* * @@ -784,14 +882,25 @@ uint8_t sctpSockPoll() uint32_t *timeout_Ptr; CmInetMemInfo memInfo; sctpSockPollParams f1PollParams, e2PollParams; +#ifdef NFAPI_ENABLED + sctpSockPollParams pnfP5PollParams; +#endif memset(&f1PollParams, 0, sizeof(sctpSockPollParams)); memset(&e2PollParams, 0, sizeof(sctpSockPollParams)); +#ifdef NFAPI_ENABLED + memset(&pnfP5PollParams, 0, sizeof(sctpSockPollParams)); +#endif if (f1Params.sockFd.blocking & ricParams.sockFd.blocking) { - /* blocking */ - timeout_Ptr = NULLP; +#ifdef NFAPI_ENABLED + if(pnfP5Params.sockFd.blocking) +#endif + { + /* blocking */ + timeout_Ptr = NULLP; + } } else { @@ -804,6 +913,9 @@ uint8_t sctpSockPoll() CM_INET_FD_ZERO(&f1PollParams.readFd); CM_INET_FD_ZERO(&e2PollParams.readFd); +#ifdef NFAPI_ENABLED + CM_INET_FD_ZERO(&pnfP5PollParams.readFd); +#endif DU_LOG("\nINFO --> SCTP : Polling started at DU\n"); while(true) @@ -822,6 +934,15 @@ uint8_t sctpSockPoll() DU_LOG("\nERROR --> SCTP : Failed to RecvMsg for E2\n"); } } +#ifdef NFAPI_ENABLED + if(pnfP5Params.itfState) + { + if((ret = processPolling(&pnfP5PollParams, &pnfP5Params.sockFd, timeout_Ptr, &memInfo)) != ROK) + { + DU_LOG("\nERROR --> SCTP : Failed to RecvMsg for E2\n"); + } + } +#endif }; return (ret); }/* End of sctpSockPoll() */ @@ -879,7 +1000,16 @@ uint8_t sctpSend(Buffer *mBuf, uint8_t itfType) #endif ret = cmInetSctpSendMsg(&ricParams.sockFd, &ricParams.destIpNetAddr, ricParams.destPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK); } - +#ifdef NFAPI_ENABLED + if(itfType == PNF_P5_INTERFACE) + { + DU_LOG("\nDEBUG --> SCTP : sending the message to PNF"); +#ifdef CALL_FLOW_DEBUG_LOG + DU_LOG("\nCall Flow: ENTSCTP -> PNF : EVENT_P5_MSG_TO_PNF\n"); +#endif + ret = cmInetSctpSendMsg(&pnfP5Params.sockFd, &pnfP5Params.destIpNetAddr, pnfP5Params.destPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK); + } +#endif if(ret != ROK && ret != RWOULDBLOCK) { DU_LOG("\nERROR --> SCTP : Failed sending the message"); diff --git a/src/intel_fapi/nfapi_interface.h b/src/intel_fapi/nfapi_interface.h index d29c9ef0c..28592269c 100644 --- a/src/intel_fapi/nfapi_interface.h +++ b/src/intel_fapi/nfapi_interface.h @@ -25,58 +25,58 @@ /*Table 2-7 Dedicated NFAPI message IDs*/ /*P5 Messages*/ -#define NFAPI_PNF_PARAM_REQ 0x0100 -#define NFAPI_PNF_PARAM_RESP 0x0101 -#define NFAPI_PNF_CONFIG_REQ 0x0102 -#define NFAPI_PNF_CONFIG_RESP 0x0103 -#define NFAPI_PNF_START_REQ 0x0104 -#define NFAPI_PNF_START_RESP 0x0105 -#define NFAPI_PNF_STOP_REQ 0x0106 -#define NFAPI_PNF_STOP_RESP 0x0107 -#define NFAPI_START_RESPONSE 0x0108 -#define NFAPI_PNF_READY_IND 0x0109 - -/*Reserved for P5 Dedicated NFAPI Messages 0x010A - 0x017F */ +#define TAG_NFAPI_PNF_PARAM_REQ 0x0100 +#define TAG_NFAPI_PNF_PARAM_RESP 0x0101 +#define TAG_NFAPI_PNF_CONFIG_REQ 0x0102 +#define TAG_NFAPI_PNF_CONFIG_RESP 0x0103 +#define TAG_NFAPI_PNF_START_REQ 0x0104 +#define TAG_NFAPI_PNF_START_RESP 0x0105 +#define TAG_NFAPI_PNF_STOP_REQ 0x0106 +#define TAG_NFAPI_PNF_STOP_RESP 0x0107 +#define TAG_NFAPI_START_RESPONSE 0x0108 +#define TAG_NFAPI_PNF_READY_IND 0x0109 + +/*Reserved for P5 Dedicated TAG_NFAPI Messages 0x010A - 0x017F */ /*P7 messages*/ -#define NFAPI_DL_NODE_SYNC 0x0180 -#define NFAPI_UL_NODE_SYNC 0x0181 -#define NFAPI_TIMING_INFO 0x0182 +#define TAG_NFAPI_DL_NODE_SYNC 0x0180 +#define TAG_NFAPI_UL_NODE_SYNC 0x0181 +#define TAG_NFAPI_TIMING_INFO 0x0182 -/*Reserved for P7 Dedicated NFAPI Messages 0x0183 - 0x01ff*/ +/*Reserved for P7 Dedicated TAG_NFAPI Messages 0x0183 - 0x01ff*/ /*RESERVED for Vendor Extension messages 0x0300 - 0x03ff*/ /*Table 3-16 nFAPI TLVs included in PARAM.response and *Table 3-19 nFAPI TLVs included in CONFIG.request*/ //PNF and VNF Parameters -#define NFAPI_P7_VNF_ADD_IPV4 0x0100 -#define NFAPI_P7_VNF_ADD_IPV6 0x0101 -#define NFAPI_P7_VNF_PORT 0x0102 -#define NFAPI_P7_PNF_ADD_IPV4 0x0103 -#define NFAPI_P7_PNF_ADD_IPV6 0x0104 -#define NFAPI_P7_PNF_PORT 0x0105 +#define TAG_NFAPI_P7_VNF_ADD_IPV4 0x0100 +#define TAG_NFAPI_P7_VNF_ADD_IPV6 0x0101 +#define TAG_NFAPI_P7_VNF_PORT 0x0102 +#define TAG_NFAPI_P7_PNF_ADD_IPV4 0x0103 +#define TAG_NFAPI_P7_PNF_ADD_IPV6 0x0104 +#define TAG_NFAPI_P7_PNF_PORT 0x0105 //TTI Related Parameters -#define NFAPI_DL_TTI_TIMING_OFFSET 0x0106 -#define NFAPI_UL_TTI_TIMING_OFFSET 0x0107 -#define NFAPI_UL_DCI_TIMING_OFFSET 0x0108 -#define NFAPI_TX_DATA_TIMING_OFFSET 0x0109 +#define TAG_NFAPI_DL_TTI_TIMING_OFFSET 0x0106 +#define TAG_NFAPI_UL_TTI_TIMING_OFFSET 0x0107 +#define TAG_NFAPI_UL_DCI_TIMING_OFFSET 0x0108 +#define TAG_NFAPI_TX_DATA_TIMING_OFFSET 0x0109 //Timing Related Parameters -#define NFAPI_TIMING_WINDOW 0x011E -#define NFAPI_TIMING_INFO_MODE 0x011F -#define NFAPI_TIMING_INFO_PERIOD 0x0120 +#define TAG_NFAPI_TIMING_WINDOW 0x011E +#define TAG_NFAPI_TIMING_INFO_MODE 0x011F +#define TAG_NFAPI_TIMING_INFO_PERIOD 0x0120 //P7 Transport Related Parameters -#define NFAPI_P7_IP_FRAGMENTATION_ALLOWED 0x0121 -#define NFAPI_P7_TRANSPORT 0x0122 -#define NFAPI_P7_PNF_ETHERNET_ADD 0x0123 -#define NFAPI_P7_VNF_ETHERNET_ADD 0x0124 +#define TAG_NFAPI_P7_IP_FRAGMENTATION_ALLOWED 0x0121 +#define TAG_NFAPI_P7_TRANSPORT 0x0122 +#define TAG_NFAPI_P7_PNF_ETHERNET_ADD 0x0123 +#define TAG_NFAPI_P7_VNF_ETHERNET_ADD 0x0124 //CPRI Related Parameters -#define NFAPI_ECPRI_MSG_TYPE 0x0125 -#define NFAPI_ECPRI_PHY_TRANSPORT_ID 0x0126 +#define TAG_NFAPI_ECPRI_MSG_TYPE 0x0125 +#define TAG_NFAPI_ECPRI_PHY_TRANSPORT_ID 0x0126 -#define NFAPI_5G_FAPI_MSG_BODY 0x0F00 +#define TAG_NFAPI_5G_FAPI_MSG_BODY 0x0F00 /*Table 3-2*/ -#define NFAPI_PNF_PARAM_GENERAL 0x1000 +#define TAG_NFAPI_PNF_PARAM_GENERAL 0x1000 /*As per Table 3-15 and Table 3-17*/ #define MAX_NUM_TLV_IN_PARAM_RESP 19 diff --git a/src/pnf_stub/pnf_stub.c b/src/pnf_stub/pnf_stub.c new file mode 100644 index 000000000..fc0021d1e --- /dev/null +++ b/src/pnf_stub/pnf_stub.c @@ -0,0 +1,163 @@ +/******************************************************************************* + * ################################################################################ + * # Copyright (c) [2017-2019] [Radisys] + * # + * # + * # + * # 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. + * # + * ################################################################################ + * *******************************************************************************/ + +/* This functions contains main() for pnf simulator */ +#include "common_def.h" +#include +#include "pnf_stub_sctp.h" +#include "pnf_stub.h" + +PnfGlobalCb pnfCb; + +void init_log() +{ + openlog("RIC_STUB",LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); +} + +/******************************************************************* + * + * @brief Read PNF related configuration + * + * @details + * + * Function : readPnfCfg + * + * Functionality: + * - RRead PNF related configuration + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ + +void readPnfCfg() +{ + uint8_t cntNumVnf = 0; + uint32_t ipv4_vnf = 0, ipv4_pnf = 0; + + DU_LOG("\nDEBUG --> PNF_STUB : Reading PNF P5 configurations"); + + pnfCb.pnfCfgParams.pnfId = PNF_ID; + strcpy(pnfCb.pnfCfgParams.pnfName, PNF_NAME); + + /* PNF IP Address and Port*/ + memset(&ipv4_pnf, 0, sizeof(uint32_t)); + cmInetAddr((S8*)LOCAL_IP_PNF, &ipv4_pnf); + + /*PNF SCTP Configuration at PNF P5 Interface*/ + pnfCb.pnfCfgParams.pnfP5SctpParams.pnfP5localIpAddr.ipV4Pres = true; + pnfCb.pnfCfgParams.pnfP5SctpParams.pnfP5localIpAddr.ipV4Addr = ipv4_pnf; + pnfCb.pnfCfgParams.pnfP5SctpParams.pnfP5localIpAddr.ipV6Pres = false; + pnfCb.pnfCfgParams.pnfP5SctpParams.pnfP5SctpPort = PNF_P5_SCTP_PORT; + + cntNumVnf = 0; + while(cntNumVnf < NUM_PNF_P5_ASSOC) + { + /* VNF IP Address */ + memset(&ipv4_vnf, 0, sizeof(uint32_t)); + cmInetAddr((S8*)REMOTE_IP_DU[cntNumVnf], &ipv4_vnf); + + /* VNF SCTP Parameters */ + pnfCb.pnfCfgParams.pnfP5SctpParams.destCb[cntNumVnf].destIpAddr.ipV4Addr = ipv4_vnf; + pnfCb.pnfCfgParams.pnfP5SctpParams.destCb[cntNumVnf].destIpAddr.ipV6Pres = false; + pnfCb.pnfCfgParams.pnfP5SctpParams.destCb[cntNumVnf].destPort = PNF_P5_SCTP_PORT; + + + (cntNumVnf)++; + } + + pnfCb.pnfCfgParams.pnfP5SctpParams.numDestNode = cntNumVnf; + +} /* End of readPnfCfg */ + + +/******************************************************************* + * + * @brief Main function of PNF SIMULATOR + * + * @details + * + * Function : main + * + * Functionality: + * - Initialize SCTP Parameters + * - Start SCTP receiver thread + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ + +uint8_t tst() +{ +#if 0 + int retVal=0; + pthread_t conThrdId; + pthread_attr_t attr; +#endif + + init_log(); + DU_LOG("\nINFO --> PNF_STUB : Starting PNF_STUB\n"); + + /* TODO: Start thread to receive console input */ +#if 0 + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, (size_t)NULLD); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + retVal = pthread_create(&conThrdId, &attr, vnfConsoleHandler, NULLP); + if(retVal != 0) + { + DU_LOG("\nERROR --> PNF_STUB : Thread creation failed. Cause %d", retVal); + } + pthread_attr_destroy(&attr); +#endif + /* Read PNF configurations */ + readPnfCfg(); + + /* Initializing SCTP global parameters */ + pnfP5SctpActvInit(); + + /* Start PNF-P5-SCTP to listen on incoming connection */ + pnfP5SctpCfgReq(); + + /*Sleep is introduced for GDB to increase the waiting time for PNF Configuration from VNF*/ + sleep(1); + + pnfP5SctpStartReq(); + + return ROK; +} + + + diff --git a/src/pnf_stub/pnf_stub.h b/src/pnf_stub/pnf_stub.h new file mode 100644 index 000000000..2b4acceb1 --- /dev/null +++ b/src/pnf_stub/pnf_stub.h @@ -0,0 +1,51 @@ +/******************************************************************************* +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# 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 __PNF_MAIN_H +#define __PNF_MAIN_H + +#define PNF_NAME_LEN_MAX 30 +#define PNF_ID 1 +#define PNF_NAME "ORAN_OAM_PNF" + +#define LOCAL_IP_PNF "192.168.130.79" + +#define PNF_P5_SCTP_PORT 7701 +#define NUM_PNF_P5_ASSOC 1 +#define REMOTE_IP_DU (char*[]){"192.168.130.81", "192.168.130.83"} + +#define PNF_APP_MEM_REG 1 +#define PNF_POOL 1 + +typedef struct pnfCfgParams +{ + uint32_t pnfId; + char pnfName[PNF_NAME_LEN_MAX]; + PnfP5SctpParams pnfP5SctpParams; +}PnfCfgParams; + +typedef struct pnfGlobalCb +{ + PnfCfgParams pnfCfgParams; + uint8_t numDu; + //DuDb duInfo[MAX_DU_SUPPORTED]; /*TODO: VNF Database can be added*/ +}PnfGlobalCb; + +extern PnfGlobalCb pnfCb; + +#endif diff --git a/src/pnf_stub/pnf_stub_sctp.c b/src/pnf_stub/pnf_stub_sctp.c new file mode 100644 index 000000000..e4b12e14e --- /dev/null +++ b/src/pnf_stub/pnf_stub_sctp.c @@ -0,0 +1,534 @@ +/******************************************************************************* +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# 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. # +################################################################################ +*******************************************************************************/ + +/* This file contains all SCTP related functionality */ + +#include "common_def.h" +#include "pnf_stub_sctp.h" +#include "pnf_stub.h" + +uint8_t socket_type; /* Socket type */ +PnfP5SctpGlobalCb pnfP5SctpCb; + +/************************************************************************** + * @brief Task Initiation callback function. + * + * @details + * + * Function : pnfP5SctpActvInit + * + * Functionality: + * This function is supplied as one of parameters during SCTP's + * task registration. SSI will invoke this function once, after + * it creates and attaches this TAPA Task to a system task. + * + * @param[in] Ent entity, the entity ID of this task. + * @param[in] Inst inst, the instance ID of this task. + * @param[in] Region region, the region ID registered for memory + * usage of this task. + * @param[in] Reason reason. + * @return ROK - success + * RFAILED - failure + ***************************************************************************/ +uint8_t pnfP5SctpActvInit() +{ + DU_LOG("\n\nDEBUG --> SCTP : Initializing"); + memset(&pnfP5SctpCb, 0, sizeof(PnfP5SctpGlobalCb)); + pnfP5SctpCb.pnfP5SctpCfg = pnfCb.pnfCfgParams.pnfP5SctpParams; + return ROK; +} + +/******************************************************************* + * + * @brief Fills the address List of the source Ip Address + * + * @details + * + * Function : fillAddrLst + * + * Functionality: + * Fills the address List of source Ip Address + * + * @params[in] CmInetNetAddrLst *addrLstPtr, Address List pointer + * @params[in] F1IpAddr *srcIpAddr, src Ip Adrress to be filled in the Address List + * @return ROK - success + * RFAILED - failure + * + ******************************************************************/ + +uint8_t fillAddrLst(CmInetNetAddrLst *addrLstPtr, PnfP5SctpIpAddr *ipAddr) +{ + addrLstPtr->addrs[addrLstPtr->count].type = CM_INET_IPV4ADDR_TYPE; + addrLstPtr->addrs[addrLstPtr->count].u.ipv4NetAddr = CM_INET_NTOH_UINT32(ipAddr->ipV4Addr); + addrLstPtr->count++; + + return ROK; +} + +/****************************************************************************** + * + * @brief Fills the address List of the source Ip Address + * + * @details + * + * Function : fillDestNetAddr + * + * Functionality: + * Fills the address List of destinatoion Ip Address + * + * @params[in] CmInetNetAddr *destAddrPtr, Address List pointer + * @params[in] F1IpAddr *dstIpAddr, destIp Address to be filled in the Address List + * @return ROK - success + * RFAILED - failure + * + *******************************************************************************/ +uint8_t fillDestNetAddr(CmInetNetAddr *destAddrPtr, PnfP5SctpIpAddr *dstIpPtr) +{ + /* Filling destination address */ + destAddrPtr->type = CM_INET_IPV4ADDR_TYPE; + destAddrPtr->u.ipv4NetAddr = CM_INET_NTOH_UINT32(dstIpPtr->ipV4Addr); + return ROK; +} + +/************************************************************************** + * @brief Function to configure the Sctp Params during config Request + * + * @details + * + * Function : pnfP5SctpCfgReq + * + * Functionality: + * This function configures SCTP Params during the config Request + * + * @return ROK - success + * RFAILED - failure + * + ***************************************************************************/ + +uint8_t pnfP5SctpCfgReq() +{ + int destIdx = 0, assocIdx = 0; + + fillAddrLst(&pnfP5SctpCb.localAddrLst, &pnfP5SctpCb.pnfP5SctpCfg.pnfP5localIpAddr); + memset(&pnfP5SctpCb.pnfP5LstnSockFd, -1, sizeof(CmInetFd)); + for(destIdx=0; destIdx < pnfP5SctpCb.pnfP5SctpCfg.numDestNode; destIdx++) + { + pnfP5SctpCb.assocCb[assocIdx].destPort = pnfP5SctpCb.pnfP5SctpCfg.destCb[destIdx].destPort; + memset(&pnfP5SctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd)); + fillDestNetAddr(&pnfP5SctpCb.assocCb[assocIdx].destIpNetAddr, &pnfP5SctpCb.pnfP5SctpCfg.destCb[destIdx].destIpAddr); + pnfP5SctpCb.assocCb[assocIdx].connUp = false; + assocIdx++; + } + pnfP5SctpCb.numAssoc = assocIdx; + return ROK; +} + +/****************************************************************************** + * + * @brief Eastablishes the Assoc Req for the received interface type + * + * @details + * + * Function : pnfP5SctpStartReq + * + * Functionality: + * Eastablishes the Socket Connection + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + *******************************************************************************/ + +uint8_t pnfP5SctpStartReq() +{ + uint8_t assocIdx = 0; + uint8_t ret = ROK; + + socket_type = CM_INET_STREAM; + + if(pnfP5SctpCb.numAssoc) + { + + if((ret = cmInetSocket(socket_type, &pnfP5SctpCb.pnfP5LstnSockFd, IPPROTO_SCTP) != ROK)) + { + DU_LOG("\nERROR --> SCTP : Socket[%d] coudnt open for listening", pnfP5SctpCb.pnfP5LstnSockFd.fd); + } + else if((ret = cmInetSctpBindx(&pnfP5SctpCb.pnfP5LstnSockFd, &pnfP5SctpCb.localAddrLst, pnfP5SctpCb.pnfP5SctpCfg.pnfP5SctpPort)) != ROK) + { + DU_LOG("\nERROR --> SCTP: Binding failed at PNF"); + } + else if((ret = cmInetListen(&pnfP5SctpCb.pnfP5LstnSockFd, 1)) != ROK) + { + DU_LOG("\nERROR --> SCTP: Unable to accept the connection at PNF"); + DU_LOG("\nERROR --> SCTP : Listening on socket failed"); + cmInetClose(&pnfP5SctpCb.pnfP5LstnSockFd); + return RFAILED; + } + else + { + for(assocIdx=0; assocIdx < pnfP5SctpCb.numAssoc; assocIdx++) + { + if((ret = pnfP5SctpAccept(&pnfP5SctpCb.assocCb[assocIdx])) != ROK) + { + DU_LOG("\nERROR --> SCTP: Unable to accept the connection at PNF"); + } + } + } + } + + if(ret == ROK) + { + if(pnfP5SctpSockPoll() != ROK) + { + DU_LOG("\nERROR --> SCTP: Polling failed to start at PNF"); + } + } + return (ret); +} + +/******************************************************************* + * + * @brief Initiates connection with peer SCTP + * + * @details + * + * Function : pnfP5SctpAccept + * + * Functionality: + * Establishes SCTP connection with peer. + * Here, VNF-P5-SCTP will initate connection towards PNF-P5-SCTP + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t pnfP5SctpAccept(PnfP5SctpAssocCb *assocCb) +{ + uint8_t ret; + + DU_LOG("\nINFO --> SCTP : Connecting"); + + while(!assocCb->connUp) + { + ret = cmInetAccept(&pnfP5SctpCb.pnfP5LstnSockFd, &assocCb->peerAddr, &assocCb->sockFd); + if (ret == ROKDNA) + { + continue; + } + else if(ret != ROK) + { + DU_LOG("\nERROR --> SCTP : Failed to accept connection"); + return RFAILED; + } + else + { + assocCb->connUp = TRUE; + pnfP5SctpSetSockOpts(&assocCb->sockFd); + break; + } + } + DU_LOG("\nINFO --> SCTP : Connection established"); + + return ROK; +} + +/******************************************************************* + * + * @brief Sets socket options as per requirement + * + * @details + * + * Function : pnfP5SctpSetSockOpts + * + * Functionality: + * Sets socket options as per requirement + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t pnfP5SctpSetSockOpts(CmInetFd *sock_Fd) +{ + S16 ret = ROK; + CmSctpEvent sctpEvent; + + sctpEvent.dataIoEvent = TRUE; + sctpEvent.associationEvent = TRUE; + sctpEvent.addressEvent = TRUE; + sctpEvent.sendFailureEvent = TRUE; + sctpEvent.peerErrorEvent = TRUE; + sctpEvent.shutdownEvent = TRUE; + sctpEvent.partialDeliveryEvent = TRUE; + sctpEvent.adaptationLayerEvent = TRUE; + + if((ret = cmInetSetOpt(sock_Fd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent)) != ROK) + { + ret = RFAILED; + } + + return (ret); +} + +/******************************************************************* + * + * @brief Receives message on the socket + * + * @details + * + * Function : pnfP5SctpSockPoll + * + * Functionality: + * Receives message on the socket + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t pnfP5SctpSockPoll() +{ + uint8_t assocIdx; + uint16_t ret = ROK; + uint32_t timeout; + uint32_t *timeoutPtr; + CmInetMemInfo memInfo; + PnfP5SctpSockPollParams pnfP5PollParams; + + memset(&pnfP5PollParams, 0, sizeof(PnfP5SctpSockPollParams)); + + /* All sockets are non-blocking */ + timeout = 0; + timeoutPtr = &timeout; + memInfo.region = PNF_APP_MEM_REG; + memInfo.pool = PNF_POOL; + + CM_INET_FD_ZERO(&pnfP5PollParams.readFd); + + DU_LOG("\nINFO --> SCTP : Polling started at PNF\n"); + while(1) + { + /* Receiving SCTP data */ + for(assocIdx = 0; assocIdx < pnfP5SctpCb.numAssoc; assocIdx++) + { + if((ret = pnfP5ProcessPolling(&pnfP5PollParams, &pnfP5SctpCb.assocCb[assocIdx], timeoutPtr, &memInfo)) != ROK) + { + DU_LOG("\nERROR --> SCTP : Failed to RecvMsg for PNF at P5 Interface \n"); + } + } + }; + return (ret); +}/* End of sctpSockPoll() */ + +/******************************************************************* + * + * @brief checks for valid readFd and process the InetSctpRecvMsg + * during polling + * + * @details + * + * Function : pnfP5ProcessPolling + * + * Functionality: + * checks for valid readFd and process the InetSctpRecvMsg + * during polling + * + * @params[in] Params required for polling + * @params[in] SockFd for file descriptor + * @params[in] timeoutPtr indicates the timeout value + * @params[in] MemInfo indicates memory region + * + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ + +uint8_t pnfP5ProcessPolling(PnfP5SctpSockPollParams *pollParams, PnfP5SctpAssocCb *assocCb, uint32_t *timeoutPtr, CmInetMemInfo *memInfo) +{ + uint16_t ret = ROK; + + CM_INET_FD_SET(&assocCb->sockFd, &pollParams->readFd); + ret = cmInetSelect(&pollParams->readFd, NULLP, timeoutPtr, &pollParams->numFd); + if(CM_INET_FD_ISSET(&assocCb->sockFd, &pollParams->readFd)) + { + CM_INET_FD_CLR(&assocCb->sockFd, &pollParams->readFd); + ret = cmInetSctpRecvMsg(&assocCb->sockFd, &pollParams->addr, &pollParams->port, memInfo, &pollParams->mBuf, \ + &pollParams->bufLen, &pollParams->info, &pollParams->flag, &pollParams->ntfy); + if(assocCb->connUp & (ret != ROK)) + { + DU_LOG("\nERROR --> SCTP: Sctp Recv Failed at PNF P5 Interface"); + // ret = RFAILED; + } + else + { + if(((pollParams->flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0) && (ret == ROK)) + { + ret = pnfP5SctpNtfyHdlr(assocCb, &pollParams->ntfy); + if(ret != ROK) + { + DU_LOG("\nERROR --> SCTP : Failed to process sctp notify msg\n"); + ret = RFAILED; + } + } + else if(assocCb->connUp) + { + /*TODO: Add the Handler of PNF P5 msgs*/ + //E2APMsgHdlr(&assocCb->duId, pollParams->mBuf); + ODU_PUT_MSG_BUF(pollParams->mBuf); + } + else + { + ODU_PUT_MSG_BUF(pollParams->mBuf); + } + } + } + return ROK; +}/* End of pnfP5ProcessPolling() */ + +/******************************************************************* + * + * @brief Handles an SCTP notification message + * + * @details + * + * Function : pnfP5SctpNtfyHdlr + * + * Functionality: + * Handles an SCTP notification message + * + * @params[in] Notify message + * + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t pnfP5SctpNtfyHdlr(PnfP5SctpAssocCb *assocCb, CmInetSctpNotification *ntfy) +{ + switch(ntfy->header.nType) + { + case CM_INET_SCTP_ASSOC_CHANGE : + DU_LOG("\nINFO --> SCTP : Assoc change notification received"); + switch(ntfy->u.assocChange.state) + { + case CM_INET_SCTP_COMM_UP: + DU_LOG("\nINFO --> Event : COMMUNICATION UP"); + assocCb->connUp = TRUE; + break; + case CM_INET_SCTP_COMM_LOST: + DU_LOG("\nINFO --> Event : COMMUNICATION LOST"); + assocCb->connUp = FALSE; + break; + case CM_INET_SCTP_RESTART: + DU_LOG("\nINFO --> Event : SCTP RESTART"); + assocCb->connUp = FALSE; + break; + case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */ + DU_LOG("\nINFO --> Event : SHUTDOWN COMPLETE"); + assocCb->connUp = FALSE; + break; + case CM_INET_SCTP_CANT_STR_ASSOC: + DU_LOG("\nINFO --> Event : CANT START ASSOC"); + assocCb->connUp = FALSE; + break; + default: + DU_LOG("\nERROR --> Invalid event"); + break; + } + break; + case CM_INET_SCTP_PEER_ADDR_CHANGE : + DU_LOG("\nINFO --> SCTP : Peer Address Change notificarion received"); + /* Need to add handler */ + break; + case CM_INET_SCTP_REMOTE_ERROR : + DU_LOG("\nINFO --> SCTP : Remote Error notification received"); + break; + case CM_INET_SCTP_SEND_FAILED : + DU_LOG("\nINFO --> SCTP : Send Failed notification received\n"); + break; + case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */ + DU_LOG("\nINFO --> SCTP : Shutdown Event notification received\n"); + assocCb->connUp = FALSE; + /*TODO: delete vnf info or database*/ + //deleteE2NodeInfo(&ricCb.duInfo[0]); + exit(0); + break; + case CM_INET_SCTP_ADAPTATION_INDICATION : + DU_LOG("\nINFO --> SCTP : Adaptation Indication received\n"); + break; + case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT: + DU_LOG("\nINFO --> SCTP : Partial Delivery Event received\n"); + break; + default: + DU_LOG("\nERROR --> SCTP : Invalid notification type\n"); + break; + } + + return ROK; +}/* End of pnfP5SctpNtfyHdlr */ + +/******************************************************************* + * + * @brief Send message on SCTP socket + * + * @details + * + * Function : sctpSend + * + * Functionality: + * Send message on SCTP socket + * + * @params[in] + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +//uint8_t pnfP5SctpSend(uint32_t vnfId, Buffer *mBuf) /*TODO: To check the VNF ID requirement here*/ +uint8_t pnfP5SctpSend(Buffer *mBuf) +{ + uint8_t assocIdx; + uint8_t ret; + MsgLen len; /* number of actually sent octets */ + CmInetMemInfo memInfo; + + memInfo.region = PNF_APP_MEM_REG; + memInfo.pool = PNF_POOL; + + for(assocIdx = 0; assocIdx < pnfP5SctpCb.numAssoc; assocIdx++) + { + /*TODO: To check whether below check req using VNFID*/ + // if(sctpCb.assocCb[assocIdx].duId == duId) + { + ret = cmInetSctpSendMsg(&pnfP5SctpCb.assocCb[assocIdx].sockFd, &pnfP5SctpCb.assocCb[assocIdx].destIpNetAddr, \ + pnfP5SctpCb.assocCb[assocIdx].destPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK); + + if(ret != ROK && ret != RWOULDBLOCK) + { + DU_LOG("\nERROR --> SCTP : Send message failed"); + return RFAILED; + } + } + } + return ROK; +} /* End of pnfP5SctpSend */ +/********************************************************************** + End of file +**********************************************************************/ + + diff --git a/src/pnf_stub/pnf_stub_sctp.h b/src/pnf_stub/pnf_stub_sctp.h new file mode 100644 index 000000000..7912cb741 --- /dev/null +++ b/src/pnf_stub/pnf_stub_sctp.h @@ -0,0 +1,103 @@ +/******************************************************************************* +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# 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. # +################################################################################ +*******************************************************************************/ + +/* This file contains all SCTP related functionality */ + +#ifndef __PNF_SCTP_H__ +#define __PNF_SCTP_H__ + +#define MAX_RETRY 5 +#define MAX_IPV6_LEN 16 +#define MAX_VNF_SUPPORTED 2 +#define MAX_ASSOC_SUPPORTED MAX_VNF_SUPPORTED + +/* Global variable declaration */ +extern uint8_t socket_type; /* Socket type */ + +typedef struct pnfP5SctpSockPollParams +{ + uint16_t numFd; + uint16_t port; + uint32_t flag; + Buffer *mBuf; + MsgLen bufLen; + CmInetNetAddr addr; + CmInetFdSet readFd; + CmInetSctpSndRcvInfo info; + CmInetSctpNotification ntfy; +}PnfP5SctpSockPollParams; + +typedef struct pnfP5SctpAssocCb +{ + uint32_t vnfId; + uint16_t destPort; /* VNF PORTS */ + CmInetFd sockFd; /* Socket file descriptor */ + CmInetAddr peerAddr; + CmInetNetAddr destIpNetAddr; /* VNF Ip address */ + Bool connUp; +}PnfP5SctpAssocCb; + +typedef struct pnfP5SctpIpAddr +{ + bool ipV4Pres; + uint32_t ipV4Addr; + bool ipV6Pres; + uint8_t ipV6Addr[MAX_IPV6_LEN]; +}PnfP5SctpIpAddr; + +typedef struct pnfP5SctpDestInfo +{ + PnfP5SctpIpAddr destIpAddr; + uint16_t destPort; +}PnfP5SctpDestInfo; + +typedef struct pnfP5SctpParams +{ + PnfP5SctpIpAddr pnfP5localIpAddr; + uint16_t pnfP5SctpPort; + uint8_t numDestNode; + PnfP5SctpDestInfo destCb[MAX_VNF_SUPPORTED]; +}PnfP5SctpParams; + +typedef struct pnfP5SctpGlobalCb +{ + PnfP5SctpParams pnfP5SctpCfg; + CmInetNetAddrLst localAddrLst; + CmInetFd pnfP5LstnSockFd; /* Listening Socket file descriptor*/ + uint8_t numAssoc; + PnfP5SctpAssocCb assocCb[MAX_ASSOC_SUPPORTED]; +}PnfP5SctpGlobalCb; + +extern PnfP5SctpGlobalCb pnfP5SctpCb; + +uint8_t pnfP5SctpActvInit(); +uint8_t pnfP5SctpCfgReq(); +uint8_t pnfP5SctpStartReq(); +uint8_t pnfP5SctpAccept(PnfP5SctpAssocCb *assocCb); +uint8_t pnfP5SctpSetSockOpts(CmInetFd *sock_Fd); +uint8_t pnfP5SctpAccept(PnfP5SctpAssocCb *assocCb); +uint8_t pnfP5SctpSockPoll(); +uint8_t pnfP5ProcessPolling(PnfP5SctpSockPollParams *pollParams, PnfP5SctpAssocCb *assocCb, uint32_t *timeoutPtr, CmInetMemInfo *memInfo); +uint8_t pnfP5SctpNtfyHdlr(PnfP5SctpAssocCb *assocCb, CmInetSctpNotification *ntfy); +uint8_t pnfP5SctpSend(Buffer *mBuf); + +#endif + +/********************************************************************** + End of file + **********************************************************************/