ethernet_lib.c 12.9 KB
Newer Older
knopp's avatar
 
knopp committed
1
/*******************************************************************************
2
    OpenAirInterface
knopp's avatar
 
knopp committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16
    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
17 18
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
knopp's avatar
 
knopp committed
19 20 21 22 23 24
    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
25

knopp's avatar
 
knopp committed
26 27 28
   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

 *******************************************************************************/
29 30 31 32 33 34 35 36 37 38
/*! \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 
 */
knopp's avatar
 
knopp committed
39 40 41 42 43 44 45 46 47 48

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
knopp's avatar
 
knopp committed
49 50
#include <unistd.h>
#include <errno.h>
knopp's avatar
 
knopp committed
51 52

#include "common_lib.h"
53
#include "ethernet_lib.h"
knopp's avatar
 
knopp committed
54

55
#define DEFAULT_IF  "eth0"
56
#define BUF_SIZ      8960 /*Jumbo frame size*/
knopp's avatar
 
knopp committed
57 58
#define MAX_INST        4

59 60
//int sockfd[MAX_INST];
int num_devices = 0;
knopp's avatar
 
knopp committed
61 62
int dest_addr_len[MAX_INST];
char sendbuf[MAX_INST][BUF_SIZ]; /*TODO*/
63

knopp's avatar
 
knopp committed
64

65 66
/* Initialization of UDP Socket to communicate with one destination */
int ethernet_socket_init(openair0_device *device) {
67

68 69 70 71 72
  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];
knopp's avatar
 
knopp committed
73
  char str[INET_ADDRSTRLEN];
74 75 76 77 78 79 80 81 82 83 84 85 86
  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);
  }
    
knopp's avatar
 
knopp committed
87
  /* Open RAW socket to send on */
88
  if ((eth->sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
knopp's avatar
 
knopp committed
89 90 91 92
    perror("ETHERNET: Error opening socket");
    exit(0);
  }

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
  /* initialize destination address */
  for (i=0; i< MAX_INST; i++)  
    bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));

 // 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;
}
knopp's avatar
 
knopp committed
119

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
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);
  
}
knopp's avatar
 
knopp committed
157 158


159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
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;
knopp's avatar
 
knopp committed
190 191 192
}


193

194
int trx_eth_reply(openair0_device *device) {
knopp's avatar
 
knopp committed
195

196 197 198 199 200 201 202 203
  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);
knopp's avatar
 
knopp committed
204

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
  /* 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;
}
225

knopp's avatar
 
knopp committed
226

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
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 + 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) {
knopp's avatar
 
knopp committed
256
    /* Send packet */
257 258 259 260 261 262 263 264
  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);
265
    }
knopp's avatar
 
knopp committed
266
  }
267

268 269 270 271 272 273
/* 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 */  
knopp's avatar
 
knopp committed
274
  *(int32_t *)buff2 = temp0;
275 276
  *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
  //printf("-----------------temp0=%d temp=%d\n",*(int32_t *)buff2,*(openair0_timestamp *)(buff2 + sizeof(int32_t)));
knopp's avatar
 
knopp committed
277
  return n_written;
278

knopp's avatar
 
knopp committed
279 280 281
}


282
int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int antenna_id) {
knopp's avatar
 
knopp committed
283

knopp's avatar
 
knopp committed
284
  int bytes_received;
knopp's avatar
 
knopp committed
285 286
  int block_cnt;
  int ret;
ghaddab's avatar
 
ghaddab committed
287
  char str[INET_ADDRSTRLEN];
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
  uint16_t  header_size=sizeof(int32_t) + sizeof(openair0_timestamp);

  
  /* 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);
knopp's avatar
 
knopp committed
303
  // send command RX for nsamps samples
304
  // printf("requesting %d samples from (%s:%d)\n",nsamps,str,ntohs(eth->dest_addr[Mod_id].sin_port));
knopp's avatar
 
knopp committed
305

ghaddab's avatar
 
ghaddab committed
306
  bytes_received=0;
knopp's avatar
 
knopp committed
307
  block_cnt=0;
308

knopp's avatar
 
knopp committed
309
  while(bytes_received < (int)((nsamps<<2))) {
ghaddab's avatar
 
ghaddab committed
310
    //printf("requesting %d bytes\n",(nsamps<<2));
311
    ret=recvfrom(eth->sockfd[Mod_id],
312
                 buff2+bytes_received,
313
                 (nsamps<<2)+header_size-bytes_received,
314
                 0,//MSG_DONTWAIT,
315 316
                 (struct sockaddr *)&eth->dest_addr[Mod_id],
                 (socklen_t *)&dest_addr_len[Mod_id]);
317

ghaddab's avatar
 
ghaddab committed
318
    //printf("bytes_received %d (ret %d)\n",bytes_received+ret,ret);
knopp's avatar
 
knopp committed
319 320
    if (ret==-1) {
      if (errno == EAGAIN) {
321 322
        perror("ETHERNET READ: ");
        return((nsamps<<2) + header_size);
323 324 325
      } else if (errno == EWOULDBLOCK) {
        block_cnt++;
        usleep(10);
326
	
327
        if (block_cnt == 100) return(-1);
knopp's avatar
 
knopp committed
328
      }
329
    } else {
knopp's avatar
 
knopp committed
330
      bytes_received+=ret;
knopp's avatar
 
knopp committed
331 332
    }
  }
333 334 335 336 337 338 339 340 341 342 343 344 345 346
  /*
    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);
  
ghaddab's avatar
 
ghaddab committed
347
  return nsamps;
348
  
knopp's avatar
 
knopp committed
349 350 351
}


352 353 354
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);
knopp's avatar
 
knopp committed
355 356
}

357 358 359 360
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));
  
knopp's avatar
 
knopp committed
361 362
}

363
int openair0_stop(int card) {
364

365
  return(0);
knopp's avatar
 
knopp committed
366 367 368

}

369
int openair0_print_stats(openair0_device* device) {
knopp's avatar
 
knopp committed
370

371
  return(0);
knopp's avatar
 
knopp committed
372

373 374
}
int openair0_reset_stats(openair0_device* device) {
knopp's avatar
 
knopp committed
375

376
  return(0);
knopp's avatar
 
knopp committed
377

378
}
379 380
void trx_eth_end(openair0_device *device) {
  // close all the sockets
381

382
  
knopp's avatar
 
knopp committed
383 384 385
}


386 387 388 389 390 391 392 393
int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg){

  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; 	
knopp's avatar
 
knopp committed
394

395 396 397 398 399 400 401 402
  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;
  
knopp's avatar
 
knopp committed
403
  memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
404 405 406 407 408 409

  if (ethernet_socket_init(device)!=0){
    return -1;
  }
  
  return 0;
knopp's avatar
 
knopp committed
410
}