Remove Benetel radio drivers
These drivers are superseded by the O-RAN 7.2 FHI.
This commit is contained in:
@@ -92,7 +92,7 @@ Options:
|
|||||||
USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default)
|
USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default)
|
||||||
Adds this RF board support (in external packages installation and in compilation)
|
Adds this RF board support (in external packages installation and in compilation)
|
||||||
-t | --transport
|
-t | --transport
|
||||||
Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS
|
Selects the transport protocol type, options: None, Ethernet, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS
|
||||||
-P | --phy_simulators
|
-P | --phy_simulators
|
||||||
Makes the unitary tests Layer 1 simulators
|
Makes the unitary tests Layer 1 simulators
|
||||||
-V | --vcd
|
-V | --vcd
|
||||||
@@ -278,7 +278,7 @@ function main() {
|
|||||||
TARGET_LIST="$TARGET_LIST oai_eth_transpro"
|
TARGET_LIST="$TARGET_LIST oai_eth_transpro"
|
||||||
CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase
|
CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase
|
||||||
;;
|
;;
|
||||||
"benetel4g" | "benetel5g" | "oran_fhlib_4g")
|
"oran_fhlib_4g")
|
||||||
TARGET_LIST="$TARGET_LIST $2"
|
TARGET_LIST="$TARGET_LIST $2"
|
||||||
CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase
|
CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -9,5 +9,3 @@ set_target_properties(oai_eth_transpro PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMA
|
|||||||
add_custom_command(TARGET oai_eth_transpro POST_BUILD
|
add_custom_command(TARGET oai_eth_transpro POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E create_symlink liboai_eth_transpro.so liboai_transpro.so
|
COMMAND ${CMAKE_COMMAND} -E create_symlink liboai_eth_transpro.so liboai_transpro.so
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
add_subdirectory(benetel)
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
pkg_check_modules(libdpdk REQUIRED libdpdk=20.05.0)
|
|
||||||
|
|
||||||
add_library(benetel_4g MODULE
|
|
||||||
benetel.c
|
|
||||||
shared_buffers.c
|
|
||||||
low.c
|
|
||||||
low_dpdk.c
|
|
||||||
dpdk_driver.c
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_definitions(benetel_4g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -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_include_directories(benetel_4g PRIVATE ${libdpdk_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(benetel_4g PRIVATE ${libdpdk_LIBRARIES})
|
|
||||||
target_link_libraries(benetel_4g PRIVATE pthread dl rt m numa)
|
|
||||||
set_target_properties(benetel_4g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
||||||
add_custom_command(TARGET benetel_4g POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E create_symlink libbenetel_4g.so liboai_transpro.so
|
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
||||||
@@ -1,392 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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] = device->openair0_cfg->rx_num_channels;
|
|
||||||
cap->nb_tx[0] = device->openair0_cfg->tx_num_channels;
|
|
||||||
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;
|
|
||||||
|
|
||||||
lock_ul_buffer(&s->buffers, *subframe);
|
|
||||||
next:
|
|
||||||
while (!((s->buffers.ul_busy[0][*subframe] == 0x3fff &&
|
|
||||||
s->buffers.ul_busy[1][*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[0][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 (antenna = 0; antenna < ru->nb_rx; antenna++) {
|
|
||||||
for (symbol = 0; symbol < 14; symbol++) {
|
|
||||||
int i;
|
|
||||||
uint16_t *p = (uint16_t *)(&s->buffers.ul[antenna][*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[antenna][*subframe][symbol*1200*4],
|
|
||||||
600 * 4);
|
|
||||||
memcpy(rxdata,
|
|
||||||
&s->buffers.ul[antenna][*subframe][symbol*1200*4] + 600*4,
|
|
||||||
600 * 4);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s->buffers.ul_busy[0][*subframe] = 0;
|
|
||||||
s->buffers.ul_busy[1][*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 int 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;
|
|
||||||
|
|
||||||
//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[0][subframe] ||
|
|
||||||
s->buffers.dl_busy[1][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 || 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 (aa = 0; aa < ru->nb_tx; aa++) {
|
|
||||||
for (symbol = 0; symbol < 14; symbol++) {
|
|
||||||
txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
|
|
||||||
#if 1
|
|
||||||
memcpy(&s->buffers.dl[aa][subframe][symbol*1200*4],
|
|
||||||
txdata + 2048 - 600,
|
|
||||||
600 * 4);
|
|
||||||
memcpy(&s->buffers.dl[aa][subframe][symbol*1200*4] + 600*4,
|
|
||||||
txdata + 1,
|
|
||||||
600 * 4);
|
|
||||||
#endif
|
|
||||||
int i;
|
|
||||||
uint16_t *p = (uint16_t *)(&s->buffers.dl[aa][subframe][symbol*1200*4]);
|
|
||||||
for (i = 0; i < 1200*2; i++) {
|
|
||||||
p[i] = htons(p[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s->buffers.dl_busy[0][subframe] = 0x3fff;
|
|
||||||
s->buffers.dl_busy[1][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(ð->buffers);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,774 +0,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_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) {
|
|
||||||
p.frame = FRAME;
|
|
||||||
p.subframe = SUBFRAME >> 4;
|
|
||||||
p.slot = 0; /* unused */
|
|
||||||
p.symbol = SYMBOL;
|
|
||||||
p.antenna = ANT_NUM;
|
|
||||||
memcpy(p.iq, IQ_ptr, 4800);
|
|
||||||
store_ul(bs, &p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// U-PLANE UL PROCESSING
|
|
||||||
if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && dl_start == 1)
|
|
||||||
{
|
|
||||||
int a = ANT_NUM;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* send actual DL data (if available) */
|
|
||||||
lock_dl_buffer(bs->buffers, tx_subframe);
|
|
||||||
if (!(bs->buffers->dl_busy[a][tx_subframe] & (1 << tx_symbol))) {
|
|
||||||
printf("%s: warning, DL underflow (antenna %d sf.symbol %d.%d)\n",
|
|
||||||
__FUNCTION__,
|
|
||||||
a,
|
|
||||||
tx_subframe, tx_symbol);
|
|
||||||
memset(IQ_ptr, 0, 1200 * 4);
|
|
||||||
} else {
|
|
||||||
memcpy(IQ_ptr, bs->buffers->dl[a][tx_subframe] + tx_symbol * 1200*4,
|
|
||||||
1200*4);
|
|
||||||
}
|
|
||||||
bs->buffers->dl_busy[a][tx_subframe] &= ~(1 << tx_symbol);
|
|
||||||
unlock_dl_buffer(bs->buffers, tx_subframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
int a = ul->antenna;
|
|
||||||
|
|
||||||
if (ul->subframe != bs->next_subframe[a] ||
|
|
||||||
ul->symbol != bs->next_symbol[a]) {
|
|
||||||
printf("%s: fatal, antenna %d expected frame.sf.symbol %d.%d.%d, got %d.%d.%d\n",
|
|
||||||
__FUNCTION__,
|
|
||||||
a,
|
|
||||||
bs->expected_benetel_frame[a], bs->next_subframe[a], bs->next_symbol[a],
|
|
||||||
ul->frame, ul->subframe, ul->symbol);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock_ul_buffer(bs->buffers, bs->next_subframe[a]);
|
|
||||||
if (bs->buffers->ul_busy[a][bs->next_subframe[a]] & (1 << bs->next_symbol[a])) {
|
|
||||||
printf("%s: warning, UL overflow (sf.symbol %d.%d)\n", __FUNCTION__,
|
|
||||||
bs->next_subframe[a], bs->next_symbol[a]);
|
|
||||||
}
|
|
||||||
memcpy(bs->buffers->ul[a][bs->next_subframe[a]] + bs->next_symbol[a] * 1200*4,
|
|
||||||
ul->iq, 1200*4);
|
|
||||||
bs->buffers->ul_busy[a][bs->next_subframe[a]] |= (1 << bs->next_symbol[a]);
|
|
||||||
signal_ul_buffer(bs->buffers, bs->next_subframe[a]);
|
|
||||||
unlock_ul_buffer(bs->buffers, bs->next_subframe[a]);
|
|
||||||
|
|
||||||
bs->next_symbol[a]++;
|
|
||||||
if (bs->next_symbol[a] == 14) {
|
|
||||||
bs->next_symbol[a] = 0;
|
|
||||||
bs->next_subframe[a] = (bs->next_subframe[a] + 1) % 10;
|
|
||||||
if (bs->next_subframe[a] == 0) {
|
|
||||||
bs->expected_benetel_frame[a]++;
|
|
||||||
bs->expected_benetel_frame[a] &= 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);
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_4G_LOW_H_
|
|
||||||
#define _BENETEL_4G_LOW_H_
|
|
||||||
|
|
||||||
#include "shared_buffers.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
shared_buffers *buffers;
|
|
||||||
/* [2] is for two antennas */
|
|
||||||
int next_subframe[2];
|
|
||||||
int next_symbol[2];
|
|
||||||
int expected_benetel_frame[2];
|
|
||||||
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_4G_LOW_H_ */
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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[0] = 255;
|
|
||||||
bs->expected_benetel_frame[1] = 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, ¶ms) != 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;
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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[0][1] = 0x3fff;
|
|
||||||
s->dl_busy[0][2] = 0x3fff;
|
|
||||||
s->dl_busy[0][3] = 0x3fff;
|
|
||||||
s->dl_busy[1][1] = 0x3fff;
|
|
||||||
s->dl_busy[1][2] = 0x3fff;
|
|
||||||
s->dl_busy[1][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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_4G_SHARED_BUFFERS_H_
|
|
||||||
#define _BENETEL_4G_SHARED_BUFFERS_H_
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* [2] is for two antennas */
|
|
||||||
unsigned char dl[2][10][14*1200*4];
|
|
||||||
unsigned char ul[2][10][14*1200*4];
|
|
||||||
uint16_t dl_busy[2][10];
|
|
||||||
uint16_t ul_busy[2][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 /* _BENETEL_4G_SHARED_BUFFERS_H_ */
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
pkg_check_modules(libdpdk REQUIRED libdpdk=20.05.0)
|
|
||||||
|
|
||||||
add_library(benetel_5g MODULE
|
|
||||||
benetel.c
|
|
||||||
shared_buffers.c
|
|
||||||
low.c
|
|
||||||
low_dpdk.c
|
|
||||||
dpdk_driver.c
|
|
||||||
)
|
|
||||||
|
|
||||||
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_include_directories(benetel_5g PRIVATE ${libdpdk_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(benetel_5g PRIVATE ${libdpdk_LIBRARIES})
|
|
||||||
target_link_libraries(benetel_5g PRIVATE pthread dl rt m numa)
|
|
||||||
set_target_properties(benetel_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include")
|
|
||||||
set_target_properties(benetel_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
||||||
add_custom_command(TARGET benetel_5g POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E create_symlink libbenetel_5g.so liboai_transpro.so
|
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
/* TODO: hardcoded to 1 for the moment, get the real value somehow... */
|
|
||||||
cap->nb_rx[0] = 1; //device->openair0_cfg->rx_num_channels;
|
|
||||||
cap->nb_tx[0] = 1; //device->openair0_cfg->tx_num_channels;
|
|
||||||
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;
|
|
||||||
|
|
||||||
lock_ul_buffer(&s->buffers, *slot);
|
|
||||||
#if 1
|
|
||||||
next:
|
|
||||||
while (!((s->buffers.ul_busy[0][*slot] == 0x3fff &&
|
|
||||||
s->buffers.ul_busy[1][*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[0][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 (antenna = 0; antenna < ru->nb_rx; antenna++) {
|
|
||||||
for (symbol = 0; symbol < 14; symbol++) {
|
|
||||||
int i;
|
|
||||||
int16_t *p = (int16_t *)(&s->buffers.ul[antenna][*slot][symbol*1272*4]);
|
|
||||||
for (i = 0; i < 1272*2; i++) {
|
|
||||||
p[i] = (int16_t)(ntohs(p[i])) / 16;
|
|
||||||
}
|
|
||||||
rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
|
|
||||||
#if 0
|
|
||||||
if (*slot == 0 && symbol == 0)
|
|
||||||
printf("rxdata in benetel_fh_if4p5_south_in %p\n", &ru->common.rxdataF[antenna][0]);
|
|
||||||
#endif
|
|
||||||
#if 1
|
|
||||||
memcpy(rxdata + 2048 - 1272/2,
|
|
||||||
&s->buffers.ul[antenna][*slot][symbol*1272*4],
|
|
||||||
(1272/2) * 4);
|
|
||||||
memcpy(rxdata,
|
|
||||||
&s->buffers.ul[antenna][*slot][symbol*1272*4] + (1272/2)*4,
|
|
||||||
(1272/2) * 4);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s->buffers.ul_busy[0][*slot] = 0;
|
|
||||||
s->buffers.ul_busy[1][*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;
|
|
||||||
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+ru->sl_ahead)%20;
|
|
||||||
proc->frame_tx = (sl>(19-ru->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;
|
|
||||||
|
|
||||||
//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[0][slot] ||
|
|
||||||
s->buffers.dl_busy[1][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 || 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 (aa = 0; aa < ru->nb_tx; aa++) {
|
|
||||||
for (symbol = 0; symbol < 14; symbol++) {
|
|
||||||
txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
|
|
||||||
#if 1
|
|
||||||
memcpy(&s->buffers.dl[aa][slot][symbol*1272*4],
|
|
||||||
txdata + 2048 - (1272/2),
|
|
||||||
(1272/2) * 4);
|
|
||||||
memcpy(&s->buffers.dl[aa][slot][symbol*1272*4] + (1272/2)*4,
|
|
||||||
txdata,
|
|
||||||
(1272/2) * 4);
|
|
||||||
#endif
|
|
||||||
int i;
|
|
||||||
uint16_t *p = (uint16_t *)(&s->buffers.dl[aa][slot][symbol*1272*4]);
|
|
||||||
for (i = 0; i < 1272*2; i++) {
|
|
||||||
p[i] = htons(p[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s->buffers.dl_busy[0][slot] = 0x3fff;
|
|
||||||
s->buffers.dl_busy[1][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(ð->buffers);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,835 +0,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_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 == 0x44 && 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) {
|
|
||||||
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 = ANT_NUM;
|
|
||||||
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 PROCESSING
|
|
||||||
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && dl_start == 1)
|
|
||||||
{
|
|
||||||
int a = ANT_NUM & 0x01;
|
|
||||||
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 + 10;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mask the symbol bits from UL packet received and apply the shift.
|
|
||||||
SYMBOL = ((SYMBOL & 0b00111111) + 10) % 14;
|
|
||||||
|
|
||||||
ANT_NUM = a;
|
|
||||||
SUBFRAME = sf;
|
|
||||||
|
|
||||||
if (a == 1)
|
|
||||||
slot_id_ctrl++;
|
|
||||||
|
|
||||||
// Slot id control for DL
|
|
||||||
if (slot_id_ctrl > 13) {
|
|
||||||
SYMBOL = SYMBOL | 0b01000000;
|
|
||||||
|
|
||||||
if (a == 1) {
|
|
||||||
if (slot_id_ctrl > 27) {
|
|
||||||
slot_id_ctrl = 0;
|
|
||||||
sf = sf + 0x10;
|
|
||||||
|
|
||||||
if (sf > 0x90){
|
|
||||||
sf = 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[a][oai_slot] & (1 << tx_symbol))) {
|
|
||||||
//printf("%s: warning, DL underflow (antenna %d sl.symbol %d.%d)\n", __FUNCTION__,a, oai_slot, tx_symbol);
|
|
||||||
memset(IQ_ptr, 0, 1272 * 4);
|
|
||||||
} else {
|
|
||||||
memcpy(IQ_ptr, bs->buffers->dl[a][oai_slot] + tx_symbol * 1272*4,
|
|
||||||
1272*4);
|
|
||||||
}
|
|
||||||
//printf("DL buffer f sf slot symbol %d %d %d %d (sf %d)\n", tx_frame, tx_subframe, tx_slot, tx_symbol, (int)sf);
|
|
||||||
bs->buffers->dl_busy[a][oai_slot] &= ~(1 << tx_symbol);
|
|
||||||
unlock_dl_buffer(bs->buffers, oai_slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, subframe * 2 + 1, 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;
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
struct timespec t;
|
|
||||||
static struct timespec old;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &t);
|
|
||||||
printf("store_ul %d.%ld (%ld)\n", (int)(t.tv_sec % 60), t.tv_nsec, t.tv_nsec - old.tv_nsec);
|
|
||||||
old = t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int a = ul->antenna;
|
|
||||||
|
|
||||||
if (ul->slot != bs->next_slot[a] ||
|
|
||||||
ul->symbol != bs->next_symbol[a]) {
|
|
||||||
printf("%s: error, antenna %d expected frame.sl.symbol %d.%d.%d, got %d.%d.%d\n",
|
|
||||||
__FUNCTION__,
|
|
||||||
a, bs->expected_benetel_frame[a], bs->next_slot[a], bs->next_symbol[a],
|
|
||||||
ul->frame, ul->slot, ul->symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill missing data with 0s */
|
|
||||||
while (ul->slot != bs->next_slot[a] ||
|
|
||||||
ul->symbol != bs->next_symbol[a]) {
|
|
||||||
lock_ul_buffer(bs->buffers, bs->next_slot[a]);
|
|
||||||
if (bs->buffers->ul_busy[a][bs->next_slot[a]] & (1 << bs->next_symbol[a])) {
|
|
||||||
printf("%s: warning, antenna %d UL overflow (sl.symbol %d.%d)\n", __FUNCTION__,
|
|
||||||
a, bs->next_slot[a], bs->next_symbol[a]);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(bs->buffers->ul[a][bs->next_slot[a]] + bs->next_symbol[a] * 1272*4,
|
|
||||||
0, 1272*4);
|
|
||||||
bs->buffers->ul_busy[a][bs->next_slot[a]] |= (1 << bs->next_symbol[a]);
|
|
||||||
signal_ul_buffer(bs->buffers, bs->next_slot[a]);
|
|
||||||
unlock_ul_buffer(bs->buffers, bs->next_slot[a]);
|
|
||||||
|
|
||||||
bs->next_symbol[a]++;
|
|
||||||
if (bs->next_symbol[a] == 14) {
|
|
||||||
bs->next_symbol[a] = 0;
|
|
||||||
bs->next_slot[a] = (bs->next_slot[a] + 1) % 20;
|
|
||||||
if (bs->next_slot[a] == 0) {
|
|
||||||
bs->expected_benetel_frame[a]++;
|
|
||||||
bs->expected_benetel_frame[a] &= 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lock_ul_buffer(bs->buffers, bs->next_slot[a]);
|
|
||||||
if (bs->buffers->ul_busy[a][bs->next_slot[a]] & (1 << bs->next_symbol[a])) {
|
|
||||||
printf("%s: warning, antenna %d UL overflow (sl.symbol %d.%d)\n", __FUNCTION__,
|
|
||||||
a, bs->next_slot[a], bs->next_symbol[a]);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(bs->buffers->ul[a][bs->next_slot[a]] + bs->next_symbol[a] * 1272*4,
|
|
||||||
ul->iq, 1272*4);
|
|
||||||
bs->buffers->ul_busy[a][bs->next_slot[a]] |= (1 << bs->next_symbol[a]);
|
|
||||||
signal_ul_buffer(bs->buffers, bs->next_slot[a]);
|
|
||||||
unlock_ul_buffer(bs->buffers, bs->next_slot[a]);
|
|
||||||
|
|
||||||
bs->next_symbol[a]++;
|
|
||||||
if (bs->next_symbol[a] == 14) {
|
|
||||||
bs->next_symbol[a] = 0;
|
|
||||||
bs->next_slot[a] = (bs->next_slot[a] + 1) % 20;
|
|
||||||
if (bs->next_slot[a] == 0) {
|
|
||||||
bs->expected_benetel_frame[a]++;
|
|
||||||
bs->expected_benetel_frame[a] &= 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);
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_5G_LOW_H_
|
|
||||||
#define _BENETEL_5G_LOW_H_
|
|
||||||
|
|
||||||
#include "shared_buffers.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
shared_buffers *buffers;
|
|
||||||
/* [2] is for two antennas */
|
|
||||||
int next_slot[2];
|
|
||||||
int next_symbol[2];
|
|
||||||
int expected_benetel_frame[2];
|
|
||||||
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_5G_LOW_H_ */
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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[0] = 255;
|
|
||||||
bs->expected_benetel_frame[1] = 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, ¶ms) != 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;
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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[0][1] = 0x3fff;
|
|
||||||
s->dl_busy[0][2] = 0x3fff;
|
|
||||||
s->dl_busy[0][3] = 0x3fff;
|
|
||||||
s->dl_busy[0][4] = 0x3fff;
|
|
||||||
s->dl_busy[0][5] = 0x3fff;
|
|
||||||
s->dl_busy[1][1] = 0x3fff;
|
|
||||||
s->dl_busy[1][2] = 0x3fff;
|
|
||||||
s->dl_busy[1][3] = 0x3fff;
|
|
||||||
s->dl_busy[1][4] = 0x3fff;
|
|
||||||
s->dl_busy[1][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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_5G_SHARED_BUFFERS_H_
|
|
||||||
#define _BENETEL_5G_SHARED_BUFFERS_H_
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* [2] is for two antennas */
|
|
||||||
unsigned char dl[2][20][14*1272*4];
|
|
||||||
unsigned char ul[2][20][14*1272*4];
|
|
||||||
uint16_t dl_busy[2][20];
|
|
||||||
uint16_t ul_busy[2][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 /* _BENETEL_5G_SHARED_BUFFERS_H_ */
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
add_boolean_option(OAI_BENETEL4G OFF "Activate OAI's Benetel 4G radio driver" OFF)
|
|
||||||
if(OAI_BENETEL4G)
|
|
||||||
add_subdirectory(4g)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_boolean_option(OAI_BENETEL5G OFF "Activate OAI's Benetel 5G radio driver" OFF)
|
|
||||||
if(OAI_BENETEL5G)
|
|
||||||
add_subdirectory(5g)
|
|
||||||
endif()
|
|
||||||
Reference in New Issue
Block a user