Commit 2dcf50a5 authored by Raphael Defosseux's avatar Raphael Defosseux

Merge remote-tracking branch 'origin/benetel_integration' into develop_integration_2020_w36

parents 869f0e98 a44a32af
......@@ -71,6 +71,12 @@ gNBs =
initialDLBWPmappingType_2 = 0;
#this is SS=1,L=12
initialDLBWPstartSymbolAndLength_2 = 54;
initialDLBWPk0_3 = 0;
initialDLBWPmappingType_3 = 0;
#this is SS=1,L=4
initialDLBWPstartSymbolAndLength_3 = 57;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 78;
......@@ -105,8 +111,8 @@ gNBs =
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3;
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#oneHalf (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
......@@ -114,8 +120,8 @@ gNBs =
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#0 = 839, 1 = 139
prach_RootSequenceIndex_PR = 1;
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
......@@ -135,6 +141,10 @@ gNBs =
# this is SS=0 L=12
initialULBWPstartSymbolAndLength_1 = 69;
initialULBWPk2_2 = 7;
initialULBWPmappingType_2 = 1;
# this is SS=10 L=4
initialULBWPstartSymbolAndLength_2 = 52;
msg3_DeltaPreamble = 1;
p0_NominalWithGrant =-90;
......@@ -237,6 +247,8 @@ RUs = (
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
eNB_instances = [0];
#beamforming 1x4 matrix:
bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
clock_src = "external";
}
......
......@@ -763,6 +763,42 @@ set(HWLIB_TCP_BRIDGE_OAI_SOURCE
add_library(tcp_bridge_oai MODULE ${HWLIB_TCP_BRIDGE_OAI_SOURCE} )
set_target_properties(tcp_bridge_oai PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
# Benetel 4G library
######################################################################
set(HWLIB_BENETEL_4G_SOURCE
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/benetel.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/shared_buffers.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/low.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/low_dpdk.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/dpdk_driver.c
)
add_library(benetel_4g MODULE ${HWLIB_BENETEL_4G_SOURCE} )
set_target_properties(benetel_4g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include")
SET(DPDK_LIBS "-Wl,-rpath,$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -Wl,--whole-archive -L$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -ldpdk -Wl,--no-whole-archive")
TARGET_LINK_LIBRARIES(benetel_4g ${DPDK_LIBS})
TARGET_LINK_LIBRARIES(benetel_4g pthread dl rt m numa)
# Benetel 5G library
######################################################################
set(HWLIB_BENETEL_5G_SOURCE
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/benetel.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/shared_buffers.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/low.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/low_dpdk.c
${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/dpdk_driver.c
)
add_library(benetel_5g MODULE ${HWLIB_BENETEL_5G_SOURCE} )
set_target_properties(benetel_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include")
SET(DPDK_LIBS "-Wl,-rpath,$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -Wl,--whole-archive -L$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -ldpdk -Wl,--no-whole-archive")
TARGET_LINK_LIBRARIES(benetel_5g ${DPDK_LIBS})
TARGET_LINK_LIBRARIES(benetel_5g pthread dl rt m numa)
##########################################################
include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
......
......@@ -180,6 +180,17 @@ int attach_rru(RU_t *ru)
((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
"RU %d failed send configuration to remote radio\n",ru->idx);
if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
&rru_config_msg,
msg_len))<0) {
LOG_I(PHY,"Waiting for RRU %d\n",ru->idx);
} else if (rru_config_msg.type == RRU_config_ok) {
LOG_I(PHY, "RRU_config_ok received\n");
} else {
LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx);
}
return 0;
}
......@@ -1442,6 +1453,8 @@ void *ru_thread( void *param ) {
LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]);
memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
if(emulate_rf) {
fill_rf_config(ru,ru->rf_config_file);
nr_init_frame_parms(&ru->config, fp);
......@@ -1464,8 +1477,6 @@ void *ru_thread( void *param ) {
AssertFatal(ret==0,"Cannot connect to remote radio\n");
}
memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
if (ru->if_south == LOCAL_RF) { // configure RF parameters only
nr_init_frame_parms(&ru->config, fp);
nr_dump_frame_parms(fp);
......@@ -1571,7 +1582,8 @@ void *ru_thread( void *param ) {
if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
//if (proc->tti_rx==8) {
if (ru->feprx) ru->feprx(ru,proc->tti_rx);
if (ru->feprx) {
ru->feprx(ru,proc->tti_rx);
//LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1);
LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx);
......@@ -1592,6 +1604,7 @@ void *ru_thread( void *param ) {
free_nr_ru_prach_entry(ru,prach_id);
}
}
}
// At this point, all information for subframe has been received on FH interface
......@@ -2131,7 +2144,8 @@ void set_function_spec_param(RU_t *ru) {
ru->fh_north_out = NULL; // no outgoing fronthaul to north
ru->nr_start_if = NULL; // no if interface
ru->rfdevice.host_type = RAU_HOST;
}
// FK this here looks messed up. The following lines should be part of the if (ru->function == gNodeB_3GPP), shouldn't they?
ru->fh_south_in = rx_rf; // local synchronous RF RX
ru->fh_south_out = tx_rf; // local synchronous RF TX
......@@ -2139,18 +2153,20 @@ void set_function_spec_param(RU_t *ru) {
ru->stop_rf = stop_rf;
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
}
/*
if (ru->function == gNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
fill_rf_config(ru,rf_config_file);
init_frame_parms(&ru->frame_parms,1);
nr_phy_init_RU(ru);
}
ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
if (setup_RU_buffers(ru)!=0) {
printf("Exiting, cannot initialize RU Buffers\n");
exit(-1);
}*/
}
*/
break;
case REMOTE_IF5: // the remote unit is IF5 RRU
......@@ -2203,6 +2219,15 @@ void set_function_spec_param(RU_t *ru) {
exit(-1);
}
if (ru->ifdevice.get_internal_parameter != NULL) {
void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
if (t != NULL)
ru->fh_south_in = t;
t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
if (t != NULL)
ru->fh_south_out = t;
}
malloc_IF4p5_buffer(ru);
break;
......
......@@ -218,7 +218,7 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_TTI_PRACH_PDU_TYPE for %d.%d\n", frame, slot, UL_tti_req->SFN, UL_tti_req->Slot);
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu;
nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
if (gNB->RU_list[0]->if_south == LOCAL_RF) nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
break;
}
}
......
......@@ -463,24 +463,53 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
schedule_nr_mib(module_idP, frame, slot);
}
// This schedule PRACH if we are not in phy_test mode
if (get_softmodem_params()->phy_test == 0)
schedule_nr_prach(module_idP, frame, slot);
nr_schedule_RA(module_idP, frame_txP, slot_txP);
else
UE_list->fiveG_connected[UE_id] = true;
// This schedule SR
// TODO
if (get_softmodem_params()->phy_test == 1) {
if (slot_txP == 7){
NR_RA_t *ra = &RC.nrmac[module_idP]->common_channels[0].ra[0];
ra->Msg2_frame = frame_txP;
ra->Msg2_slot = slot_txP;
ra->state = Msg2;
ra->bwp_id = 1;
NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1];
struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
for (int i=0;i<commonSearchSpaceList->list.count;i++) {
NR_SearchSpace_t *ss=commonSearchSpaceList->list.array[i];
if(ss->searchSpaceId == *bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace)
ra->ra_ss=ss;
}
AssertFatal(ra->ra_ss!=NULL,"no search space for RA'n");
nr_generate_Msg2(module_idP, 0/*CC_id*/,
frame_txP,
slot_txP);
}
}
// This schedule CSI
// TODO
// Phytest scheduling
if (get_softmodem_params()->phy_test) {
// TbD once RACH is available, start ta_timer when UE is connected
if (ue_sched_ctl->ta_timer)
ue_sched_ctl->ta_timer--;
// This schedule RA procedure if not in phy_test mode
// Otherwise already consider 5G already connected
if (get_softmodem_params()->phy_test == 0) {
nr_schedule_RA(module_idP, frame, slot);
nr_schedule_reception_msg3(module_idP, 0, frame, slot);
if (ue_sched_ctl->ta_timer == 0) {
gNB->ta_command = ue_sched_ctl->ta_update;
/* if time is up, then set the timer to not send it for 5 frames
// regardless of the TA value */
ue_sched_ctl->ta_timer = 100;
/* reset ta_update */
ue_sched_ctl->ta_update = 31;
/* MAC CE flag indicating TA length */
gNB->ta_len = 2;
}
}
else
UE_list->fiveG_connected[UE_id] = true;
if (get_softmodem_params()->phy_test) {
......
......@@ -437,7 +437,10 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t
NR_UE_list_t *UE_list = &mac->UE_list;
int UE_id = 0;
AssertFatal(ra->state != RA_IDLE, "RA is not active for RA %X\n", ra->rnti);
if (ra->state != RA_IDLE) {
LOG_W(MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti);
return;
}
LOG_D(MAC, "[gNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d RA is active, Msg3 in (%d,%d)\n", module_idP, frameP, slotP, CC_id, ra->Msg3_frame, ra->Msg3_slot);
......
......@@ -9093,14 +9093,16 @@ void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP,
rrc_eNB_ue_context_t *ue_context;
unsigned char buffer[8192];
int size;
ue_context = rrc_eNB_get_ue_context(RC.rrc[enb_mod_idP], m->rnti);
if (ue_context) {
ue_context->ue_context.nb_of_modify_endc_e_rabs = m->nb_e_rabs_admitted_tobeadded;
int j=0;
while(j < m->nb_e_rabs_admitted_tobeadded) {
for (int e_rab_idx=0; e_rab_idx<ue_context->ue_context.setup_e_rabs; e_rab_idx++) {
int j=0;
while(j < m->nb_e_rabs_admitted_tobeadded){
for (int e_rab_idx=0; e_rab_idx<ue_context->ue_context.setup_e_rabs; e_rab_idx++){
//Update ue_context information with gNB's address and new GTP tunnel ID
if( ue_context->ue_context.e_rab[e_rab_idx].param.e_rab_id == m->e_rabs_admitted_tobeadded[j].e_rab_id) {
if( ue_context->ue_context.e_rab[e_rab_idx].param.e_rab_id == m->e_rabs_admitted_tobeadded[j].e_rab_id){
memcpy(ue_context->ue_context.gnb_gtp_endc_addrs[e_rab_idx].buffer,
m->e_rabs_admitted_tobeadded[j].gnb_addr.buffer,
m->e_rabs_admitted_tobeadded[j].gnb_addr.length);
......@@ -9110,7 +9112,6 @@ void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP,
break;
}
}
j++;
}
......@@ -9119,7 +9120,9 @@ void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP,
ENB_FLAG_YES,
m->rnti,
0, 0);
size = rrc_eNB_generate_RRCConnectionReconfiguration_endc(&ctxt, ue_context, buffer, 8192, scg_CellGroupConfig, nr1_conf);
rrc_data_req(&ctxt,
DCCH,
rrc_eNB_mui++,
......@@ -9127,8 +9130,11 @@ void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP,
size,
buffer,
PDCP_TRANSMISSION_MODE_CONTROL);
}
} else {
LOG_E(F1AP, "no ue_context for RNTI %x, acknowledging release\n", m->rnti);
}
}
//-----------------------------------------------------------------------------
void *rrc_enb_process_itti_msg(void *notUsed) {
......
......@@ -434,6 +434,11 @@ struct openair0_device_t {
* \param arg pointer to capabilities or configuration
*/
int (*trx_write_init)(openair0_device *device);
/* \brief Get internal parameter
* \param id parameter to get
* \return a pointer to the parameter
*/
void *(*get_internal_parameter)(char *id);
};
/* type of device init function, implemented in shared lib */
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#include "shared_buffers.h"
#include "low.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
typedef struct {
eth_state_t e;
shared_buffers buffers;
rru_config_msg_type_t last_msg;
int capabilities_sent;
void *benetel_priv;
char *dpdk_main_command_line;
} benetel_eth_state_t;
int trx_benetel_start(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
void trx_benetel_end(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
}
int trx_benetel_stop(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_freq(openair0_device* device,
openair0_config_t *openair0_cfg,
int exmimo_dump_config)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_gains(openair0_device* device,
openair0_config_t *openair0_cfg)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_get_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_reset_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int ethernet_tune(openair0_device *device,
unsigned int option,
int value)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
int trx_benetel_write_raw(openair0_device *device,
openair0_timestamp timestamp,
void **buff, int nsamps, int cc, int flags)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
int trx_benetel_read_raw(openair0_device *device,
openair0_timestamp *timestamp,
void **buff, int nsamps, int cc)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
char *msg_type(int t)
{
static char *s[12] = {
"RAU_tick",
"RRU_capabilities",
"RRU_config",
"RRU_config_ok",
"RRU_start",
"RRU_stop",
"RRU_sync_ok",
"RRU_frame_resynch",
"RRU_MSG_max_num",
"RRU_check_sync",
"RRU_config_update",
"RRU_config_update_ok",
};
if (t < 0 || t > 11) return "UNKNOWN";
return s[t];
}
int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type,
msg_type(rru_config_msg->type));
s->last_msg = rru_config_msg->type;
return msg_len;
}
int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
RRU_capabilities_t *cap;
rru_config_msg->type = RRU_capabilities;
rru_config_msg->len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
cap = (RRU_capabilities_t*)&rru_config_msg->msg[0];
cap->FH_fmt = OAI_IF4p5_only;
cap->num_bands = 1;
cap->band_list[0] = 7;
cap->nb_rx[0] = 1;
cap->nb_tx[0] = 1;
cap->max_pdschReferenceSignalPower[0] = -27;
cap->max_rxgain[0] = 90;
s->capabilities_sent = 1;
return rru_config_msg->len;
}
if (s->last_msg == RRU_config) {
rru_config_msg->type = RRU_config_ok;
return 0;
}
if (s->last_msg == RRU_start) {
s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
}
/* correct? */
while (1) pause();
return 0;
}
void benetel_fh_if4p5_south_in(RU_t *ru,
int *frame,
int *subframe)
{
benetel_eth_state_t *s = ru->ifdevice.priv;
PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB;
LTE_DL_FRAME_PARMS *fp;
int symbol;
int32_t *rxdata;
int antenna = 0;
lock_ul_buffer(&s->buffers, *subframe);
next:
while (!(s->buffers.ul_busy[*subframe] == 0x3fff ||
s->buffers.prach_busy[*subframe] == 1))
wait_ul_buffer(&s->buffers, *subframe);
if (s->buffers.prach_busy[*subframe] == 1) {
int i;
int antenna = 0;
uint16_t *in;
uint16_t *out;
in = (uint16_t *)s->buffers.prach[*subframe];
out = (uint16_t *)ru->prach_rxsigF[antenna];
for (i = 0; i < 840*2; i++)
out[i] = ntohs(in[i]);
s->buffers.prach_busy[*subframe] = 0;
ru->wakeup_prach_eNB(ru->eNB_list[0], ru, *frame, *subframe);
goto next;
}
eNB = eNB_list[0];
fp = &eNB->frame_parms;
for (symbol = 0; symbol < 14; symbol++) {
int i;
uint16_t *p = (uint16_t *)(&s->buffers.ul[*subframe][symbol*1200*4]);
for (i = 0; i < 1200*2; i++) {
p[i] = htons(p[i]);
}
rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(rxdata + 2048 - 600,
&s->buffers.ul[*subframe][symbol*1200*4],
600 * 4);
memcpy(rxdata,
&s->buffers.ul[*subframe][symbol*1200*4] + 600*4,
600 * 4);
#endif
}
s->buffers.ul_busy[*subframe] = 0;
signal_ul_buffer(&s->buffers, *subframe);
unlock_ul_buffer(&s->buffers, *subframe);
//printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *subframe);
RU_proc_t *proc = &ru->proc;
extern uint16_t sf_ahead;
int f = *frame;
int sf = *subframe;
//calculate timestamp_rx, timestamp_tx based on frame and subframe
proc->tti_rx = sf;
proc->frame_rx = f;
proc->timestamp_rx = ((proc->frame_rx * 10) + proc->tti_rx ) * fp->samples_per_tti ;
if (get_nprocs()<=4) {
proc->tti_tx = (sf+sf_ahead)%10;
proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f;
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,f);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,sf);
proc->symbol_mask[sf] = 0;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff);
}
void benetel_fh_if4p5_south_out(RU_t *ru,
int frame,
int subframe,
uint64_t timestamp)
{
benetel_eth_state_t *s = ru->ifdevice.priv;
PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB;
LTE_DL_FRAME_PARMS *fp;
int symbol;
int32_t *txdata;
int aa = 0;
//printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, subframe, timestamp);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
lock_dl_buffer(&s->buffers, subframe);
if (s->buffers.dl_busy[subframe]) {
printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, subframe);
unlock_dl_buffer(&s->buffers, subframe);
return;
}
eNB = eNB_list[0];
fp = &eNB->frame_parms;
if (ru->num_eNB != 1 || ru->nb_tx != 1 || fp->ofdm_symbol_size != 2048 ||
fp->Ncp != NORMAL || fp->symbols_per_tti != 14) {
printf("%s:%d:%s: unsupported configuration\n",
__FILE__, __LINE__, __FUNCTION__);
exit(1);
}
for (symbol = 0; symbol < 14; symbol++) {
txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(&s->buffers.dl[subframe][symbol*1200*4],
txdata + 2048 - 600,
600 * 4);
memcpy(&s->buffers.dl[subframe][symbol*1200*4] + 600*4,
txdata + 1,
600 * 4);
#endif
int i;
uint16_t *p = (uint16_t *)(&s->buffers.dl[subframe][symbol*1200*4]);
for (i = 0; i < 1200*2; i++) {
p[i] = htons(p[i]);
}
}
s->buffers.dl_busy[subframe] = 0x3fff;
unlock_dl_buffer(&s->buffers, subframe);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.frame_tx);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.tti_tx);
}
void *get_internal_parameter(char *name)
{
printf("BENETEL: %s\n", __FUNCTION__);
if (!strcmp(name, "fh_if4p5_south_in"))
return benetel_fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return benetel_fh_if4p5_south_out;
return NULL;
}
__attribute__((__visibility__("default")))
int transport_init(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t * eth_params )
{
benetel_eth_state_t *eth;
printf("BENETEL: %s\n", __FUNCTION__);
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_benetel_start;
device->trx_get_stats_func = trx_benetel_get_stats;
device->trx_reset_stats_func = trx_benetel_reset_stats;
device->trx_end_func = trx_benetel_end;
device->trx_stop_func = trx_benetel_stop;
device->trx_set_freq_func = trx_benetel_set_freq;
device->trx_set_gains_func = trx_benetel_set_gains;
device->trx_write_func = trx_benetel_write_raw;
device->trx_read_func = trx_benetel_read_raw;
device->trx_ctlsend_func = trx_benetel_ctlsend;
device->trx_ctlrecv_func = trx_benetel_ctlrecv;
device->get_internal_parameter = get_internal_parameter;
eth = calloc(1, sizeof(benetel_eth_state_t));
if (eth == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
device->priv = eth;
device->openair0_cfg=&openair0_cfg[0];
if (openair0_cfg->sdr_addrs == NULL) {
printf("benetel: fatal: sdr_addrs not set in configuration file\n");
exit(1);
}
eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs);
if (eth->dpdk_main_command_line == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->last_msg = -1;
init_buffers(&eth->buffers);
return 0;
}
/* license: to be defined */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include "low.h"
// HEADER DEFINITION
#define ANT_NUM buf[23]
#define PAYLOAD_1 buf[20]
#define PAYLOAD_2 buf[21]
#define ETH_TYPE buf[17]
#define SYMBOL buf[29]
#define SUBFRAME buf[28]
#define FRAME buf[27]
static volatile bool force_quit;
unsigned short iq[33600];
unsigned char iq_swap[67200];
unsigned short *iq_ptr[14];
unsigned int dl_start = 0;
/* MAC updating enabled by default */
static int mac_updating = 1;
#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */
#define MEMPOOL_CACHE_SIZE 256
/*
* Configurable number of RX/TX ring descriptors
*/
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/* ethernet addresses of ports */
static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;
/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
static unsigned int l2fwd_rx_queue_per_lcore = 1;
#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf {
unsigned n_rx_port;
unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
} __rte_cache_aligned;
struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME,
.split_hdr_size = 0,
.max_rx_pkt_len = 9500,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
/* Per-port statistics struct */
struct l2fwd_port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
static uint64_t timer_period = 10; /* default period is 10 seconds */
/* Print out statistics on packets dropped */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
unsigned portid;
total_packets_dropped = 0;
total_packets_tx = 0;
total_packets_rx = 0;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
/* Clear screen and move to top left */
printf("%s%s", clr, topLeft);
printf("\nPort statistics ====================================");
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
/* skip disabled ports */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
"\nPackets sent: %24"PRIu64
"\nPackets received: %20"PRIu64
"\nPackets dropped: %21"PRIu64,
portid,
port_statistics[portid].tx,
port_statistics[portid].rx,
port_statistics[portid].dropped);
total_packets_dropped += port_statistics[portid].dropped;
total_packets_tx += port_statistics[portid].tx;
total_packets_rx += port_statistics[portid].rx;
}
printf("\nAggregate statistics ==============================="
"\nTotal packets sent: %18"PRIu64
"\nTotal packets received: %14"PRIu64
"\nTotal packets dropped: %15"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
}
static void
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs)
{
unsigned char *buf, *buf_tx;
unsigned int len;
struct ether_hdr *eth;
unsigned dst_port;
int sent, prach_ctrl = 0;
struct rte_eth_dev_tx_buffer *buffer;
unsigned char * IQ_ptr;
ul_packet_t p;
buf = rte_pktmbuf_mtod(m, unsigned char *);
//rte_memdump(stdout, "Rx Packet",buf ,34);
eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
len = rte_pktmbuf_data_len(m);
IQ_ptr = &buf[34];
//destination mac address (RRU MAC)
eth->d_addr.addr_bytes[0] = 0x02;
eth->d_addr.addr_bytes[1] = 0x00;
eth->d_addr.addr_bytes[2] = 0x5e;
eth->d_addr.addr_bytes[3] = 0x01;
eth->d_addr.addr_bytes[4] = 0x01;
eth->d_addr.addr_bytes[5] = 0x01;
//source mac address (DU MAC)
eth->s_addr.addr_bytes[0] = 0xdd;
eth->s_addr.addr_bytes[1] = 0xdd;
eth->s_addr.addr_bytes[2] = 0xdd;
eth->s_addr.addr_bytes[3] = 0xdd;
eth->s_addr.addr_bytes[4] = 0xdd;
eth->s_addr.addr_bytes[5] = 0xdd;
dst_port = l2fwd_dst_ports[portid];
#if 1
if (buf[18] == 0xAA) //msg1 check
{
printf("\nHandshake MSG 1 Received\n");
printf("\n====================================================\n");
buf[18] = 0xBB;//change to msg2 after receive msg1
printf("Handshake MSG 2 Sent\n");
printf("\n====================================================\n");
}
#else
// Handshake Condition
if (buf[18] == 0x01 || buf[18] == 0x03) // ORAN handshake msgs.
{
if (buf[18] == 0x01) //msg1 check
{
printf("\nHandshake MSG 1 Received\n");
printf("\n====================================================\n");
buf[18] = 0x02;//change to msg2 after receive msg1
printf("Handshake MSG 2 Sent\n");
printf("\n====================================================\n");
}
else if(buf[18] == 0x03) //msg3 check
{
printf("Handshake MSG 3 Sent\n");
printf("\n====================================================\n");
buf[18] = 0x04;
printf("Handshake MSG 4 Sent\n");
printf("\n====================================================\n");
}
}
#endif
// Trigger start send DL packets
if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && SYMBOL == 0x09 && ANT_NUM == 0x00 && dl_start == 0){
printf("\nU-Plane Started\n");
printf("\n====================================================\n");
dl_start = 1;
}
if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00) {
p.frame = FRAME;
p.subframe = SUBFRAME >> 4;
p.slot = 0; /* unused */
p.symbol = SYMBOL;
p.antenna = 0;
memcpy(p.iq, IQ_ptr, 4800);
store_ul(bs, &p);
}
// U-PLANE UL ANT_0 PROCESSING
if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00 && dl_start == 1)
{
int tx_frame = FRAME;
int tx_subframe = SUBFRAME >> 4;
int tx_symbol = SYMBOL + 5;
if (tx_symbol > 13) {
tx_symbol -= 14;
tx_subframe++;
if (tx_subframe == 10) {
tx_subframe = 0;
tx_frame = (tx_frame + 1) & 255;
}
}
// ANT_NUM = 0x00;
// SYMBOL = (SYMBOL + 5) % 14;
PAYLOAD_2 = 0xc8;
FRAME = tx_frame;
SUBFRAME = tx_subframe << 4;
SYMBOL = tx_symbol;
/* antenna 0 - send actual DL data (if available) */
lock_dl_buffer(bs->buffers, tx_subframe);
if (!(bs->buffers->dl_busy[tx_subframe] & (1 << tx_symbol))) {
printf("%s: warning, DL underflow (sf.symbol %d.%d)\n", __FUNCTION__,
tx_subframe, tx_symbol);
memset(IQ_ptr, 0, 1200 * 4);
} else {
memcpy(IQ_ptr, bs->buffers->dl[tx_subframe] + tx_symbol * 1200*4,
1200*4);
}
bs->buffers->dl_busy[tx_subframe] &= ~(1 << tx_symbol);
unlock_dl_buffer(bs->buffers, tx_subframe);
// fill DL Data for ant 0 with 0 value
// memset(IQ_ptr, 0, 4800);
}
// U-PLANE UL ANT_1 PROCESSING
else if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x01 && dl_start == 1)
{
// ANT_NUM = 0x01;
SYMBOL = (SYMBOL + 5) % 14;
PAYLOAD_2 = 0xc8;
// fill DL Data for ant 1 with 0 value
memset(IQ_ptr, 0, 4800);
}
// U-PLANE PRACH PROCESSING
else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){
if (ANT_NUM == 0) {
store_prach(bs, FRAME, SUBFRAME>>4, IQ_ptr);
}
rte_pktmbuf_free(m);
return;
}
// Send Packets
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
/* main processing loop */
static void
l2fwd_main_loop(benetel_t *bs)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on master core */
if (lcore_id == rte_get_master_lcore()) {
//print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid, bs);
}
}
}
}
static int
l2fwd_launch_one_lcore(void *bs)
{
l2fwd_main_loop(bs);
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (pm == 0)
return -1;
return pm;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case 0:
break;
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
rte_eth_link_get_nowait(portid, &link);
/* print link status if flag set */
if (print_flag == 1) {
if (link.link_status)
printf(
"Port%d Link Up. Speed %u Mbps - %s\n",
portid, link.link_speed,
(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
("full-duplex") : ("half-duplex\n"));
else
printf("Port %d Link Down\n", portid);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
dpdk_main(int argc, char **argv, benetel_t *bs)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/*
* Each logical core is assigned a dedicated TX queue on each port.
*/
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
}
else
last_port = portid;
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, 9680,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
rte_eth_dev_info_get(portid, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
rte_eth_promiscuous_enable(portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER);
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
rte_eth_dev_stop(portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
return ret;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "low.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void store_ul(benetel_t *bs, ul_packet_t *ul)
{
/* only antenna 0 for the moment */
if (ul->antenna != 0)
return;
if (ul->subframe != bs->next_subframe ||
ul->symbol != bs->next_symbol) {
printf("%s: fatal, expected frame.sf.symbol %d.%d.%d, got %d.%d.%d\n",
__FUNCTION__,
bs->expected_benetel_frame, bs->next_subframe, bs->next_symbol,
ul->frame, ul->subframe, ul->symbol);
exit(1);
}
lock_ul_buffer(bs->buffers, bs->next_subframe);
if (bs->buffers->ul_busy[bs->next_subframe] & (1 << bs->next_symbol)) {
printf("%s: warning, UL overflow (sf.symbol %d.%d)\n", __FUNCTION__,
bs->next_subframe, bs->next_symbol);
}
memcpy(bs->buffers->ul[bs->next_subframe] + bs->next_symbol * 1200*4,
ul->iq, 1200*4);
bs->buffers->ul_busy[bs->next_subframe] |= (1 << bs->next_symbol);
signal_ul_buffer(bs->buffers, bs->next_subframe);
unlock_ul_buffer(bs->buffers, bs->next_subframe);
bs->next_symbol++;
if (bs->next_symbol == 14) {
bs->next_symbol = 0;
bs->next_subframe = (bs->next_subframe + 1) % 10;
if (bs->next_subframe == 0) {
bs->expected_benetel_frame++;
bs->expected_benetel_frame &= 255;
}
}
}
void store_prach(benetel_t *bs, int frame, int subframe, void *data)
{
static int last_frame = -1;
static int last_subframe = -1;
/* hack: antenna number is always 0, discard second packet with same f/sf */
if (frame == last_frame && subframe == last_subframe) return;
last_frame = frame;
last_subframe = subframe;
lock_ul_buffer(bs->buffers, subframe);
if (bs->buffers->prach_busy[subframe]) {
printf("store_prach: fatal: previous prach buffer not processed\n");
unlock_ul_buffer(bs->buffers, subframe);
return;
}
bs->buffers->prach_busy[subframe] = 1;
memcpy(bs->buffers->prach[subframe], data, 849*4);
signal_ul_buffer(bs->buffers, subframe);
unlock_ul_buffer(bs->buffers, subframe);
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
if (!strcmp(ifname, "dpdk"))
return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line);
printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname);
exit(1);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _BENETEL_LOW_H_
#define _BENETEL_LOW_H_
#include "shared_buffers.h"
typedef struct {
shared_buffers *buffers;
int next_subframe;
int next_symbol;
int expected_benetel_frame;
char *dpdk_main_command_line;
} benetel_t;
typedef struct {
int frame;
int subframe;
int slot;
int symbol;
int antenna;
unsigned char iq[4800];
} ul_packet_t;
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void store_ul(benetel_t *bs, ul_packet_t *ul);
void store_prach(benetel_t *bs, int frame, int subframe, void *data);
#endif /* _BENETEL_LOW_H_ */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* those 2 lines for CPU_SET */
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "low.h"
int dpdk_main(int argc, char **argv, benetel_t *);
void *dpdk_thread(void *_bs)
{
benetel_t *bs = _bs;
int n = 0;
char **v = NULL; // { "softmodem", "-n", "2", "-l", "8", "--", "-p", "0x2" };
char *s = bs->dpdk_main_command_line;
char *tok;
while ((tok = strtok(s, " ")) != NULL) {
n++;
v = realloc(v, n * sizeof(char *));
if (v == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
v[n-1] = tok;
s = NULL;
}
dpdk_main(n, v, bs);
exit(1);
return 0;
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
benetel_t *bs;
bs = calloc(1, sizeof(benetel_t));
if (bs == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
bs->buffers = buffers;
bs->expected_benetel_frame = 255;
bs->dpdk_main_command_line = dpdk_main_command_line;
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(12,&cpuset);
if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) {
printf("pthread_attr_setaffinity_np failed\n");
exit(1);
}
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
printf("pthread_attr_setschedpolicy failed\n");
exit(1);
}
struct sched_param params;
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_get_priority_max(SCHED_FIFO) == -1) {
printf("sched_get_priority_max failed\n");
exit(1);
}
if (pthread_attr_setschedparam(&attr, &params) != 0) {
printf("pthread_setschedparam failed\n");
exit(1);
}
pthread_t t;
if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) {
printf("%s: thread creation failed\n", __FUNCTION__);
exit(1);
}
if (pthread_attr_destroy(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
return bs;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "shared_buffers.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init_buffers(shared_buffers *s)
{
int subframe;
memset(s, 0, sizeof(*s));
for (subframe = 0; subframe < 10; subframe++) {
if (pthread_mutex_init(&s->m_dl[subframe], NULL) != 0 ||
pthread_cond_init(&s->c_dl[subframe], NULL) != 0 ||
pthread_mutex_init(&s->m_ul[subframe], NULL) != 0 ||
pthread_cond_init(&s->c_ul[subframe], NULL) != 0) {
printf("%s: error initializing mutex/cond\n", __FUNCTION__);
exit(1);
}
}
/* in FDD the eNB's first transmitted DL subframe is 4 but the device
* needs to have subframes 1, 2 and 3 ready. Let's pretend there are ready.
*/
s->dl_busy[1] = 0x3fff;
s->dl_busy[2] = 0x3fff;
s->dl_busy[3] = 0x3fff;
}
void lock_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_lock(&s->m_dl[subframe]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
exit(1);
}
}
void unlock_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_unlock(&s->m_dl[subframe]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_wait(&s->c_dl[subframe], &s->m_dl[subframe]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_broadcast(&s->c_dl[subframe]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
void lock_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_lock(&s->m_ul[subframe]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
exit(1);
}
}
void unlock_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_unlock(&s->m_ul[subframe]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_wait(&s->c_ul[subframe], &s->m_ul[subframe]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_broadcast(&s->c_ul[subframe]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _SHARED_BUFFERS_H_
#define _SHARED_BUFFERS_H_
#include <pthread.h>
#include <stdint.h>
typedef struct {
unsigned char dl[10][14*1200*4];
unsigned char ul[10][14*1200*4];
uint16_t dl_busy[10];
uint16_t ul_busy[10];
pthread_mutex_t m_ul[10];
pthread_cond_t c_ul[10];
pthread_mutex_t m_dl[10];
pthread_cond_t c_dl[10];
unsigned char prach[10][849*4];
unsigned char prach_busy[10];
/* statistics/error counting */
int ul_overflow;
int dl_underflow;
} shared_buffers;
void init_buffers(shared_buffers *s);
void lock_dl_buffer(shared_buffers *s, int subframe);
void unlock_dl_buffer(shared_buffers *s, int subframe);
void wait_dl_buffer(shared_buffers *s, int subframe);
void signal_dl_buffer(shared_buffers *s, int subframe);
void lock_ul_buffer(shared_buffers *s, int subframe);
void unlock_ul_buffer(shared_buffers *s, int subframe);
void wait_ul_buffer(shared_buffers *s, int subframe);
void signal_ul_buffer(shared_buffers *s, int subframe);
#endif /* _SHARED_BUFFERS_H_ */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#include "shared_buffers.h"
#include "low.h"
#include "openair1/PHY/defs_gNB.h"
typedef struct {
eth_state_t e;
shared_buffers buffers;
rru_config_msg_type_t last_msg;
int capabilities_sent;
void *benetel_priv;
char *dpdk_main_command_line;
} benetel_eth_state_t;
int trx_benetel_start(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
void trx_benetel_end(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
}
int trx_benetel_stop(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_freq(openair0_device* device,
openair0_config_t *openair0_cfg,
int exmimo_dump_config)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_gains(openair0_device* device,
openair0_config_t *openair0_cfg)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_get_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_reset_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int ethernet_tune(openair0_device *device,
unsigned int option,
int value)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
int trx_benetel_write_raw(openair0_device *device,
openair0_timestamp timestamp,
void **buff, int nsamps, int cc, int flags)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
int trx_benetel_read_raw(openair0_device *device,
openair0_timestamp *timestamp,
void **buff, int nsamps, int cc)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
char *msg_type(int t)
{
static char *s[12] = {
"RAU_tick",
"RRU_capabilities",
"RRU_config",
"RRU_config_ok",
"RRU_start",
"RRU_stop",
"RRU_sync_ok",
"RRU_frame_resynch",
"RRU_MSG_max_num",
"RRU_check_sync",
"RRU_config_update",
"RRU_config_update_ok",
};
if (t < 0 || t > 11) return "UNKNOWN";
return s[t];
}
int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type,
msg_type(rru_config_msg->type));
s->last_msg = rru_config_msg->type;
return msg_len;
}
int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
RRU_capabilities_t *cap;
rru_config_msg->type = RRU_capabilities;
rru_config_msg->len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
cap = (RRU_capabilities_t*)&rru_config_msg->msg[0];
cap->FH_fmt = OAI_IF4p5_only;
cap->num_bands = 1;
cap->band_list[0] = 78;
cap->nb_rx[0] = 1;
cap->nb_tx[0] = 1;
cap->max_pdschReferenceSignalPower[0] = -27;
cap->max_rxgain[0] = 90;
s->capabilities_sent = 1;
return rru_config_msg->len;
}
#if 0
if (s->last_msg == RRU_config) {
rru_config_msg->type = RRU_config_ok;
return 0;
}
if (s->last_msg == RRU_start) {
printf("***************** benetel start\n");
s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
}
#endif
if (s->last_msg == RRU_config) {
rru_config_msg->type = RRU_config_ok;
s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
}
/* correct? */
//printf("***************** benetel pause\n");
// while (1) pause();
return 0;
}
void benetel_fh_if4p5_south_in(RU_t *ru,
int *frame,
int *slot)
{
//printf("XXX benetel_fh_if4p5_south_in %d %d\n", *frame, *slot);
benetel_eth_state_t *s = ru->ifdevice.priv;
NR_DL_FRAME_PARMS *fp;
int symbol;
int32_t *rxdata;
int antenna = 0;
lock_ul_buffer(&s->buffers, *slot);
#if 1
next:
while (!(s->buffers.ul_busy[*slot] == 0x3fff ||
s->buffers.prach_busy[*slot] == 1))
wait_ul_buffer(&s->buffers, *slot);
if (s->buffers.prach_busy[*slot] == 1) {
int i;
int antenna = 0;
uint16_t *in;
uint16_t *out;
in = (uint16_t *)s->buffers.prach[*slot];
out = (uint16_t *)ru->prach_rxsigF[antenna];
for (i = 0; i < 839*2; i++)
out[i] = ntohs(in[i]);
s->buffers.prach_busy[*slot] = 0;
//printf("prach for f.sl %d.%d\n", *frame, *slot);
//ru->wakeup_prach_gNB(ru->gNB_list[0], ru, *frame, *slot);
goto next;
}
#endif
fp = ru->nr_frame_parms;
for (symbol = 0; symbol < 14; symbol++) {
int i;
uint16_t *p = (uint16_t *)(&s->buffers.ul[*slot][symbol*1272*4]);
for (i = 0; i < 1272*2; i++) {
p[i] = htons(p[i]);
}
rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(rxdata + 2048 - 1272/2,
&s->buffers.ul[*slot][symbol*1272*4],
(1272/2) * 4);
memcpy(rxdata,
&s->buffers.ul[*slot][symbol*1272*4] + (1272/2)*4,
(1272/2) * 4);
#endif
}
s->buffers.ul_busy[*slot] = 0;
signal_ul_buffer(&s->buffers, *slot);
unlock_ul_buffer(&s->buffers, *slot);
//printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *slot);
RU_proc_t *proc = &ru->proc;
extern uint16_t sl_ahead;
int f = *frame;
int sl = *slot;
//calculate timestamp_rx, timestamp_tx based on frame and slot
proc->tti_rx = sl;
proc->frame_rx = f;
/* TODO: be sure of samples_per_slot0
FK: should use get_samples_per_slot(slot)
but for mu=1 its ok
*/
proc->timestamp_rx = ((proc->frame_rx * 20) + proc->tti_rx ) * fp->samples_per_slot0;
if (get_nprocs()<=4) {
// why? what if there are more?
proc->tti_tx = (sl+sl_ahead)%20;
proc->frame_tx = (sl>(19-sl_ahead)) ? (f+1)&1023 : f;
}
}
void benetel_fh_if4p5_south_out(RU_t *ru,
int frame,
int slot,
uint64_t timestamp)
{
//printf("XXX benetel_fh_if4p5_south_out %d %d %ld\n", frame, slot, timestamp);
benetel_eth_state_t *s = ru->ifdevice.priv;
NR_DL_FRAME_PARMS *fp;
int symbol;
int32_t *txdata;
int aa = 0;
//printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, slot, timestamp);
lock_dl_buffer(&s->buffers, slot);
if (s->buffers.dl_busy[slot]) {
printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, slot);
unlock_dl_buffer(&s->buffers, slot);
return;
}
fp = ru->nr_frame_parms;
if (ru->num_gNB != 1 || ru->nb_tx != 1 || fp->ofdm_symbol_size != 2048 ||
fp->Ncp != NORMAL || fp->symbols_per_slot != 14) {
printf("%s:%d:%s: unsupported configuration\n",
__FILE__, __LINE__, __FUNCTION__);
exit(1);
}
for (symbol = 0; symbol < 14; symbol++) {
txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(&s->buffers.dl[slot][symbol*1272*4],
txdata + 2048 - (1272/2),
(1272/2) * 4);
memcpy(&s->buffers.dl[slot][symbol*1272*4] + (1272/2)*4,
txdata,
(1272/2) * 4);
#endif
int i;
uint16_t *p = (uint16_t *)(&s->buffers.dl[slot][symbol*1272*4]);
for (i = 0; i < 1272*2; i++) {
p[i] = htons(p[i]);
}
}
s->buffers.dl_busy[slot] = 0x3fff;
unlock_dl_buffer(&s->buffers, slot);
}
void *get_internal_parameter(char *name)
{
printf("BENETEL: %s\n", __FUNCTION__);
if (!strcmp(name, "fh_if4p5_south_in"))
return benetel_fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return benetel_fh_if4p5_south_out;
return NULL;
}
__attribute__((__visibility__("default")))
int transport_init(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t * eth_params )
{
benetel_eth_state_t *eth;
printf("BENETEL: %s\n", __FUNCTION__);
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_benetel_start;
device->trx_get_stats_func = trx_benetel_get_stats;
device->trx_reset_stats_func = trx_benetel_reset_stats;
device->trx_end_func = trx_benetel_end;
device->trx_stop_func = trx_benetel_stop;
device->trx_set_freq_func = trx_benetel_set_freq;
device->trx_set_gains_func = trx_benetel_set_gains;
device->trx_write_func = trx_benetel_write_raw;
device->trx_read_func = trx_benetel_read_raw;
device->trx_ctlsend_func = trx_benetel_ctlsend;
device->trx_ctlrecv_func = trx_benetel_ctlrecv;
device->get_internal_parameter = get_internal_parameter;
eth = calloc(1, sizeof(benetel_eth_state_t));
if (eth == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
device->priv = eth;
device->openair0_cfg=&openair0_cfg[0];
if (openair0_cfg->sdr_addrs == NULL) {
printf("benetel: fatal: sdr_addrs not set in configuration file\n");
exit(1);
}
eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs);
if (eth->dpdk_main_command_line == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->last_msg = -1;
init_buffers(&eth->buffers);
return 0;
}
/* license: to be defined */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include "low.h"
// HEADER DEFINITION
#define ANT_NUM buf[23]
#define PAYLOAD_1 buf[20]
#define PAYLOAD_2 buf[21]
#define ETH_TYPE buf[17]
#define SYMBOL buf[29]
#define SUBFRAME buf[28]
#define FRAME buf[27]
static volatile bool force_quit;
unsigned short iq[712320];
unsigned char iq_swap[1424640];
unsigned short *iq_ptr[14];
unsigned int dl_start = 0, slot_id_ctrl = 0, count_symbol = 0, sf = 0x10;
/* MAC updating enabled by default */
static int mac_updating = 1;
#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */
#define MEMPOOL_CACHE_SIZE 256
/*
* Configurable number of RX/TX ring descriptors
*/
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/* ethernet addresses of ports */
static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;
/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
static unsigned int l2fwd_rx_queue_per_lcore = 1;
#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf {
unsigned n_rx_port;
unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
} __rte_cache_aligned;
struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME,
.split_hdr_size = 0,
.max_rx_pkt_len = 9500,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
/* Per-port statistics struct */
struct l2fwd_port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
static uint64_t timer_period = 10; /* default period is 10 seconds */
/* Print out statistics on packets dropped */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
unsigned portid;
total_packets_dropped = 0;
total_packets_tx = 0;
total_packets_rx = 0;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
/* Clear screen and move to top left */
printf("%s%s", clr, topLeft);
printf("\nPort statistics ====================================");
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
/* skip disabled ports */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
"\nPackets sent: %24"PRIu64
"\nPackets received: %20"PRIu64
"\nPackets dropped: %21"PRIu64,
portid,
port_statistics[portid].tx,
port_statistics[portid].rx,
port_statistics[portid].dropped);
total_packets_dropped += port_statistics[portid].dropped;
total_packets_tx += port_statistics[portid].tx;
total_packets_rx += port_statistics[portid].rx;
}
printf("\nAggregate statistics ==============================="
"\nTotal packets sent: %18"PRIu64
"\nTotal packets received: %14"PRIu64
"\nTotal packets dropped: %15"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
}
static void
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs)
{
unsigned char *buf, *buf_tx;
unsigned int len;
struct ether_hdr *eth;
unsigned dst_port;
int sent, prach_ctrl = 0;
struct rte_eth_dev_tx_buffer *buffer;
unsigned char * IQ_ptr;
ul_packet_t p;
buf = rte_pktmbuf_mtod(m, unsigned char *);
//DD Debug
//rte_memdump(stdout, "Rx Packet",buf ,34);
eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
len = rte_pktmbuf_data_len(m);
IQ_ptr = &buf[34];
if (portid == 0)
{
//destination mac address (RRU MAC)
/*eth->d_addr.addr_bytes[0] = 0x02;
eth->d_addr.addr_bytes[1] = 0x00;
eth->d_addr.addr_bytes[2] = 0x5e;
eth->d_addr.addr_bytes[3] = 0x01;
eth->d_addr.addr_bytes[4] = 0x01;
eth->d_addr.addr_bytes[5] = 0x01;*/
eth->d_addr.addr_bytes[0] = buf[6];
eth->d_addr.addr_bytes[1] = buf[7];
eth->d_addr.addr_bytes[2] = buf[8];
eth->d_addr.addr_bytes[3] = buf[9];
eth->d_addr.addr_bytes[4] = buf[10];
eth->d_addr.addr_bytes[5] = buf[11];
//source mac address (DU MAC)
eth->s_addr.addr_bytes[0] = 0xdd;
eth->s_addr.addr_bytes[1] = 0xdd;
eth->s_addr.addr_bytes[2] = 0xdd;
eth->s_addr.addr_bytes[3] = 0xdd;
eth->s_addr.addr_bytes[4] = 0xdd;
eth->s_addr.addr_bytes[5] = 0xdd;
}
else
{
//destination mac address (RRU MAC)
/*eth->d_addr.addr_bytes[0] = 0x02;
eth->d_addr.addr_bytes[1] = 0x00;
eth->d_addr.addr_bytes[2] = 0x5e;
eth->d_addr.addr_bytes[3] = 0x01;
eth->d_addr.addr_bytes[4] = 0x01;
eth->d_addr.addr_bytes[5] = 0x01;*/
eth->d_addr.addr_bytes[0] = buf[6];
eth->d_addr.addr_bytes[1] = buf[7];
eth->d_addr.addr_bytes[2] = buf[8];
eth->d_addr.addr_bytes[3] = buf[9];
eth->d_addr.addr_bytes[4] = buf[10];
eth->d_addr.addr_bytes[5] = buf[11];
//source mac address (DU MAC)
eth->s_addr.addr_bytes[0] = 0xdd;
eth->s_addr.addr_bytes[1] = 0xdd;
eth->s_addr.addr_bytes[2] = 0xdd;
eth->s_addr.addr_bytes[3] = 0xdd;
eth->s_addr.addr_bytes[4] = 0xdd;
eth->s_addr.addr_bytes[5] = 0xde;
}
dst_port = l2fwd_dst_ports[portid];
//DD Debug
//printf("dstPort =%d\n", dst_port);
// Handshake Condition
if (buf[18] == 0xAA ) // ORAN handshake msgs.
{
printf("\n Start UP Request Received\n");
printf("\n====================================================\n");
buf[18] = 0xBB;//change to msg2 after receive msg1
printf(" Start Up Response Sent\n");
printf("\n====================================================\n");
}
// Trigger start send DL packets
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && SYMBOL == 0x46 && ANT_NUM == 0x00 && SUBFRAME == 0x00 && dl_start == 0){
printf("\nU-Plane Started\n");
printf("\n====================================================\n");
dl_start = 1;
count_symbol = 28;
}
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x00) {
int subframe = SUBFRAME >> 4;
int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
p.frame = FRAME;
p.slot = subframe * 2 + slot;
p.symbol = SYMBOL & 0x3f;
p.antenna = 0;
memcpy(p.iq, IQ_ptr, 5088);
store_ul(bs, &p);
//if (p.symbol==0) printf("store ul f.sl.sy %d.%d.%d\n", p.frame, p.slot, p.symbol);
}
// U-PLANE UL ANT_0 PROCESSING
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x00 && dl_start == 1)
{
int frame = FRAME;
int subframe = SUBFRAME >> 4;
int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
int symbol = SYMBOL & 0x3f;
int oai_slot;
int tx_frame = frame;
int tx_subframe = subframe;
int tx_slot = slot;
int tx_symbol = symbol + 8;
if (tx_symbol > 13) {
tx_symbol -= 14;
tx_slot++;
if (tx_slot == 2) {
tx_slot = 0;
tx_subframe++;
if (tx_subframe == 10) {
tx_subframe = 0;
tx_frame = (tx_frame + 1) & 255;
}
}
}
ANT_NUM = 0x00;
// Mask the symbol bits from UL packet received and apply the shift.
SYMBOL = ((SYMBOL & 0b00111111) + 8) % 14;
ANT_NUM = 0x00;
SUBFRAME = sf;
// Slot id control for DL
if(slot_id_ctrl > 13){
SYMBOL = SYMBOL | 0b01000000;
}
/* antenna 0 - send actual DL data (if available) */
oai_slot = tx_subframe * 2 + tx_slot;
lock_dl_buffer(bs->buffers, oai_slot);
if (!(bs->buffers->dl_busy[oai_slot] & (1 << tx_symbol))) {
printf("%s: warning, DL underflow (sl.symbol %d.%d)\n", __FUNCTION__,
oai_slot, tx_symbol);
memset(IQ_ptr, 0, 1272 * 4);
} else {
memcpy(IQ_ptr, bs->buffers->dl[oai_slot] + tx_symbol * 1272*4,
1272*4);
}
bs->buffers->dl_busy[oai_slot] &= ~(1 << tx_symbol);
unlock_dl_buffer(bs->buffers, oai_slot);
// fill DL Data for ant 0 with 0 value
// memset(IQ_ptr, 0, 5088);
}
// U-PLANE UL ANT_1 PROCESSING
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x01 && dl_start == 1)
{
// Mask the symbol bits from UL packet received and apply the shift.
SYMBOL = ((SYMBOL & 0b00111111) + 8) % 14;
ANT_NUM = 0x01;
SUBFRAME = sf;
slot_id_ctrl++;
// Slot id control for DL
if(slot_id_ctrl > 13){
SYMBOL = SYMBOL | 0b01000000;
if(slot_id_ctrl > 27){
slot_id_ctrl = 0;
sf = sf + 0x10;
if (sf >0x90){
sf = 0;
}
}
}
// fill DL Data for ant 1 with 0 value
memset(IQ_ptr, 0, 5088);
}
// U-PLANE PRACH PROCESSING
else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){
if (ANT_NUM == 0) {
int subframe = SUBFRAME >> 4;
int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
if (subframe==9) {
//printf("store prach f.sf.sl %d.%d.%d %d\n", FRAME, subframe, slot, subframe * 2 + slot);
store_prach(bs, FRAME, slot /*subframe * 2 + slot*/, IQ_ptr);
}
}
rte_pktmbuf_free(m);
return;
}
// Send Packets
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
/* main processing loop */
static void
l2fwd_main_loop(benetel_t *bs)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on master core */
if (lcore_id == rte_get_master_lcore()) {
print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid, bs);
}
}
}
}
static int
l2fwd_launch_one_lcore(void *bs)
{
l2fwd_main_loop(bs);
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (pm == 0)
return -1;
return pm;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case 0:
break;
case 'proc-type':
break;
case 'socket-mem':
break;
case 'file-prefix':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
/* timer period */
/* timer period */
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
rte_eth_link_get_nowait(portid, &link);
/* print link status if flag set */
if (print_flag == 1) {
if (link.link_status)
printf(
"Port%d Link Up. Speed %u Mbps - %s\n",
portid, link.link_speed,
(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
("full-duplex") : ("half-duplex\n"));
else
printf("Port %d Link Down\n", portid);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
dpdk_main(int argc, char **argv, benetel_t *bs)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/*
* Each logical core is assigned a dedicated TX queue on each port.
*/
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
}
else
last_port = portid;
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
//DD Debug
//printf ("Proc Type %d \n", rte_eal_process_type());
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, 9680,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
rte_eth_dev_info_get(portid, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
rte_eth_promiscuous_enable(portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER);
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
rte_eth_dev_stop(portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
return ret;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "low.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void store_ul(benetel_t *bs, ul_packet_t *ul)
{
/* only antenna 0 for the moment */
if (ul->antenna != 0)
return;
if (ul->slot != bs->next_slot ||
ul->symbol != bs->next_symbol) {
printf("%s: fatal, expected frame.sl.symbol %d.%d.%d, got %d.%d.%d\n",
__FUNCTION__,
bs->expected_benetel_frame, bs->next_slot, bs->next_symbol,
ul->frame, ul->slot, ul->symbol);
exit(1);
}
lock_ul_buffer(bs->buffers, bs->next_slot);
if (bs->buffers->ul_busy[bs->next_slot] & (1 << bs->next_symbol)) {
printf("%s: warning, UL overflow (sl.symbol %d.%d)\n", __FUNCTION__,
bs->next_slot, bs->next_symbol);
}
memcpy(bs->buffers->ul[bs->next_slot] + bs->next_symbol * 1272*4,
ul->iq, 1272*4);
bs->buffers->ul_busy[bs->next_slot] |= (1 << bs->next_symbol);
signal_ul_buffer(bs->buffers, bs->next_slot);
unlock_ul_buffer(bs->buffers, bs->next_slot);
bs->next_symbol++;
if (bs->next_symbol == 14) {
bs->next_symbol = 0;
bs->next_slot = (bs->next_slot + 1) % 20;
if (bs->next_slot == 0) {
bs->expected_benetel_frame++;
bs->expected_benetel_frame &= 255;
}
}
}
void store_prach(benetel_t *bs, int frame, int slot, void *data)
{
static int last_frame = -1;
static int last_slot = -1;
/* hack: antenna number is always 0, discard second packet with same f/sf */
//if (frame == last_frame && slot == last_slot) return;
if (frame == last_frame && slot == last_slot) { printf("got f.sl %d.%d twice\n", frame, slot); return; }
last_frame = frame;
last_slot = slot;
lock_ul_buffer(bs->buffers, slot);
if (bs->buffers->prach_busy[slot]) {
printf("store_prach: fatal: previous prach buffer not processed\n");
unlock_ul_buffer(bs->buffers, slot);
return;
}
bs->buffers->prach_busy[slot] = 1;
memcpy(bs->buffers->prach[slot], data, 839*4);
signal_ul_buffer(bs->buffers, slot);
unlock_ul_buffer(bs->buffers, slot);
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
if (!strcmp(ifname, "dpdk"))
return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line);
printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname);
exit(1);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _BENETEL_LOW_H_
#define _BENETEL_LOW_H_
#include "shared_buffers.h"
typedef struct {
shared_buffers *buffers;
int next_slot;
int next_symbol;
int expected_benetel_frame;
char *dpdk_main_command_line;
} benetel_t;
typedef struct {
int frame;
int slot;
int symbol;
int antenna;
unsigned char iq[5088];
} ul_packet_t;
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void store_ul(benetel_t *bs, ul_packet_t *ul);
void store_prach(benetel_t *bs, int frame, int slot, void *data);
#endif /* _BENETEL_LOW_H_ */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* those 2 lines for CPU_SET */
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "low.h"
int dpdk_main(int argc, char **argv, benetel_t *);
void *dpdk_thread(void *_bs)
{
benetel_t *bs = _bs;
int n = 0;
char **v = NULL; // = { "softmodem", "-n", "2", "--file-prefix", "pg2", "-l", "6", "--", "-p", "0x1" };
char *s = bs->dpdk_main_command_line;
char *tok;
while ((tok = strtok(s, " ")) != NULL) {
n++;
v = realloc(v, n * sizeof(char *));
if (v == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
v[n-1] = tok;
s = NULL;
}
dpdk_main(n, v, bs);
exit(1);
return 0;
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
benetel_t *bs;
bs = calloc(1, sizeof(benetel_t));
if (bs == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
bs->buffers = buffers;
bs->expected_benetel_frame = 255;
bs->dpdk_main_command_line = dpdk_main_command_line;
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(10,&cpuset);
if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) {
printf("pthread_attr_setaffinity_np failed\n");
exit(1);
}
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
printf("pthread_attr_setschedpolicy failed\n");
exit(1);
}
struct sched_param params;
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_get_priority_max(SCHED_FIFO) == -1) {
printf("sched_get_priority_max failed\n");
exit(1);
}
if (pthread_attr_setschedparam(&attr, &params) != 0) {
printf("pthread_setschedparam failed\n");
exit(1);
}
pthread_t t;
if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) {
printf("%s: thread creation failed\n", __FUNCTION__);
exit(1);
}
if (pthread_attr_destroy(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
return bs;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "shared_buffers.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init_buffers(shared_buffers *s)
{
int slot;
memset(s, 0, sizeof(*s));
for (slot = 0; slot < 20; slot++) {
if (pthread_mutex_init(&s->m_dl[slot], NULL) != 0 ||
pthread_cond_init(&s->c_dl[slot], NULL) != 0 ||
pthread_mutex_init(&s->m_ul[slot], NULL) != 0 ||
pthread_cond_init(&s->c_ul[slot], NULL) != 0) {
printf("%s: error initializing mutex/cond\n", __FUNCTION__);
exit(1);
}
}
/* the gNB's first transmitted DL slot is 6 but the device
* needs to have slots 1, 2 and 3, 4 and 5 ready. Let's pretend
* they are ready.
*/
s->dl_busy[1] = 0x3fff;
s->dl_busy[2] = 0x3fff;
s->dl_busy[3] = 0x3fff;
s->dl_busy[4] = 0x3fff;
s->dl_busy[5] = 0x3fff;
}
void lock_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_lock(&s->m_dl[slot]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
exit(1);
}
}
void unlock_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_unlock(&s->m_dl[slot]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_wait(&s->c_dl[slot], &s->m_dl[slot]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_broadcast(&s->c_dl[slot]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
void lock_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_lock(&s->m_ul[slot]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
printf("%s: fatal: lock fails slot %d\n", __FUNCTION__, slot);
exit(1);
}
}
void unlock_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_unlock(&s->m_ul[slot]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_wait(&s->c_ul[slot], &s->m_ul[slot]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_broadcast(&s->c_ul[slot]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _SHARED_BUFFERS_H_
#define _SHARED_BUFFERS_H_
#include <pthread.h>
#include <stdint.h>
typedef struct {
unsigned char dl[20][14*1272*4];
unsigned char ul[20][14*1272*4];
uint16_t dl_busy[20];
uint16_t ul_busy[20];
pthread_mutex_t m_ul[20];
pthread_cond_t c_ul[20];
pthread_mutex_t m_dl[20];
pthread_cond_t c_dl[20];
unsigned char prach[20][849*4];
unsigned char prach_busy[20];
/* statistics/error counting */
int ul_overflow;
int dl_underflow;
} shared_buffers;
void init_buffers(shared_buffers *s);
void lock_dl_buffer(shared_buffers *s, int slot);
void unlock_dl_buffer(shared_buffers *s, int slot);
void wait_dl_buffer(shared_buffers *s, int slot);
void signal_dl_buffer(shared_buffers *s, int slot);
void lock_ul_buffer(shared_buffers *s, int slot);
void unlock_ul_buffer(shared_buffers *s, int slot);
void wait_ul_buffer(shared_buffers *s, int slot);
void signal_ul_buffer(shared_buffers *s, int slot);
#endif /* _SHARED_BUFFERS_H_ */
Active_eNBs = ( "eNB-Eurecom-LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
# real_time choice in {hard, rt-preempt, no}
real_time = "no";
////////// Identification parameters:
eNB_ID = 0xe00;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB-Eurecom-LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ( { mcc = 222; mnc = 01; mnc_length = 2; } );
tr_s_preference = "local_mac"
////////// Physical parameters:
component_carriers = (
{
node_function = "NGFI_RCC_IF4p5";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2655000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 0;
N_RB_DL = 100;
Nid_cell_mbsfn = 0;
nb_antenna_ports = 1;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
tx_gain = 90;
rx_gain = 125;
pbch_repetition = "FALSE";
prach_root = 0;
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 90;
pucch_delta_shift = 1;
pucch_nRB_CQI = 0;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -10;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -96;
pusch_alpha = "AL1";
pucch_p0_Nominal = -104;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
ue_TransmissionMode = 1;
//Parameters for SIB18
rxPool_sc_CP_Len = "normal";
rxPool_sc_Period = "sf40";
rxPool_data_CP_Len = "normal";
rxPool_ResourceConfig_prb_Num = 20;
rxPool_ResourceConfig_prb_Start = 5;
rxPool_ResourceConfig_prb_End = 44;
rxPool_ResourceConfig_offsetIndicator_present = "prSmall";
rxPool_ResourceConfig_offsetIndicator_choice = 0;
rxPool_ResourceConfig_subframeBitmap_present = "prBs40";
rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000";
rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5;
rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
/* rxPool_dataHoppingConfig_hoppingParameter = 0;
rxPool_dataHoppingConfig_numSubbands = "ns1";
rxPool_dataHoppingConfig_rbOffset = 0;
rxPool_commTxResourceUC-ReqAllowed = "TRUE";
*/
// Parameters for SIB19
discRxPool_cp_Len = "normal"
discRxPool_discPeriod = "rf32"
discRxPool_numRetx = 1;
discRxPool_numRepetition = 2;
discRxPool_ResourceConfig_prb_Num = 5;
discRxPool_ResourceConfig_prb_Start = 3;
discRxPool_ResourceConfig_prb_End = 21;
discRxPool_ResourceConfig_offsetIndicator_present = "prSmall";
discRxPool_ResourceConfig_offsetIndicator_choice = 0;
discRxPool_ResourceConfig_subframeBitmap_present = "prBs40";
discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff";
discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5;
discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.168.61.195";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
enable_measurement_reports = "no";
///X2
enable_x2 = "yes";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.160.46";
ENB_INTERFACE_NAME_FOR_S1U = "eth0";
ENB_IPV4_ADDRESS_FOR_S1U = "192.168.160.46";
ENB_PORT_FOR_S1U = 2152; # Spec 2152
ENB_IPV4_ADDRESS_FOR_X2C = "127.0.0.1";
ENB_PORT_FOR_X2C = 36422; # Spec 36422
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 150;
}
);
RUs = (
{
//local_if_name = "enp129s0f0";
local_if_name = "dpdk";
sdr_addrs = "softmodem -m 2048 -l 8 -n 2 -b 0000:3b:00.0 --proc-type auto --file-prefix ggg -- -p 0x1";
#sdr_addrs = "softmodem -l 8 -n 2 -- -p 0x2";
remote_address = "127.0.0.2";
local_address = "127.0.0.1";
local_portc = 50000;
remote_portc = 50000;
local_portd = 50001;
remote_portd = 50001;
local_rf = "no"
tr_preference = "raw_if4p5"
nb_tx = 1
nb_rx = 1
att_tx = 0
att_rx = 0;
eNB_instances = [0];
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
#parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
NETWORK_CONTROLLER :
{
FLEXRAN_ENABLED = "no";
FLEXRAN_INTERFACE_NAME = "lo";
FLEXRAN_IPV4_ADDRESS = "127.0.0.1";
FLEXRAN_PORT = 2210;
FLEXRAN_CACHE = "/mnt/oai_agent_cache";
FLEXRAN_AWAIT_RECONF = "no";
};
log_config :
{
global_log_level ="info";
global_log_verbosity ="medium";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="info";
rlc_log_verbosity ="medium";
pdcp_log_level ="info";
pdcp_log_verbosity ="medium";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
Active_gNBs = ( "gNB-Eurecom-5GNRBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
cell_type = "CELL_MACRO_GNB";
gNB_name = "gNB-Eurecom-5GNRBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({mcc = 222; mnc = 01; mnc_length = 2;});
tr_s_preference = "local_mac"
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
pdsch_AntennaPorts = 1;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is is the central frequency of SSB
absoluteFrequencySSB = 640000; //641272
dl_frequencyBand = 78;
# the carrier frequency is assumed to be in the middle of the carrier, i.e. dl_absoluteFrequencyPointA_kHz + dl_carrierBandwidth*12*SCS_kHz/2
dl_absoluteFrequencyPointA = 638728; //640000;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=84,L=13 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 6366; //28875; //6366; #6407; #3384;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 0;
initialDLBWPsearchSpaceZero = 0;
#pdsch-ConfigCommon
#pdschTimeDomainAllocationList (up to 16 entries)
initialDLBWPk0_0 = 0;
#initialULBWPmappingType
#0=typeA,1=typeB
initialDLBWPmappingType_0 = 0;
#this is SS=1,L=13
initialDLBWPstartSymbolAndLength_0 = 40;
initialDLBWPk0_1 = 0;
initialDLBWPmappingType_1 = 0;
#this is SS=2,L=12
initialDLBWPstartSymbolAndLength_1 = 53;
initialDLBWPk0_2 = 0;
initialDLBWPmappingType_2 = 0;
#this is SS=1,L=12
initialDLBWPstartSymbolAndLength_2 = 54;
initialDLBWPk0_3 = 0;
initialDLBWPmappingType_3 = 0;
#this is SS=1,L=4 //5 (4 is for 43, 5 is for 57)
initialDLBWPstartSymbolAndLength_3 = 57; //43; //57;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 78;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 6366; //28875; //6366; #6407; #3384;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 4;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 74;
zeroCorrelationZoneConfig = 13;
#preambleReceivedTargetPower = -118;
preambleReceivedTargetPower = -104;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 6;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#oneHalf (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; //15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 1;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
#msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# pusch-ConfigCommon (up to 16 elements)
initialULBWPk2_0 = 2;
initialULBWPmappingType_0 = 1
# this is SS=0 L=11
initialULBWPstartSymbolAndLength_0 = 55;
initialULBWPk2_1 = 2;
initialULBWPmappingType_1 = 1;
# this is SS=0 L=12
initialULBWPstartSymbolAndLength_1 = 69;
initialULBWPk2_2 = 7;
initialULBWPmappingType_2 = 1;
# this is SS=10 L=4
initialULBWPstartSymbolAndLength_2 = 52;
msg3_DeltaPreamble = 1;
p0_NominalWithGrant =-90;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 40;
p0_nominal = -90;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
ssb_PositionsInBurst_Bitmap = 1; #0x80;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 6;
nrofDownlinkSlots = 7; //8; //7;
nrofDownlinkSymbols = 6; //0; //6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4; //0; //4;
#ssPBCH_BlockPower = 10;
ssPBCH_BlockPower = 10;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.168.61.195";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
///X2
enable_x2 = "yes";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
target_enb_x2_ip_address = (
{ ipv4 = "127.0.0.1";
ipv6 = "192:168:30::17";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_S1_MME = "eth0";
GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.160.146/24";
GNB_INTERFACE_NAME_FOR_S1U = "eth0";
GNB_IPV4_ADDRESS_FOR_S1U = "192.168.160.146/24";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
GNB_IPV4_ADDRESS_FOR_X2C = "127.0.0.2/24";
GNB_PORT_FOR_X2C = 36422; # Spec 36422
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
}
);
RUs = (
{
local_rf = "no"
nb_tx = 1
nb_rx = 1
att_tx = 0
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
eNB_instances = [0];
//clock_src = "internal";
clock_src = "external";
local_if_name = "dpdk";
sdr_addrs = "softmodem -m 2048 -l 6 -n 3 -b 0000:3b:00.1 --proc-type auto --file-prefix hhh -- -p 0x1";
remote_address = "127.0.0.2";
local_address = "127.0.0.1";
local_portc = 50000;
remote_portc = 50000;
local_portd = 50001;
remote_portd = 50001;
tr_preference = "raw_if4p5"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
//parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_DISABLE";
}
);
log_config :
{
global_log_level ="info";
global_log_verbosity ="medium";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="info";
rlc_log_verbosity ="medium";
pdcp_log_level ="info";
pdcp_log_verbosity ="medium";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
......@@ -2675,6 +2675,15 @@ void set_function_spec_param(RU_t *ru) {
exit(-1);
}
if (ru->ifdevice.get_internal_parameter != NULL) {
void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
if (t != NULL)
ru->fh_south_in = t;
t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
if (t != NULL)
ru->fh_south_out = t;
}
malloc_IF4p5_buffer(ru);
break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment