Merge remote-tracking branch 'origin/develop' into oairu

This commit is contained in:
Raymond Knopp
2020-12-24 14:53:58 +01:00
799 changed files with 149243 additions and 30930 deletions
+6 -66
View File
@@ -102,23 +102,15 @@ int eth_socket_init_raw(openair0_device *device) {
eth->local_addrd_ll.sll_family = AF_PACKET;
eth->local_addrd_ll.sll_ifindex = eth->if_index.ifr_ifindex;
/* hear traffic from specific protocol*/
if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
eth->local_addrd_ll.sll_protocol = htons(0xbffe);
} else{
eth->local_addrc_ll.sll_protocol = htons((short)device->eth_params->my_portc);
eth->local_addrd_ll.sll_protocol = htons((short)device->eth_params->my_portd);
}
eth->local_addrc_ll.sll_protocol = htons((short)device->eth_params->my_portc);
eth->local_addrd_ll.sll_protocol = htons((short)device->eth_params->my_portd);
eth->local_addrc_ll.sll_halen = ETH_ALEN;
eth->local_addrc_ll.sll_pkttype = PACKET_OTHERHOST;
eth->local_addrd_ll.sll_halen = ETH_ALEN;
eth->local_addrd_ll.sll_pkttype = PACKET_OTHERHOST;
eth->addr_len = sizeof(struct sockaddr_ll);
if ((eth->flags != ETH_RAW_IF5_MOBIPASS ) &&
(bind(eth->sockfdc,(struct sockaddr *)&eth->local_addrc_ll,eth->addr_len)<0)) {
perror("ETHERNET: Cannot bind to socket (control)");
exit(0);
}
if (bind(eth->sockfdd,(struct sockaddr *)&eth->local_addrd_ll,eth->addr_len)<0) {
perror("ETHERNET: Cannot bind to socket (user)");
exit(0);
@@ -127,12 +119,9 @@ int eth_socket_init_raw(openair0_device *device) {
/* Construct the Ethernet header */
ether_aton_r(local_mac, (struct ether_addr *)(&(eth->ehd.ether_shost)));
ether_aton_r(remote_mac, (struct ether_addr *)(&(eth->ehd.ether_dhost)));
if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
eth->ehd.ether_type = htons(0xbffe);
} else {
eth->ehc.ether_type = htons((short)device->eth_params->my_portc);
eth->ehd.ether_type = htons((short)device->eth_params->my_portd);
}
eth->ehc.ether_type = htons((short)device->eth_params->my_portc);
eth->ehd.ether_type = htons((short)device->eth_params->my_portd);
printf("[%s] binding to hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"),eth->ehd.ether_shost[0],eth->ehd.ether_shost[1],eth->ehd.ether_shost[2],eth->ehd.ether_shost[3],eth->ehd.ether_shost[4],eth->ehd.ether_shost[5]);
return 0;
@@ -216,8 +205,6 @@ int trx_eth_write_raw_IF4p5(openair0_device *device, openair0_timestamp timestam
packet_size = RAW_IF4p5_PULFFT_SIZE_BYTES(nblocks);
} else if (flags == IF4p5_PULTICK) {
packet_size = RAW_IF4p5_PULTICK_SIZE_BYTES;
} else if (flags == IF5_MOBIPASS) {
packet_size = RAW_IF5_MOBIPASS_SIZE_BYTES;
} else {
packet_size = RAW_IF4p5_PRACH_SIZE_BYTES;
}
@@ -430,53 +417,6 @@ int trx_eth_read_raw_IF4p5(openair0_device *device, openair0_timestamp *timestam
}
int trx_eth_read_raw_IF5_mobipass(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
// Read nblocks info from packet itself
int bytes_received=0;
eth_state_t *eth = (eth_state_t*)device->priv;
int ret;
ssize_t packet_size = 28; //MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t ;
// ssize_t packet_size = MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + 640*sizeof(int16_t);
bytes_received = recv(eth->sockfdd,
buff[0],
packet_size,
MSG_PEEK);
if (bytes_received ==-1) {
eth->num_rx_errors++;
perror("[MOBIPASS]ETHERNET IF5 READ (header): ");
exit(-1);
}
IF5_mobipass_header_t *test_header = (IF5_mobipass_header_t*)((uint8_t *)buff[0] + MAC_HEADER_SIZE_BYTES);
*timestamp = test_header->time_stamp;
packet_size = MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + 640*sizeof(int16_t);
while(bytes_received < packet_size) {
ret = recv(eth->sockfdd,
buff[0],
packet_size,
0);
if (bytes_received ==-1) {
eth->num_rx_errors++;
perror("[MOBIPASS] ETHERNET IF5 READ (payload): ");
return(-1);
} else {
bytes_received+=ret;
eth->rx_actual_nsamps = bytes_received>>1;
eth->rx_count++;
}
}
eth->rx_nsamps = nsamps;
return(bytes_received);
}
int eth_set_dev_conf_raw(openair0_device *device) {
eth_state_t *eth = (eth_state_t*)device->priv;
+156 -120
View File
@@ -46,7 +46,7 @@
#include "common_lib.h"
#include "ethernet_lib.h"
#define DEBUG 0
//#define DEBUG 1
// These are for IF5 and must be put into the device structure if multiple RUs in the same RAU !!!!!!!!!!!!!!!!!
uint16_t pck_seq_num = 1;
@@ -141,8 +141,8 @@ int eth_socket_init_udp(openair0_device *device) {
perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (control)");
exit(0);
}
if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))) {
perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (user)");
if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_NO_CHECK, &enable, sizeof(int))) {
perror("ETHERNET: Cannot set SO_NO_CHECK option on socket (user)");
exit(0);
}
@@ -201,8 +201,9 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
goto again;
}
} else {
perror("ETHERNET IF4p5 READ");
printf("(%s):\n", strerror(errno));
return(-1);
//perror("ETHERNET IF4p5 READ");
//printf("(%s):\n", strerror(errno));
}
} else {
*timestamp = test_header->sub_type;
@@ -263,36 +264,82 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
return (bytes_sent);
}
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags) {
int bytes_sent=0;
eth_state_t *eth = (eth_state_t*)device->priv;
int sendto_flag =0;
int i=0;
//sendto_flag|=flags;
eth->tx_nsamps=nsamps;
for (i=0;i<cc;i++) {
/* buff[i] points to the position in tx buffer where the payload to be sent is
int nsamps2; // aligned to upper 32 or 16 byte boundary
#if defined(__x86_64) || defined(__i386__)
#ifdef __AVX2__
nsamps2 = (nsamps+7)>>3;
__m256i buff_tx[nsamps2+1];
__m256i *buff_tx2=buff_tx+1;
#else
nsamps2 = (nsamps+3)>>2;
__m128i buff_tx[nsamps2+2];
__m128i *buff_tx2=buff_tx+2;
#endif
#elif defined(__arm__) || defined(__aarch64__)
nsamps2 = (nsamps+3)>>2;
int16x8_t buff_tx[nsamps2+2];
int16x8_t *buff_tx2=buff_tx+2;
#else
#error Unsupported CPU architecture, ethernet device cannot be built
#endif
// bring TX data into 12 LSBs for softmodem RX
for (int j=0; j<nsamps2; j++) {
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
buff_tx2[j] = _mm256_slli_epi16(((__m256i *)buff)[j],4);
#else
buff_tx2[j] = _mm_slli_epi16(((__m128i *)buff)[j],4);
#endif
#elif defined(__arm__)
buff_tx2[j] = vshlq_n_s16(((int16x8_t *)buff)[j],4);
#endif
}
/* buff[i] points to the position in tx buffer where the payload to be sent is
buff2 points to the position in tx buffer where the packet header will be placed */
void *buff2 = (void*)(buff[i]- APP_HEADER_SIZE_BYTES);
/* we don't want to ovewrite with the header info the previous tx buffer data so we store it*/
int32_t temp0 = *(int32_t *)buff2;
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
void *buff2 = ((void*)buff_tx2)- APP_HEADER_SIZE_BYTES;
bytes_sent = 0;
/* constract application header */
// eth->pck_header.seq_num = pck_seq_num;
//eth->pck_header.antenna_id = 1+(i<<1);
//eth->pck_header.timestamp = timestamp;
*(uint16_t *)buff2 = eth->pck_seq_num;
*(uint16_t *)(buff2 + sizeof(uint16_t)) = 1+(i<<1);
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM, eth->pck_seq_num);
// ECPRI Protocol revision + reserved bits (1 byte)
*(uint8_t *)buff2 = ECPRIREV;
// ECPRI Message type (1 byte)
*(uint8_t *)(buff2 + 1) = 64;
// ECPRI Payload Size (2 bytes)
AssertFatal(nsamps<16381,"nsamps > 16381\n");
*(uint8_t *)(buff2 + 2) = (nsamps<<2)>>8;
*(uint8_t *)(buff2 + 3) = (nsamps<<2)&0xff;
// ECPRI PC_ID (2 bytes)
*(uint16_t *)(buff2 + 4) = cc;
// OAI modified SEQ_ID (4 bytes)
*(uint64_t *)(buff2 + 6) = ((uint64_t )timestamp)*6;
/*
printf("ECPRI TX (REV %x, MessType %d, Payload size %d, PC_ID %d, TS %llu\n",
*(uint8_t *)buff2,
*(uint8_t *)(buff2+1),
*(uint16_t *)(buff2+2),
*(uint16_t *)(buff2+4),
*(uint64_t *)(buff2+6));
*/
int sent_byte;
if (eth->compression == ALAW_COMPRESS) {
@@ -310,7 +357,7 @@ int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, voi
bytes_sent);
#endif
/* Send packet */
bytes_sent += sendto(eth->sockfdd,
bytes_sent = sendto(eth->sockfdd,
buff2,
sent_byte,
sendto_flag,
@@ -338,17 +385,13 @@ int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, voi
}
//}
/* tx buffer values restored */
*(int32_t *)buff2 = temp0;
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
}
return (bytes_sent-APP_HEADER_SIZE_BYTES)>>2;
}
#define NOSHIFT 1
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc) {
int bytes_received=0;
eth_state_t *eth = (eth_state_t*)device->priv;
@@ -356,105 +399,98 @@ int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, voi
int rcvfrom_flag =0;
int block_cnt=0;
int again_cnt=0;
int i=0;
static int packet_cnt=0;
int payload_size = UDP_PACKET_SIZE_BYTES(nsamps);
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
int nsamps2 = (payload_size>>5)+1;
__m256i temp_rx[nsamps2];
char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
#else
int nsamps2 = (payload_size>>4)+1;
__m128i temp_rx[nsamps2];
char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
#endif
#elif defined(__arm__) || defined(__aarch64__)
int nsamps2 = (payload_size>>4)+1
int16x8_t temp_rx[nsamps2];
char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
#else
#error Unsupported CPU architecture device cannot be built
int nsamps2 = (payload_size>>2)+1;
int32_t temp_rx[payload_size>>2];
char* *temp_rx0 = ((char *)&temp_rx[1]) - APP_HEADER_SIZE_BYTES;
#endif
eth->rx_nsamps=nsamps;
for (i=0;i<cc;i++) {
/* buff[i] points to the position in rx buffer where the payload to be received will be placed
buff2 points to the position in rx buffer where the packet header will be placed */
void *buff2 = (void*)(buff[i]- APP_HEADER_SIZE_BYTES);
/* we don't want to ovewrite with the header info the previous rx buffer data so we store it*/
int32_t temp0 = *(int32_t *)buff2;
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
bytes_received=0;
block_cnt=0;
int receive_bytes;
if (eth->compression == ALAW_COMPRESS) {
receive_bytes = UDP_PACKET_SIZE_BYTES_ALAW(nsamps);
} else {
receive_bytes = UDP_PACKET_SIZE_BYTES(nsamps);
}
while(bytes_received < receive_bytes) {
again:
#if DEBUG
printf("------- RX------: buff2 current position=%d remaining_bytes=%d bytes_recv=%d \n",
(void *)(buff2+bytes_received),
receive_bytes - bytes_received,
bytes_received);
#endif
bytes_received +=recvfrom(eth->sockfdd,
buff2,
receive_bytes,
rcvfrom_flag,
(struct sockaddr *)&eth->dest_addrd,
(socklen_t *)&eth->addr_len);
if (bytes_received ==-1) {
eth->num_rx_errors++;
if (errno == EAGAIN) {
again_cnt++;
usleep(10);
if (again_cnt == 1000) {
bytes_received=0;
block_cnt=0;
AssertFatal(eth->compression == NO_COMPRESS, "IF5 compression not supported for now\n");
while(bytes_received < payload_size) {
again:
bytes_received +=recvfrom(eth->sockfdd,
temp_rx0,
payload_size,
rcvfrom_flag,
(struct sockaddr *)&eth->dest_addrd,
(socklen_t *)&eth->addr_len);
packet_cnt++;
if (bytes_received ==-1) {
eth->num_rx_errors++;
if (errno == EAGAIN) {
again_cnt++;
usleep(10);
if (again_cnt == 1000) {
perror("ETHERNET READ: ");
exit(-1);
} else {
printf("AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN \n");
goto again;
}
} else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
if (block_cnt == 1000) {
perror("ETHERNET READ: ");
exit(-1);
} else {
printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
goto again;
}
} else {
bytes_received=0;
goto again;
}
} else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
if (block_cnt == 1000) {
perror("ETHERNET READ: ");
exit(-1);
} else {
printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
goto again;
}
} else {
#if DEBUG
printf("------- RX------: nu=%d an_id=%d ts%d bytes_recv=%d\n",
*(int16_t *)buff2,
*(int16_t *)(buff2 + sizeof(int16_t)),
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
bytes_received);
dump_packet((device->host_type == RAU_HOST)? "RAU":"RRU", buff2, UDP_PACKET_SIZE_BYTES(nsamps),RX_FLAG);
#endif
/* store the timestamp value from packet's header */
*timestamp = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
/* store the sequence number of the previous packet received */
if (eth->pck_seq_num_cur == 0) {
eth->pck_seq_num_prev = *(uint16_t *)buff2;
} else {
eth->pck_seq_num_prev = eth->pck_seq_num_cur;
}
/* get the packet sequence number from packet's header */
eth->pck_seq_num_cur = *(uint16_t *)buff2;
if ( ( eth->pck_seq_num_cur != (eth->pck_seq_num_prev + 1) ) && !((eth->pck_seq_num_prev==MAX_PACKET_SEQ_NUM(nsamps,device->openair0_cfg->samples_per_frame)) && (eth->pck_seq_num_cur==1 )) && !((eth->pck_seq_num_prev==1) && (eth->pck_seq_num_cur==1))) {
//#if DEBUG
printf("Out of order packet received: current_packet=%d previous_packet=%d timestamp=%"PRId64"\n",eth->pck_seq_num_cur,eth->pck_seq_num_prev,*timestamp);
//#endif
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM,eth->pck_seq_num_cur);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM_PRV,eth->pck_seq_num_prev);
eth->rx_actual_nsamps=bytes_received>>2;
eth->rx_count++;
}
}
/* tx buffer values restored */
*(int32_t *)buff2 = temp0;
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
}
return (bytes_received-APP_HEADER_SIZE_BYTES)>>2;
} else {
/* store the timestamp value from packet's header */
*timestamp = *(openair0_timestamp *)(temp_rx0 + ECPRICOMMON_BYTES+ECPRIPCID_BYTES);
// convert TS to samples, /3 for 30.72 Ms/s, /6 for 15.36 Ms/s, /12 for 7.68 Ms/s, etc.
*timestamp = *timestamp/6;
// handle 1.4,3,5,10,15 MHz cases
*cc = *(uint16_t*)(temp_rx0 + ECPRICOMMON_BYTES);
}
eth->rx_actual_nsamps=payload_size>>2;
eth->rx_count++;
}
#ifdef NOSHIFT
memcpy(buff,(void*)(temp_rx+1),payload_size);
#else
// populate receive buffer in lower 12-bits from 16-bit representation
for (int j=1; j<nsamps2; j++) {
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
((__m256i *)buff)[j-1] = _mm256_srai_epi16(temp_rx[j],2);
#else
((__m128i *)buff)[j-1] = _mm_srai_epi16(temp_rx[j],2);
#endif
#elif defined(__arm__)
((int16x8_t *)buff)[j] = vshrq_n_s16(temp_rx[i][j],2);
#endif
}
#endif
return (payload_size>>2);
}
@@ -52,11 +52,20 @@ int num_devices_eth = 0;
struct sockaddr_in dest_addr[MAX_INST];
int dest_addr_len[MAX_INST];
int load_lib(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t *cfg,
uint8_t flag);
int trx_eth_start(openair0_device *device)
{
eth_state_t *eth = (eth_state_t*)device->priv;
if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
AssertFatal(device->thirdparty_init != NULL, "device->thirdparty_init is null\n");
AssertFatal(device->thirdparty_init(device) == 0, "third-party init failed\n");
device->openair0_cfg->samples_per_packet = 256;
}
/* initialize socket */
if (eth->flags == ETH_RAW_MODE) {
printf("Setting ETHERNET to ETH_RAW_IF5_MODE\n");
@@ -121,11 +130,6 @@ int trx_eth_start(openair0_device *device)
} else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
printf("Setting ETHERNET to RAW_IF5_MODE\n");
if (eth_socket_init_raw(device)!=0) return -1;
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
} else {
printf("Setting ETHERNET to UDP_IF5_MODE\n");
if (eth_socket_init_udp(device)!=0) return -1;
@@ -137,8 +141,7 @@ int trx_eth_start(openair0_device *device)
if(eth_get_dev_conf_udp(device)!=0) return -1;
}*/
/* adjust MTU wrt number of samples per packet */
if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
//if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
}
@@ -166,9 +169,15 @@ void trx_eth_end(openair0_device *device)
}
int trx_eth_stop(openair0_device *device)
{
return(0);
int trx_eth_stop(openair0_device *device) {
eth_state_t *eth = (eth_state_t*)device->priv;
if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
AssertFatal(device->thirdparty_cleanup != NULL, "device->thirdparty_cleanup is null\n");
AssertFatal(device->thirdparty_cleanup(device) == 0, "third-party cleanup failed\n");
}
return(0);
}
@@ -197,6 +206,10 @@ int trx_eth_reset_stats(openair0_device* device)
return(0);
}
int trx_eth_write_init(openair0_device *device)
{
return 0;
}
int ethernet_tune(openair0_device *device,
unsigned int option,
@@ -284,7 +297,7 @@ int ethernet_tune(openair0_device *device,
/******************* interface level options *************************/
case MTU_SIZE: /* change MTU of the eth interface */
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name)-1);
ifr.ifr_mtu =value;
if (ioctl(eth->sockfdd,SIOCSIFMTU,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the MTU");
@@ -294,7 +307,7 @@ int ethernet_tune(openair0_device *device,
case TX_Q_LEN: /* change TX queue length of eth interface */
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name)-1);
ifr.ifr_qlen =value;
if (ioctl(eth->sockfdd,SIOCSIFTXQLEN,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the txqueuelen");
@@ -383,20 +396,11 @@ int transport_init(openair0_device *device,
eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
memset(eth, 0, sizeof(eth_state_t));
if (eth_params->transp_preference == 1) {
eth->flags = ETH_RAW_MODE;
} else if (eth_params->transp_preference == 0) {
eth->flags = ETH_UDP_MODE;
} else if (eth_params->transp_preference == 3) {
eth->flags = ETH_RAW_IF4p5_MODE;
} else if (eth_params->transp_preference == 2) {
eth->flags = ETH_UDP_IF4p5_MODE;
} else if (eth_params->transp_preference == 4) {
eth->flags = ETH_RAW_IF5_MOBIPASS;
} else {
printf("transport_init: Unknown transport preference %d - default to RAW", eth_params->transp_preference);
eth->flags = ETH_RAW_MODE;
}
eth->flags = eth_params->transp_preference;
// load third-party driver
if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) load_lib(device,openair0_cfg,eth_params,RAU_REMOTE_THIRDPARTY_RADIO_HEAD);
if (eth_params->if_compress == 0) {
eth->compression = NO_COMPRESS;
@@ -415,15 +419,21 @@ int transport_init(openair0_device *device,
device->trx_reset_stats_func = trx_eth_reset_stats;
device->trx_end_func = trx_eth_end;
device->trx_stop_func = trx_eth_stop;
device->trx_set_freq_func = trx_eth_set_freq;
device->trx_set_gains_func = trx_eth_set_gains;
device->trx_set_freq_func = trx_eth_set_freq;
device->trx_set_gains_func = trx_eth_set_gains;
device->trx_write_init = trx_eth_write_init;
if (eth->flags == ETH_RAW_MODE) {
device->trx_read_func2 = NULL;
device->trx_read_func = NULL;
device->trx_write_func2 = NULL;
device->trx_write_func = NULL;
if (eth->flags == ETH_RAW_MODE) {
device->trx_write_func = trx_eth_write_raw;
device->trx_read_func = trx_eth_read_raw;
} else if (eth->flags == ETH_UDP_MODE) {
device->trx_write_func = trx_eth_write_udp;
device->trx_read_func = trx_eth_read_udp;
} else if (eth->flags == ETH_UDP_MODE || eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
device->trx_write_func2 = trx_eth_write_udp;
device->trx_read_func2 = trx_eth_read_udp;
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
} else if (eth->flags == ETH_RAW_IF4p5_MODE) {
@@ -434,9 +444,6 @@ int transport_init(openair0_device *device,
device->trx_read_func = trx_eth_read_udp_IF4p5;
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
} else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
device->trx_write_func = trx_eth_write_raw_IF4p5;
device->trx_read_func = trx_eth_read_raw_IF5_mobipass;
} else {
//device->trx_write_func = trx_eth_write_udp_IF4p5;
//device->trx_read_func = trx_eth_read_udp_IF4p5;
@@ -49,7 +49,10 @@
#define RX_FLAG 0
#include "if_defs.h"
#define APP_HEADER_SIZE_BYTES (sizeof(int32_t) + sizeof(openair0_timestamp))
#define ECPRICOMMON_BYTES 4
#define ECPRIPCID_BYTES 2
#define APP_HEADER_SIZE_BYTES (ECPRICOMMON_BYTES + ECPRIPCID_BYTES + sizeof(openair0_timestamp))
#define ECPRIREV 1 // ECPRI Version 1, C=0 - single ECPRI message per OAI TX packet
/*!\brief opaque ethernet data structure */
typedef struct {
@@ -234,8 +237,8 @@ int ethernet_tune(openair0_device *device, unsigned int option, int value);
* @ingroup _oai
*/
int eth_socket_init_udp(openair0_device *device);
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags);
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc);
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags);
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc);
int eth_socket_init_raw(openair0_device *device);
@@ -36,15 +36,17 @@
#include <netinet/ether.h>
#include <stdint.h>
#ifndef LITE_COMPILATION
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#endif
// ETH transport preference modes
#define ETH_UDP_MODE 0
#define ETH_RAW_MODE 1
#define ETH_UDP_MODE 0
#define ETH_RAW_MODE 1
#define ETH_UDP_IF4p5_MODE 2
#define ETH_RAW_IF4p5_MODE 3
#define ETH_RAW_IF5_MOBIPASS 4
#define ETH_UDP_IF5_ECPRI_MODE 4
// COMMOM HEADER LENGTHS
+386
View File
@@ -0,0 +1,386 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#include "shared_buffers.h"
#include "low.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
typedef struct {
eth_state_t e;
shared_buffers buffers;
rru_config_msg_type_t last_msg;
int capabilities_sent;
void *benetel_priv;
char *dpdk_main_command_line;
} benetel_eth_state_t;
int trx_benetel_start(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
void trx_benetel_end(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
}
int trx_benetel_stop(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_freq(openair0_device* device,
openair0_config_t *openair0_cfg,
int exmimo_dump_config)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_gains(openair0_device* device,
openair0_config_t *openair0_cfg)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_get_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_reset_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int ethernet_tune(openair0_device *device,
unsigned int option,
int value)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
int trx_benetel_write_raw(openair0_device *device,
openair0_timestamp timestamp,
void **buff, int nsamps, int cc, int flags)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
int trx_benetel_read_raw(openair0_device *device,
openair0_timestamp *timestamp,
void **buff, int nsamps, int cc)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
char *msg_type(int t)
{
static char *s[12] = {
"RAU_tick",
"RRU_capabilities",
"RRU_config",
"RRU_config_ok",
"RRU_start",
"RRU_stop",
"RRU_sync_ok",
"RRU_frame_resynch",
"RRU_MSG_max_num",
"RRU_check_sync",
"RRU_config_update",
"RRU_config_update_ok",
};
if (t < 0 || t > 11) return "UNKNOWN";
return s[t];
}
int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type,
msg_type(rru_config_msg->type));
s->last_msg = rru_config_msg->type;
return msg_len;
}
int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
RRU_capabilities_t *cap;
rru_config_msg->type = RRU_capabilities;
rru_config_msg->len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
cap = (RRU_capabilities_t*)&rru_config_msg->msg[0];
cap->FH_fmt = OAI_IF4p5_only;
cap->num_bands = 1;
cap->band_list[0] = 7;
cap->nb_rx[0] = 1;
cap->nb_tx[0] = 1;
cap->max_pdschReferenceSignalPower[0] = -27;
cap->max_rxgain[0] = 90;
s->capabilities_sent = 1;
return rru_config_msg->len;
}
if (s->last_msg == RRU_config) {
rru_config_msg->type = RRU_config_ok;
return 0;
}
if (s->last_msg == RRU_start) {
s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
}
/* correct? */
while (1) pause();
return 0;
}
void benetel_fh_if4p5_south_in(RU_t *ru,
int *frame,
int *subframe)
{
benetel_eth_state_t *s = ru->ifdevice.priv;
PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB;
LTE_DL_FRAME_PARMS *fp;
int symbol;
int32_t *rxdata;
int antenna = 0;
lock_ul_buffer(&s->buffers, *subframe);
next:
while (!(s->buffers.ul_busy[*subframe] == 0x3fff ||
s->buffers.prach_busy[*subframe] == 1))
wait_ul_buffer(&s->buffers, *subframe);
if (s->buffers.prach_busy[*subframe] == 1) {
int i;
int antenna = 0;
uint16_t *in;
uint16_t *out;
in = (uint16_t *)s->buffers.prach[*subframe];
out = (uint16_t *)ru->prach_rxsigF[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 (symbol = 0; symbol < 14; symbol++) {
int i;
uint16_t *p = (uint16_t *)(&s->buffers.ul[*subframe][symbol*1200*4]);
for (i = 0; i < 1200*2; i++) {
p[i] = htons(p[i]);
}
rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(rxdata + 2048 - 600,
&s->buffers.ul[*subframe][symbol*1200*4],
600 * 4);
memcpy(rxdata,
&s->buffers.ul[*subframe][symbol*1200*4] + 600*4,
600 * 4);
#endif
}
s->buffers.ul_busy[*subframe] = 0;
signal_ul_buffer(&s->buffers, *subframe);
unlock_ul_buffer(&s->buffers, *subframe);
//printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *subframe);
RU_proc_t *proc = &ru->proc;
extern uint16_t sf_ahead;
int f = *frame;
int sf = *subframe;
//calculate timestamp_rx, timestamp_tx based on frame and subframe
proc->tti_rx = sf;
proc->frame_rx = f;
proc->timestamp_rx = ((proc->frame_rx * 10) + proc->tti_rx ) * fp->samples_per_tti ;
if (get_nprocs()<=4) {
proc->tti_tx = (sf+sf_ahead)%10;
proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f;
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,f);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,sf);
proc->symbol_mask[sf] = 0;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff);
}
void benetel_fh_if4p5_south_out(RU_t *ru,
int frame,
int subframe,
uint64_t timestamp)
{
benetel_eth_state_t *s = ru->ifdevice.priv;
PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB;
LTE_DL_FRAME_PARMS *fp;
int symbol;
int32_t *txdata;
int aa = 0;
//printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, subframe, timestamp);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
lock_dl_buffer(&s->buffers, subframe);
if (s->buffers.dl_busy[subframe]) {
printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, subframe);
unlock_dl_buffer(&s->buffers, subframe);
return;
}
eNB = eNB_list[0];
fp = &eNB->frame_parms;
if (ru->num_eNB != 1 || ru->nb_tx != 1 || fp->ofdm_symbol_size != 2048 ||
fp->Ncp != NORMAL || fp->symbols_per_tti != 14) {
printf("%s:%d:%s: unsupported configuration\n",
__FILE__, __LINE__, __FUNCTION__);
exit(1);
}
for (symbol = 0; symbol < 14; symbol++) {
txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(&s->buffers.dl[subframe][symbol*1200*4],
txdata + 2048 - 600,
600 * 4);
memcpy(&s->buffers.dl[subframe][symbol*1200*4] + 600*4,
txdata + 1,
600 * 4);
#endif
int i;
uint16_t *p = (uint16_t *)(&s->buffers.dl[subframe][symbol*1200*4]);
for (i = 0; i < 1200*2; i++) {
p[i] = htons(p[i]);
}
}
s->buffers.dl_busy[subframe] = 0x3fff;
unlock_dl_buffer(&s->buffers, subframe);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.frame_tx);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.tti_tx);
}
void *get_internal_parameter(char *name)
{
printf("BENETEL: %s\n", __FUNCTION__);
if (!strcmp(name, "fh_if4p5_south_in"))
return benetel_fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return benetel_fh_if4p5_south_out;
return NULL;
}
__attribute__((__visibility__("default")))
int transport_init(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t * eth_params )
{
benetel_eth_state_t *eth;
printf("BENETEL: %s\n", __FUNCTION__);
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_benetel_start;
device->trx_get_stats_func = trx_benetel_get_stats;
device->trx_reset_stats_func = trx_benetel_reset_stats;
device->trx_end_func = trx_benetel_end;
device->trx_stop_func = trx_benetel_stop;
device->trx_set_freq_func = trx_benetel_set_freq;
device->trx_set_gains_func = trx_benetel_set_gains;
device->trx_write_func = trx_benetel_write_raw;
device->trx_read_func = trx_benetel_read_raw;
device->trx_ctlsend_func = trx_benetel_ctlsend;
device->trx_ctlrecv_func = trx_benetel_ctlrecv;
device->get_internal_parameter = get_internal_parameter;
eth = calloc(1, sizeof(benetel_eth_state_t));
if (eth == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
device->priv = eth;
device->openair0_cfg=&openair0_cfg[0];
if (openair0_cfg->sdr_addrs == NULL) {
printf("benetel: fatal: sdr_addrs not set in configuration file\n");
exit(1);
}
eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs);
if (eth->dpdk_main_command_line == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->last_msg = -1;
init_buffers(&eth->buffers);
return 0;
}
@@ -0,0 +1,786 @@
/* 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 && ANT_NUM == 0x00) {
p.frame = FRAME;
p.subframe = SUBFRAME >> 4;
p.slot = 0; /* unused */
p.symbol = SYMBOL;
p.antenna = 0;
memcpy(p.iq, IQ_ptr, 4800);
store_ul(bs, &p);
}
// U-PLANE UL ANT_0 PROCESSING
if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00 && dl_start == 1)
{
int tx_frame = FRAME;
int tx_subframe = SUBFRAME >> 4;
int tx_symbol = SYMBOL + 5;
if (tx_symbol > 13) {
tx_symbol -= 14;
tx_subframe++;
if (tx_subframe == 10) {
tx_subframe = 0;
tx_frame = (tx_frame + 1) & 255;
}
}
// ANT_NUM = 0x00;
// SYMBOL = (SYMBOL + 5) % 14;
PAYLOAD_2 = 0xc8;
FRAME = tx_frame;
SUBFRAME = tx_subframe << 4;
SYMBOL = tx_symbol;
/* antenna 0 - send actual DL data (if available) */
lock_dl_buffer(bs->buffers, tx_subframe);
if (!(bs->buffers->dl_busy[tx_subframe] & (1 << tx_symbol))) {
printf("%s: warning, DL underflow (sf.symbol %d.%d)\n", __FUNCTION__,
tx_subframe, tx_symbol);
memset(IQ_ptr, 0, 1200 * 4);
} else {
memcpy(IQ_ptr, bs->buffers->dl[tx_subframe] + tx_symbol * 1200*4,
1200*4);
}
bs->buffers->dl_busy[tx_subframe] &= ~(1 << tx_symbol);
unlock_dl_buffer(bs->buffers, tx_subframe);
// fill DL Data for ant 0 with 0 value
// memset(IQ_ptr, 0, 4800);
}
// U-PLANE UL ANT_1 PROCESSING
else if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x01 && dl_start == 1)
{
// ANT_NUM = 0x01;
SYMBOL = (SYMBOL + 5) % 14;
PAYLOAD_2 = 0xc8;
// fill DL Data for ant 1 with 0 value
memset(IQ_ptr, 0, 4800);
}
// U-PLANE PRACH PROCESSING
else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){
if (ANT_NUM == 0) {
store_prach(bs, FRAME, SUBFRAME>>4, IQ_ptr);
}
rte_pktmbuf_free(m);
return;
}
// Send Packets
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
/* main processing loop */
static void
l2fwd_main_loop(benetel_t *bs)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on master core */
if (lcore_id == rte_get_master_lcore()) {
//print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid, bs);
}
}
}
}
static int
l2fwd_launch_one_lcore(void *bs)
{
l2fwd_main_loop(bs);
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (pm == 0)
return -1;
return pm;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case 0:
break;
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
rte_eth_link_get_nowait(portid, &link);
/* print link status if flag set */
if (print_flag == 1) {
if (link.link_status)
printf(
"Port%d Link Up. Speed %u Mbps - %s\n",
portid, link.link_speed,
(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
("full-duplex") : ("half-duplex\n"));
else
printf("Port %d Link Down\n", portid);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
dpdk_main(int argc, char **argv, benetel_t *bs)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/*
* Each logical core is assigned a dedicated TX queue on each port.
*/
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
}
else
last_port = portid;
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, 9680,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
rte_eth_dev_info_get(portid, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
rte_eth_promiscuous_enable(portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER);
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
rte_eth_dev_stop(portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
return ret;
}
+95
View File
@@ -0,0 +1,95 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "low.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void store_ul(benetel_t *bs, ul_packet_t *ul)
{
/* only antenna 0 for the moment */
if (ul->antenna != 0)
return;
if (ul->subframe != bs->next_subframe ||
ul->symbol != bs->next_symbol) {
printf("%s: fatal, expected frame.sf.symbol %d.%d.%d, got %d.%d.%d\n",
__FUNCTION__,
bs->expected_benetel_frame, bs->next_subframe, bs->next_symbol,
ul->frame, ul->subframe, ul->symbol);
exit(1);
}
lock_ul_buffer(bs->buffers, bs->next_subframe);
if (bs->buffers->ul_busy[bs->next_subframe] & (1 << bs->next_symbol)) {
printf("%s: warning, UL overflow (sf.symbol %d.%d)\n", __FUNCTION__,
bs->next_subframe, bs->next_symbol);
}
memcpy(bs->buffers->ul[bs->next_subframe] + bs->next_symbol * 1200*4,
ul->iq, 1200*4);
bs->buffers->ul_busy[bs->next_subframe] |= (1 << bs->next_symbol);
signal_ul_buffer(bs->buffers, bs->next_subframe);
unlock_ul_buffer(bs->buffers, bs->next_subframe);
bs->next_symbol++;
if (bs->next_symbol == 14) {
bs->next_symbol = 0;
bs->next_subframe = (bs->next_subframe + 1) % 10;
if (bs->next_subframe == 0) {
bs->expected_benetel_frame++;
bs->expected_benetel_frame &= 255;
}
}
}
void store_prach(benetel_t *bs, int frame, int subframe, void *data)
{
static int last_frame = -1;
static int last_subframe = -1;
/* hack: antenna number is always 0, discard second packet with same f/sf */
if (frame == last_frame && subframe == last_subframe) return;
last_frame = frame;
last_subframe = subframe;
lock_ul_buffer(bs->buffers, subframe);
if (bs->buffers->prach_busy[subframe]) {
printf("store_prach: fatal: previous prach buffer not processed\n");
unlock_ul_buffer(bs->buffers, subframe);
return;
}
bs->buffers->prach_busy[subframe] = 1;
memcpy(bs->buffers->prach[subframe], data, 849*4);
signal_ul_buffer(bs->buffers, subframe);
unlock_ul_buffer(bs->buffers, subframe);
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
if (!strcmp(ifname, "dpdk"))
return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line);
printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname);
exit(1);
}
+49
View File
@@ -0,0 +1,49 @@
/*
* 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;
int next_subframe;
int next_symbol;
int expected_benetel_frame;
char *dpdk_main_command_line;
} benetel_t;
typedef struct {
int frame;
int subframe;
int slot;
int symbol;
int antenna;
unsigned char iq[4800];
} ul_packet_t;
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void store_ul(benetel_t *bs, ul_packet_t *ul);
void store_prach(benetel_t *bs, int frame, int subframe, void *data);
#endif /* _BENETEL_4G_LOW_H_ */
+118
View File
@@ -0,0 +1,118 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* those 2 lines for CPU_SET */
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "low.h"
int dpdk_main(int argc, char **argv, benetel_t *);
void *dpdk_thread(void *_bs)
{
benetel_t *bs = _bs;
int n = 0;
char **v = NULL; // { "softmodem", "-n", "2", "-l", "8", "--", "-p", "0x2" };
char *s = bs->dpdk_main_command_line;
char *tok;
while ((tok = strtok(s, " ")) != NULL) {
n++;
v = realloc(v, n * sizeof(char *));
if (v == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
v[n-1] = tok;
s = NULL;
}
dpdk_main(n, v, bs);
exit(1);
return 0;
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
benetel_t *bs;
bs = calloc(1, sizeof(benetel_t));
if (bs == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
bs->buffers = buffers;
bs->expected_benetel_frame = 255;
bs->dpdk_main_command_line = dpdk_main_command_line;
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(12,&cpuset);
if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) {
printf("pthread_attr_setaffinity_np failed\n");
exit(1);
}
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
printf("pthread_attr_setschedpolicy failed\n");
exit(1);
}
struct sched_param params;
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_get_priority_max(SCHED_FIFO) == -1) {
printf("sched_get_priority_max failed\n");
exit(1);
}
if (pthread_attr_setschedparam(&attr, &params) != 0) {
printf("pthread_setschedparam failed\n");
exit(1);
}
pthread_t t;
if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) {
printf("%s: thread creation failed\n", __FUNCTION__);
exit(1);
}
if (pthread_attr_destroy(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
return bs;
}
@@ -0,0 +1,114 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "shared_buffers.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init_buffers(shared_buffers *s)
{
int subframe;
memset(s, 0, sizeof(*s));
for (subframe = 0; subframe < 10; subframe++) {
if (pthread_mutex_init(&s->m_dl[subframe], NULL) != 0 ||
pthread_cond_init(&s->c_dl[subframe], NULL) != 0 ||
pthread_mutex_init(&s->m_ul[subframe], NULL) != 0 ||
pthread_cond_init(&s->c_ul[subframe], NULL) != 0) {
printf("%s: error initializing mutex/cond\n", __FUNCTION__);
exit(1);
}
}
/* in FDD the eNB's first transmitted DL subframe is 4 but the device
* needs to have subframes 1, 2 and 3 ready. Let's pretend there are ready.
*/
s->dl_busy[1] = 0x3fff;
s->dl_busy[2] = 0x3fff;
s->dl_busy[3] = 0x3fff;
}
void lock_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_lock(&s->m_dl[subframe]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
exit(1);
}
}
void unlock_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_unlock(&s->m_dl[subframe]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_wait(&s->c_dl[subframe], &s->m_dl[subframe]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_dl_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_broadcast(&s->c_dl[subframe]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
void lock_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_lock(&s->m_ul[subframe]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
exit(1);
}
}
void unlock_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_mutex_unlock(&s->m_ul[subframe]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_wait(&s->c_ul[subframe], &s->m_ul[subframe]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_ul_buffer(shared_buffers *s, int subframe)
{
if (pthread_cond_broadcast(&s->c_ul[subframe]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
@@ -0,0 +1,60 @@
/*
* 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 {
unsigned char dl[10][14*1200*4];
unsigned char ul[10][14*1200*4];
uint16_t dl_busy[10];
uint16_t ul_busy[10];
pthread_mutex_t m_ul[10];
pthread_cond_t c_ul[10];
pthread_mutex_t m_dl[10];
pthread_cond_t c_dl[10];
unsigned char prach[10][849*4];
unsigned char prach_busy[10];
/* statistics/error counting */
int ul_overflow;
int dl_underflow;
} shared_buffers;
void init_buffers(shared_buffers *s);
void lock_dl_buffer(shared_buffers *s, int subframe);
void unlock_dl_buffer(shared_buffers *s, int subframe);
void wait_dl_buffer(shared_buffers *s, int subframe);
void signal_dl_buffer(shared_buffers *s, int subframe);
void lock_ul_buffer(shared_buffers *s, int subframe);
void unlock_ul_buffer(shared_buffers *s, int subframe);
void wait_ul_buffer(shared_buffers *s, int subframe);
void signal_ul_buffer(shared_buffers *s, int subframe);
#endif /* _BENETEL_4G_SHARED_BUFFERS_H_ */
+389
View File
@@ -0,0 +1,389 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#include "shared_buffers.h"
#include "low.h"
#include "openair1/PHY/defs_gNB.h"
typedef struct {
eth_state_t e;
shared_buffers buffers;
rru_config_msg_type_t last_msg;
int capabilities_sent;
void *benetel_priv;
char *dpdk_main_command_line;
} benetel_eth_state_t;
int trx_benetel_start(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
void trx_benetel_end(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
}
int trx_benetel_stop(openair0_device *device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_freq(openair0_device* device,
openair0_config_t *openair0_cfg,
int exmimo_dump_config)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_set_gains(openair0_device* device,
openair0_config_t *openair0_cfg)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_get_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int trx_benetel_reset_stats(openair0_device* device)
{
printf("BENETEL: %s\n", __FUNCTION__);
return(0);
}
int ethernet_tune(openair0_device *device,
unsigned int option,
int value)
{
printf("BENETEL: %s\n", __FUNCTION__);
return 0;
}
int trx_benetel_write_raw(openair0_device *device,
openair0_timestamp timestamp,
void **buff, int nsamps, int cc, int flags)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
int trx_benetel_read_raw(openair0_device *device,
openair0_timestamp *timestamp,
void **buff, int nsamps, int cc)
{
printf("BENETEL: %s\n", __FUNCTION__);
return nsamps*4;
}
char *msg_type(int t)
{
static char *s[12] = {
"RAU_tick",
"RRU_capabilities",
"RRU_config",
"RRU_config_ok",
"RRU_start",
"RRU_stop",
"RRU_sync_ok",
"RRU_frame_resynch",
"RRU_MSG_max_num",
"RRU_check_sync",
"RRU_config_update",
"RRU_config_update_ok",
};
if (t < 0 || t > 11) return "UNKNOWN";
return s[t];
}
int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type,
msg_type(rru_config_msg->type));
s->last_msg = rru_config_msg->type;
return msg_len;
}
int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
benetel_eth_state_t *s = device->priv;
printf("BENETEL: %s\n", __FUNCTION__);
if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
RRU_capabilities_t *cap;
rru_config_msg->type = RRU_capabilities;
rru_config_msg->len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
cap = (RRU_capabilities_t*)&rru_config_msg->msg[0];
cap->FH_fmt = OAI_IF4p5_only;
cap->num_bands = 1;
cap->band_list[0] = 78;
cap->nb_rx[0] = 1;
cap->nb_tx[0] = 1;
cap->max_pdschReferenceSignalPower[0] = -27;
cap->max_rxgain[0] = 90;
s->capabilities_sent = 1;
return rru_config_msg->len;
}
#if 0
if (s->last_msg == RRU_config) {
rru_config_msg->type = RRU_config_ok;
return 0;
}
if (s->last_msg == RRU_start) {
printf("***************** benetel start\n");
s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
}
#endif
if (s->last_msg == RRU_config) {
rru_config_msg->type = RRU_config_ok;
s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
}
/* correct? */
//printf("***************** benetel pause\n");
// while (1) pause();
return 0;
}
void benetel_fh_if4p5_south_in(RU_t *ru,
int *frame,
int *slot)
{
//printf("XXX benetel_fh_if4p5_south_in %d %d\n", *frame, *slot);
benetel_eth_state_t *s = ru->ifdevice.priv;
NR_DL_FRAME_PARMS *fp;
int symbol;
int32_t *rxdata;
int antenna = 0;
lock_ul_buffer(&s->buffers, *slot);
#if 1
next:
while (!(s->buffers.ul_busy[*slot] == 0x3fff ||
s->buffers.prach_busy[*slot] == 1))
wait_ul_buffer(&s->buffers, *slot);
if (s->buffers.prach_busy[*slot] == 1) {
int i;
int antenna = 0;
uint16_t *in;
uint16_t *out;
in = (uint16_t *)s->buffers.prach[*slot];
out = (uint16_t *)ru->prach_rxsigF[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 (symbol = 0; symbol < 14; symbol++) {
int i;
uint16_t *p = (uint16_t *)(&s->buffers.ul[*slot][symbol*1272*4]);
for (i = 0; i < 1272*2; i++) {
p[i] = htons(p[i]);
}
rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(rxdata + 2048 - 1272/2,
&s->buffers.ul[*slot][symbol*1272*4],
(1272/2) * 4);
memcpy(rxdata,
&s->buffers.ul[*slot][symbol*1272*4] + (1272/2)*4,
(1272/2) * 4);
#endif
}
s->buffers.ul_busy[*slot] = 0;
signal_ul_buffer(&s->buffers, *slot);
unlock_ul_buffer(&s->buffers, *slot);
//printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *slot);
RU_proc_t *proc = &ru->proc;
extern uint16_t sl_ahead;
int f = *frame;
int sl = *slot;
//calculate timestamp_rx, timestamp_tx based on frame and slot
proc->tti_rx = sl;
proc->frame_rx = f;
/* TODO: be sure of samples_per_slot0
FK: should use get_samples_per_slot(slot)
but for mu=1 its ok
*/
proc->timestamp_rx = ((proc->frame_rx * 20) + proc->tti_rx ) * fp->samples_per_slot0;
if (get_nprocs()<=4) {
// why? what if there are more?
proc->tti_tx = (sl+sl_ahead)%20;
proc->frame_tx = (sl>(19-sl_ahead)) ? (f+1)&1023 : f;
}
}
void benetel_fh_if4p5_south_out(RU_t *ru,
int frame,
int slot,
uint64_t timestamp)
{
//printf("XXX benetel_fh_if4p5_south_out %d %d %ld\n", frame, slot, timestamp);
benetel_eth_state_t *s = ru->ifdevice.priv;
NR_DL_FRAME_PARMS *fp;
int symbol;
int32_t *txdata;
int aa = 0;
//printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, slot, timestamp);
lock_dl_buffer(&s->buffers, slot);
if (s->buffers.dl_busy[slot]) {
printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, slot);
unlock_dl_buffer(&s->buffers, slot);
return;
}
fp = ru->nr_frame_parms;
if (ru->num_gNB != 1 || ru->nb_tx != 1 || fp->ofdm_symbol_size != 2048 ||
fp->Ncp != NORMAL || fp->symbols_per_slot != 14) {
printf("%s:%d:%s: unsupported configuration\n",
__FILE__, __LINE__, __FUNCTION__);
exit(1);
}
for (symbol = 0; symbol < 14; symbol++) {
txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
#if 1
memcpy(&s->buffers.dl[slot][symbol*1272*4],
txdata + 2048 - (1272/2),
(1272/2) * 4);
memcpy(&s->buffers.dl[slot][symbol*1272*4] + (1272/2)*4,
txdata,
(1272/2) * 4);
#endif
int i;
uint16_t *p = (uint16_t *)(&s->buffers.dl[slot][symbol*1272*4]);
for (i = 0; i < 1272*2; i++) {
p[i] = htons(p[i]);
}
}
s->buffers.dl_busy[slot] = 0x3fff;
unlock_dl_buffer(&s->buffers, slot);
}
void *get_internal_parameter(char *name)
{
printf("BENETEL: %s\n", __FUNCTION__);
if (!strcmp(name, "fh_if4p5_south_in"))
return benetel_fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return benetel_fh_if4p5_south_out;
return NULL;
}
__attribute__((__visibility__("default")))
int transport_init(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t * eth_params )
{
benetel_eth_state_t *eth;
printf("BENETEL: %s\n", __FUNCTION__);
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_benetel_start;
device->trx_get_stats_func = trx_benetel_get_stats;
device->trx_reset_stats_func = trx_benetel_reset_stats;
device->trx_end_func = trx_benetel_end;
device->trx_stop_func = trx_benetel_stop;
device->trx_set_freq_func = trx_benetel_set_freq;
device->trx_set_gains_func = trx_benetel_set_gains;
device->trx_write_func = trx_benetel_write_raw;
device->trx_read_func = trx_benetel_read_raw;
device->trx_ctlsend_func = trx_benetel_ctlsend;
device->trx_ctlrecv_func = trx_benetel_ctlrecv;
device->get_internal_parameter = get_internal_parameter;
eth = calloc(1, sizeof(benetel_eth_state_t));
if (eth == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
device->priv = eth;
device->openair0_cfg=&openair0_cfg[0];
if (openair0_cfg->sdr_addrs == NULL) {
printf("benetel: fatal: sdr_addrs not set in configuration file\n");
exit(1);
}
eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs);
if (eth->dpdk_main_command_line == NULL) {
AssertFatal(0==1, "out of memory\n");
}
eth->last_msg = -1;
init_buffers(&eth->buffers);
return 0;
}
@@ -0,0 +1,856 @@
/* 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 && ANT_NUM == 0x00) {
int subframe = SUBFRAME >> 4;
int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
p.frame = FRAME;
p.slot = subframe * 2 + slot;
p.symbol = SYMBOL & 0x3f;
p.antenna = 0;
memcpy(p.iq, IQ_ptr, 5088);
store_ul(bs, &p);
// if (p.symbol==0) printf("store ul f.sl.sy %d.%d.%d\n", p.frame, p.slot, p.symbol);
}
// U-PLANE UL ANT_0 PROCESSING
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x00 && dl_start == 1)
{
int frame = FRAME;
int subframe = SUBFRAME >> 4;
int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
int symbol = SYMBOL & 0x3f;
int oai_slot;
int tx_frame = frame;
int tx_subframe = subframe;
int tx_slot = slot;
int tx_symbol = symbol + 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;
}
}
}
ANT_NUM = 0x00;
// Mask the symbol bits from UL packet received and apply the shift.
SYMBOL = ((SYMBOL & 0b00111111) + 10) % 14;
ANT_NUM = 0x00;
SUBFRAME = sf;
// Slot id control for DL
if(slot_id_ctrl > 13){
SYMBOL = SYMBOL | 0b01000000;
}
/* antenna 0 - send actual DL data (if available) */
oai_slot = tx_subframe * 2 + tx_slot;
lock_dl_buffer(bs->buffers, oai_slot);
if (!(bs->buffers->dl_busy[oai_slot] & (1 << tx_symbol))) {
printf("%s: warning, DL underflow (sl.symbol %d.%d)\n", __FUNCTION__,
oai_slot, tx_symbol);
memset(IQ_ptr, 0, 1272 * 4);
} else {
memcpy(IQ_ptr, bs->buffers->dl[oai_slot] + tx_symbol * 1272*4,
1272*4);
}
//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[oai_slot] &= ~(1 << tx_symbol);
unlock_dl_buffer(bs->buffers, oai_slot);
// fill DL Data for ant 0 with 0 value
// memset(IQ_ptr, 0, 5088);
}
// U-PLANE UL ANT_1 PROCESSING
if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x01 && dl_start == 1)
{
// Mask the symbol bits from UL packet received and apply the shift.
SYMBOL = ((SYMBOL & 0b00111111) +10) % 14;
ANT_NUM = 0x01;
SUBFRAME = sf;
slot_id_ctrl++;
// Slot id control for DL
if(slot_id_ctrl > 13){
SYMBOL = SYMBOL | 0b01000000;
if(slot_id_ctrl > 27){
slot_id_ctrl = 0;
sf = sf + 0x10;
if (sf >0x90){
sf = 0;
}
}
}
// fill DL Data for ant 1 with 0 value
memset(IQ_ptr, 0, 5088);
}
// U-PLANE PRACH PROCESSING
else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){
if (ANT_NUM == 0) {
int subframe = SUBFRAME >> 4;
//int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
if (subframe==9) {
//printf("store prach f.sf.sl %d.%d.%d %d\n", FRAME, subframe, slot, subframe * 2 + slot);
store_prach(bs, FRAME, 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;
}
+130
View File
@@ -0,0 +1,130 @@
/*
* 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
/* only antenna 0 for the moment */
if (ul->antenna != 0)
return;
if (ul->slot != bs->next_slot ||
ul->symbol != bs->next_symbol) {
printf("%s: error, expected frame.sl.symbol %d.%d.%d, got %d.%d.%d\n",
__FUNCTION__,
bs->expected_benetel_frame, bs->next_slot, bs->next_symbol,
ul->frame, ul->slot, ul->symbol);
}
/* fill missing data with 0s */
while (ul->slot != bs->next_slot ||
ul->symbol != bs->next_symbol) {
lock_ul_buffer(bs->buffers, bs->next_slot);
if (bs->buffers->ul_busy[bs->next_slot] & (1 << bs->next_symbol)) {
printf("%s: warning, UL overflow (sl.symbol %d.%d)\n", __FUNCTION__,
bs->next_slot, bs->next_symbol);
}
memset(bs->buffers->ul[bs->next_slot] + bs->next_symbol * 1272*4,
0, 1272*4);
bs->buffers->ul_busy[bs->next_slot] |= (1 << bs->next_symbol);
signal_ul_buffer(bs->buffers, bs->next_slot);
unlock_ul_buffer(bs->buffers, bs->next_slot);
bs->next_symbol++;
if (bs->next_symbol == 14) {
bs->next_symbol = 0;
bs->next_slot = (bs->next_slot + 1) % 20;
if (bs->next_slot == 0) {
bs->expected_benetel_frame++;
bs->expected_benetel_frame &= 255;
}
}
}
lock_ul_buffer(bs->buffers, bs->next_slot);
if (bs->buffers->ul_busy[bs->next_slot] & (1 << bs->next_symbol)) {
printf("%s: warning, UL overflow (sl.symbol %d.%d)\n", __FUNCTION__,
bs->next_slot, bs->next_symbol);
}
memcpy(bs->buffers->ul[bs->next_slot] + bs->next_symbol * 1272*4,
ul->iq, 1272*4);
bs->buffers->ul_busy[bs->next_slot] |= (1 << bs->next_symbol);
signal_ul_buffer(bs->buffers, bs->next_slot);
unlock_ul_buffer(bs->buffers, bs->next_slot);
bs->next_symbol++;
if (bs->next_symbol == 14) {
bs->next_symbol = 0;
bs->next_slot = (bs->next_slot + 1) % 20;
if (bs->next_slot == 0) {
bs->expected_benetel_frame++;
bs->expected_benetel_frame &= 255;
}
}
}
void store_prach(benetel_t *bs, int frame, int slot, void *data)
{
static int last_frame = -1;
static int last_slot = -1;
/* hack: antenna number is always 0, discard second packet with same f/sf */
//if (frame == last_frame && slot == last_slot) return;
if (frame == last_frame && slot == last_slot) { printf("got f.sl %d.%d twice\n", frame, slot); return; }
last_frame = frame;
last_slot = slot;
lock_ul_buffer(bs->buffers, slot);
if (bs->buffers->prach_busy[slot]) {
printf("store_prach: fatal: previous prach buffer not processed\n");
unlock_ul_buffer(bs->buffers, slot);
return;
}
bs->buffers->prach_busy[slot] = 1;
memcpy(bs->buffers->prach[slot], data, 839*4);
signal_ul_buffer(bs->buffers, slot);
unlock_ul_buffer(bs->buffers, slot);
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
if (!strcmp(ifname, "dpdk"))
return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line);
printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname);
exit(1);
}
+48
View File
@@ -0,0 +1,48 @@
/*
* 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;
int next_slot;
int next_symbol;
int expected_benetel_frame;
char *dpdk_main_command_line;
} benetel_t;
typedef struct {
int frame;
int slot;
int symbol;
int antenna;
unsigned char iq[5088];
} ul_packet_t;
void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
void store_ul(benetel_t *bs, ul_packet_t *ul);
void store_prach(benetel_t *bs, int frame, int slot, void *data);
#endif /* _BENETEL_5G_LOW_H_ */
+118
View File
@@ -0,0 +1,118 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* those 2 lines for CPU_SET */
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "low.h"
int dpdk_main(int argc, char **argv, benetel_t *);
void *dpdk_thread(void *_bs)
{
benetel_t *bs = _bs;
int n = 0;
char **v = NULL; // = { "softmodem", "-n", "2", "--file-prefix", "pg2", "-l", "6", "--", "-p", "0x1" };
char *s = bs->dpdk_main_command_line;
char *tok;
while ((tok = strtok(s, " ")) != NULL) {
n++;
v = realloc(v, n * sizeof(char *));
if (v == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
v[n-1] = tok;
s = NULL;
}
dpdk_main(n, v, bs);
exit(1);
return 0;
}
void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
{
benetel_t *bs;
bs = calloc(1, sizeof(benetel_t));
if (bs == NULL) {
printf("%s: out of memory\n", __FUNCTION__);
exit(1);
}
bs->buffers = buffers;
bs->expected_benetel_frame = 255;
bs->dpdk_main_command_line = dpdk_main_command_line;
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(10,&cpuset);
if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) {
printf("pthread_attr_setaffinity_np failed\n");
exit(1);
}
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
printf("pthread_attr_setschedpolicy failed\n");
exit(1);
}
struct sched_param params;
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_get_priority_max(SCHED_FIFO) == -1) {
printf("sched_get_priority_max failed\n");
exit(1);
}
if (pthread_attr_setschedparam(&attr, &params) != 0) {
printf("pthread_setschedparam failed\n");
exit(1);
}
pthread_t t;
if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) {
printf("%s: thread creation failed\n", __FUNCTION__);
exit(1);
}
if (pthread_attr_destroy(&attr) != 0) {
printf("pthread_attr_init failed\n");
exit(1);
}
return bs;
}
@@ -0,0 +1,118 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "shared_buffers.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init_buffers(shared_buffers *s)
{
int slot;
memset(s, 0, sizeof(*s));
for (slot = 0; slot < 20; slot++) {
if (pthread_mutex_init(&s->m_dl[slot], NULL) != 0 ||
pthread_cond_init(&s->c_dl[slot], NULL) != 0 ||
pthread_mutex_init(&s->m_ul[slot], NULL) != 0 ||
pthread_cond_init(&s->c_ul[slot], NULL) != 0) {
printf("%s: error initializing mutex/cond\n", __FUNCTION__);
exit(1);
}
}
/* the gNB's first transmitted DL slot is 6 but the device
* needs to have slots 1, 2 and 3, 4 and 5 ready. Let's pretend
* they are ready.
*/
s->dl_busy[1] = 0x3fff;
s->dl_busy[2] = 0x3fff;
s->dl_busy[3] = 0x3fff;
s->dl_busy[4] = 0x3fff;
s->dl_busy[5] = 0x3fff;
}
void lock_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_lock(&s->m_dl[slot]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
exit(1);
}
}
void unlock_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_unlock(&s->m_dl[slot]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_wait(&s->c_dl[slot], &s->m_dl[slot]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_dl_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_broadcast(&s->c_dl[slot]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
void lock_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_lock(&s->m_ul[slot]) != 0) {
printf("%s: fatal: lock fails\n", __FUNCTION__);
printf("%s: fatal: lock fails slot %d\n", __FUNCTION__, slot);
exit(1);
}
}
void unlock_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_mutex_unlock(&s->m_ul[slot]) != 0) {
printf("%s: fatal: unlock fails\n", __FUNCTION__);
exit(1);
}
}
void wait_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_wait(&s->c_ul[slot], &s->m_ul[slot]) != 0) {
printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
exit(1);
}
}
void signal_ul_buffer(shared_buffers *s, int slot)
{
if (pthread_cond_broadcast(&s->c_ul[slot]) != 0) {
printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
exit(1);
}
}
@@ -0,0 +1,60 @@
/*
* 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 {
unsigned char dl[20][14*1272*4];
unsigned char ul[20][14*1272*4];
uint16_t dl_busy[20];
uint16_t ul_busy[20];
pthread_mutex_t m_ul[20];
pthread_cond_t c_ul[20];
pthread_mutex_t m_dl[20];
pthread_cond_t c_dl[20];
unsigned char prach[20][849*4];
unsigned char prach_busy[20];
/* statistics/error counting */
int ul_overflow;
int dl_underflow;
} shared_buffers;
void init_buffers(shared_buffers *s);
void lock_dl_buffer(shared_buffers *s, int slot);
void unlock_dl_buffer(shared_buffers *s, int slot);
void wait_dl_buffer(shared_buffers *s, int slot);
void signal_dl_buffer(shared_buffers *s, int slot);
void lock_ul_buffer(shared_buffers *s, int slot);
void unlock_ul_buffer(shared_buffers *s, int slot);
void wait_ul_buffer(shared_buffers *s, int slot);
void signal_ul_buffer(shared_buffers *s, int slot);
#endif /* _BENETEL_5G_SHARED_BUFFERS_H_ */