* add RRH gateway module, IQ transports, and its gtkwave template (experimental)

* update ethernet library and common lib 
* update runtime values of the lte-softmodem tx and rx threads based on an empirical model


git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7709 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
navid
2015-07-16 15:31:04 +00:00
parent 4ef9500af4
commit ff2f80989b
28 changed files with 2968 additions and 339 deletions
+281 -123
View File
@@ -26,16 +26,16 @@
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/** ethernet_lib : API to stream I/Q samples over standard ethernet
*
* Authors: Pedro Dinis <pedrodinis20@gmail.com>
* Lucio Ferreira <lucio.ferreira@inov.pt>
* Raymond Knopp <raymond.knopp@eurecom.fr>
*
* Changelog:
* 06.10.2014: Initial version
*/
/*! \fileethernet_lib.c
* \brief API to stream I/Q samples over standard ethernet
* \author Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
* \date 2015
* \version 0.2
* \company Eurecom
* \maintainer: navid.nikaein@eurecom.fr
* \note
* \warning
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
@@ -50,203 +50,361 @@
#include <errno.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#define DEFAULT_IF "eth0"
#define BUF_SIZ 8960 /*Jumbo frame size*/
#define BUF_SIZ 8960 /*Jumbo frame size*/
#define MAX_INST 4
int sockfd[MAX_INST];
struct sockaddr_in dest_addr[MAX_INST];
//int sockfd[MAX_INST];
int num_devices = 0;
int dest_addr_len[MAX_INST];
int i;
int tx_len = 0;
char sendbuf[MAX_INST][BUF_SIZ]; /*TODO*/
/**PDF: Initialization of UDP Socket to communicate with one DEST */
int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port)
{
/* Initialization of UDP Socket to communicate with one destination */
int ethernet_socket_init(openair0_device *device) {
/**PDF: To be passed by input argument*/
// DEST_port = 32000;
struct sockaddr_in *dest = &dest_addr[Mod_id];
int i = 0;
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
// struct sockaddr_in *dest = &dest_addr[Mod_id];
char str[INET_ADDRSTRLEN];
const char *dest_ip;
int dest_port;
if (device->func_type == RRH_FUNC ){
dest_ip = device->openair0_cfg.my_ip;
dest_port = device->openair0_cfg.my_port;
printf("[RRH] ip addr %s port %d\n",dest_ip, dest_port);
} else {
dest_ip = device->openair0_cfg.remote_ip;
dest_port = device->openair0_cfg.remote_port;
printf("[BBU] ip addr %s port %d\n",dest_ip, dest_port);
}
/* Open RAW socket to send on */
if ((sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
if ((eth->sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("ETHERNET: Error opening socket");
exit(0);
}
bzero((void *)dest,sizeof(struct sockaddr));
dest->sin_family = AF_INET;
dest->sin_addr.s_addr=inet_addr(dest_ip);
dest->sin_port=htons(dest_port);
dest_addr_len[Mod_id] = sizeof(struct sockaddr);
/* initialize destination address */
for (i=0; i< MAX_INST; i++)
bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));
inet_ntop(AF_INET, &(dest->sin_addr), str, INET_ADDRSTRLEN);
printf("Connecting to %s:%d\n",str,ntohs(dest->sin_port));
// bzero((void *)dest,sizeof(struct sockaddr_in));
eth->dest_addr[Mod_id].sin_family = AF_INET;
inet_pton(AF_INET,dest_ip,&(eth->dest_addr[Mod_id].sin_addr.s_addr));
eth->dest_addr[Mod_id].sin_port=htons(dest_port);
dest_addr_len[Mod_id] = sizeof(struct sockaddr_in);
inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
/* if RRH, then I am the server, so bind */
if (device->func_type == RRH_FUNC ){
if (bind(eth->sockfd[Mod_id],(struct sockaddr *)&eth->dest_addr[Mod_id], dest_addr_len[Mod_id])<0) {
perror("ETHERNET: Cannot bind to socket");
exit(0);
}else {
printf("[RRH] binding mod_%d to %s:%d\n",Mod_id,str,ntohs(eth->dest_addr[Mod_id].sin_port));
}
}else {
printf("[BBU] Connecting to %s:%d\n",str,ntohs(eth->dest_addr[Mod_id].sin_port));
}
return 0;
}
void ethernet_socket_opt (openair0_device *device){
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id=device->Mod_id;
int sndbuf_size=0, rcvbuf_size=0;
socklen_t optlen;
/* chang the MTU of the eth interface */
struct ifreq ifr;
optlen = sizeof(int);
if (getsockopt(eth->sockfd[Mod_id],
SOL_SOCKET,
SO_SNDBUF,
&sndbuf_size,&optlen))
printf("error:getsockopt()\n");
if (getsockopt(eth->sockfd[Mod_id],
SOL_SOCKET,
SO_RCVBUF,
&rcvbuf_size,&optlen))
printf("error:getsockopt()\n");
printf( "sndbuf_size= %d bytes rcvbuf_size= %d bytes\n", sndbuf_size,
rcvbuf_size);
ifr.ifr_addr.sa_family = AF_INET;
//iap->ifa_name is bond1:xx
strncpy(ifr.ifr_name, DEFAULT_IF, sizeof(ifr.ifr_name));
ifr.ifr_mtu = device->openair0_cfg.samples_per_packet*5;
if (ioctl(eth->sockfd[Mod_id], SIOCSIFMTU, (caddr_t)&ifr) < 0 )
perror ("Can't set the MTU");
else
printf("[ETHERNET] %s MTU size has changed to %d\n",DEFAULT_IF,ifr.ifr_mtu);
}
int trx_eth_request(openair0_device *device) {
int Mod_id = device->Mod_id;
eth_state_t *eth = (eth_state_t*)device->priv;
void *msg;
ssize_t msg_len;
/* send to RRH (server) required configuration parameters:
-number of downlink RBs (so that frame/packet size can be set accordingly)
-rx_num_0channels
-tx_num_channels
-rx_freq
-tx_freq
-rxg_mode[4]
-rx_gain
-tx_gain
-rx_bw
-tx_bw
-autocal */
msg=malloc(sizeof(openair0_config_t));
msg_len=sizeof(openair0_config_t);
memcpy(msg,(void*)&device->openair0_cfg,msg_len);
if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&eth->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1){
perror("ETHERNET: ");
exit(0);
}
return 0;
}
int ethernet_write_data(int Mod_id, openair0_timestamp timestamp, const void **buff, int antenna_id, int nsamps)
{
int trx_eth_reply(openair0_device *device) {
void *buff2 = (void*)buff[antenna_id]-sizeof(openair0_timestamp)-(sizeof(int16_t)*2);
int32_t temp0 = *(int32_t *)buff2;
openair0_timestamp temp1 = *(openair0_timestamp *)(buff2+(sizeof(int16_t)*2));
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
char str[INET_ADDRSTRLEN];
void *msg;
ssize_t msg_len;
msg=malloc(sizeof(openair0_config_t));
msg_len=sizeof(openair0_config_t);
/* receive from client (lte-softmodem) */
if (recvfrom(eth->sockfd[Mod_id],
msg,
msg_len,
0,
(struct sockaddr *)&eth->dest_addr[Mod_id],
(socklen_t *)&dest_addr_len[Mod_id])==-1){
perror("ETHERNET: ");
exit(0);
}
memcpy((void*)&device->openair0_cfg,msg,msg_len);
inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
device->openair0_cfg.remote_port =ntohs(eth->dest_addr[Mod_id].sin_port);
device->openair0_cfg.remote_ip=str;
//ethernet_socket_opt (device);
printf("[RRH] write mod_%d %d to %s:%d\n",Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port));
return 1;
}
int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id) {
int n_written;
uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
int sendto_flag =0;
sendto_flag|=MSG_DONTWAIT;
/* buff[antenna_id] 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[antenna_id]-header_size); // (void*)((unsigned char *)buff[antenna_id]-header_size);
/* 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));
//printf("temp0=%d temp=%d\n",temp0,temp1);
//char str[INET_ADDRSTRLEN];
n_written = 0;
((int16_t *)buff2)[0] = 1+(antenna_id<<1);
((int16_t *)buff2)[1] = nsamps;
*((openair0_timestamp *)(buff2+(sizeof(int16_t)*2))) = timestamp;
// printf("Timestamp TX sent : %d\n",timestamp);
// printf("buffer head : %d %d %d %d \n",((int16_t *)buff2)[0],((int16_t *)buff2)[1],((int16_t *)buff2)[2],((int16_t *)buff2)[3]);
while(n_written < nsamps) {
*(int16_t *)(buff2 + sizeof(int16_t))=1+(antenna_id<<1);
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
//inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
//printf("[RRH]write mod_%d %d to %s:%d, len %d, buff %p antenna %d\n",
//Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port),(nsamps<<2)+header_size, buff2, antenna_id);
while(n_written < nsamps) {
/* Send packet */
if ((n_written += sendto(sockfd[Mod_id],
buff2,
(nsamps<<2)+sizeof(openair0_timestamp)+(2*sizeof(int16_t)),
0,
(struct sockaddr*)&dest_addr[Mod_id],
dest_addr_len[Mod_id])) < 0) {
printf("Send failed for Mod_id %d\n",Mod_id);
perror("ETHERNET:");
exit(-1);
if ((n_written += sendto(eth->sockfd[Mod_id],
buff2,
(nsamps<<2)+header_size,
0,
(struct sockaddr*)&eth->dest_addr[Mod_id],
dest_addr_len[Mod_id])) < 0) {
perror("ETHERNET WRITE");
exit(-1);
}
}
/* printf("Buffer head TX: nu=%d an_id=%d ts%d byte_send=%d \n", *(int16_t *)buff2,
*(int16_t *)(buff2 + sizeof(int16_t)),
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
n_written>>2);*/
/* tx buffer values restored */
*(int32_t *)buff2 = temp0;
*(openair0_timestamp *)(buff2+2*sizeof(int16_t)) = temp1;
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
//printf("-----------------temp0=%d temp=%d\n",*(int32_t *)buff2,*(openair0_timestamp *)(buff2 + sizeof(int32_t)));
return n_written;
}
int ethernet_read_data(int Mod_id,openair0_timestamp *timestamp,void **buff, int antenna_id, int nsamps)
{
int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id) {
void *buff2 = (void*)buff[antenna_id]-sizeof(openair0_timestamp);
int bytes_received;
int block_cnt;
int ret;
openair0_timestamp temp = *(openair0_timestamp*)(buff2);
int16_t mesg[2];
char str[INET_ADDRSTRLEN];
uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
//mesg[0] = 0+(antenna_id<<1);
//mesg[1] = nsamps;
inet_ntop(AF_INET, &(dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
/* buff[antenna_id] 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[antenna_id]-header_size);
/* 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));
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
// send command RX for nsamps samples
// printf("requesting %d samples from (%s:%d)\n",nsamps,str,ntohs(dest_addr[Mod_id].sin_port));
//sendto(sockfd[Mod_id],mesg,4,0,(struct sockaddr *)&dest_addr[Mod_id],dest_addr_len[Mod_id]);
// printf("requesting %d samples from (%s:%d)\n",nsamps,str,ntohs(eth->dest_addr[Mod_id].sin_port));
bytes_received=0;
block_cnt=0;
while(bytes_received < (int)((nsamps<<2))) {
//printf("requesting %d bytes\n",(nsamps<<2));
ret=recvfrom(sockfd[Mod_id],
ret=recvfrom(eth->sockfd[Mod_id],
buff2+bytes_received,
(nsamps<<2)+sizeof(openair0_timestamp)-bytes_received,
(nsamps<<2)+header_size-bytes_received,
0,//MSG_DONTWAIT,
(struct sockaddr *)&dest_addr[Mod_id],
&dest_addr_len[Mod_id]);
(struct sockaddr *)&eth->dest_addr[Mod_id],
(socklen_t *)&dest_addr_len[Mod_id]);
//printf("bytes_received %d (ret %d)\n",bytes_received+ret,ret);
if (ret==-1) {
if (errno == EAGAIN) {
perror("ETHERNET: ");
return((nsamps<<2)+sizeof(openair0_timestamp));
perror("ETHERNET READ: ");
return((nsamps<<2) + header_size);
} else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
if (block_cnt == 100) return(-1);
}
} else {
bytes_received+=ret;
}
}
//printf("buffer head : %x %x %x %x \n",((int32_t *)buff2)[0],((int32_t *)buff2)[1],((int32_t *)buff2)[2],((int32_t *)buff2)[3]);
*timestamp = *(openair0_timestamp *)(buff2);
// printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
*(openair0_timestamp *)(buff2) = temp;
/*
printf("Buffer head RX: nu=%d an_id=%d ts%d byte_recv=%d\n", *(int16_t *)buff2,
*(int16_t *)(buff2 + sizeof(int16_t)),
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
ret>>2);*/
/* store the timestamp value from packet's header */
*timestamp = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
/* tx buffer values restored */
*(int32_t *)buff2 = temp0;
*(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
// printf("Received %d samples, timestamp = %d\n",bytes_received>>2,*(int32_t*)timestamp);
return nsamps;
}
int trx_eth_start(openair0_device *openair0)
{
int trx_eth_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int antenna_id, int flags) {
return ethernet_write_data(device,timestamp,buff,nsamps,antenna_id);
}
int16_t mesg[2];
int Mod_id;
Mod_id = openair0->openair0_cfg.Mod_id;
ethernet_socket_init(openair0->openair0_cfg.Mod_id, openair0->openair0_cfg.rrh_ip,openair0->openair0_cfg.rrh_port);
mesg[0] = 1 + 0; //antenna index is 0, to be replaced by the number of active antennas
mesg[1] = openair0->openair0_cfg.samples_per_packet;
sendto(sockfd[Mod_id],mesg,4,0,(struct sockaddr *)&dest_addr[Mod_id],dest_addr_len[Mod_id]);
int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int antenna_id) {
return(ethernet_read_data(device,ptimestamp,buff,nsamps,antenna_id));
}
int openair0_stop(int card) {
return(0);
}
void trx_eth_write(openair0_device *device, openair0_timestamp timestamp, const void **buff, int nsamps, int cc, int flags)
{
int i;
for (i=0; i<cc; i++)
ethernet_write_data(device->Mod_id,timestamp,buff,i,nsamps);
}
int trx_eth_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int cc)
{
int i;
for (i=0; i<cc; i++)
return(ethernet_read_data(device->Mod_id,ptimestamp,buff,i,nsamps));
}
void trx_eth_end(openair0_device *device)
{
int openair0_print_stats(openair0_device* device) {
return(0);
}
int openair0_reset_stats(openair0_device* device) {
int openair0_stop(int dummy) {
return(0);
return 0;
}
void trx_eth_end(openair0_device *device) {
// close all the sockets
}
int num_devices = 0;
int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg)
{
int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg){
printf("ETHERNET: Initializing openair0_device\n");
device->Mod_id = num_devices++;
device->trx_start_func = trx_eth_start;
device->trx_end_func = trx_eth_end;
device->trx_read_func = trx_eth_read;
device->trx_write_func = trx_eth_write;
eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
int card = 0;
memset(eth, 0, sizeof(eth_state_t));
eth->buffer_size = (unsigned int)openair0_cfg[card].samples_per_packet*sizeof(int32_t); // buffer size = 4096 for sample_len of 1024
eth->sample_rate = (unsigned int)openair0_cfg[card].sample_rate;
device->priv = eth;
printf("ETHERNET: Initializing openair0_device for %s ...\n", ((device->func_type == BBU_FUNC) ? "BBU": "RRH"));
device->Mod_id = num_devices++;
device->trx_request_func = trx_eth_request;
device->trx_reply_func = trx_eth_reply;
device->trx_end_func = trx_eth_end;
device->trx_read_func = trx_eth_read;
device->trx_write_func = trx_eth_write;
memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
if (ethernet_socket_init(device)!=0){
return -1;
}
return 0;
}
@@ -1,3 +1,42 @@
/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file ethernet_lib.h
* \brief API to stream I/Q samples over standard ethernet
* \author Katerina Trilyraki, Navid Nikaein
* \date 2015
* \version 0.2
* \company Eurecom
* \maintainer: navid.nikaein@eurecom.fr
* \note
* \warning
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
@@ -8,8 +47,75 @@
#include <net/if.h>
#include <netinet/ether.h>
int ethernet_socket_init(int Mod_id, char *dest_ip,int dest_port);
int ethernet_write_data(int Mod_id, const void *buff, int nsamps,int cc);
typedef struct {
int ethernet_read_data(int Mod_id,void *buff, int nsamps,int cc);
// opaque eth data struct
//struct eth_if *dev;
// An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
int sockfd[4];
struct sockaddr_in dest_addr[4];
unsigned int buffer_size;
unsigned int timeout_ns;
//struct eth_metadata meta_rx;
//struct eth_metadata meta_tx;
unsigned int sample_rate;
// time offset between transmiter timestamp and receiver timestamp;
double tdiff;
// use brf_time_offset to get this value
int tx_forward_nsamps; //166 for 20Mhz
// --------------------------------
// Debug and output control
// --------------------------------
int num_underflows;
int num_overflows;
int num_seq_errors;
int num_rx_errors;
int num_tx_errors;
uint64_t tx_actual_nsamps; // actual number of samples transmitted
uint64_t rx_actual_nsamps;
uint64_t tx_nsamps; // number of planned samples
uint64_t rx_nsamps;
uint64_t tx_count; // number pf packets
uint64_t rx_count;
//openair0_timestamp rx_timestamp;
} eth_state_t;
#define ETH_META_STATUS_OVERRUN (1 << 0)
#define ETH_META_STATUS_UNDERRUN (1 << 1)
struct eth_meta_data{
uint64_t timestamp;
uint32_t flags;
uint32_t status;
unsigned int actual_count;
};
typedef struct {
/* packet's timestamp */
openair0_timestamp timestamp;
/* variable declared for alignment purposes (sample size=32 bit) */
int16_t not_used;
/* antenna port used to resynchronize*/
int16_t antenna_id;
} header_t;
int ethernet_socket_init(openair0_device *device);
int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id);
int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id);
void ethernet_socket_opt (openair0_device *device);