ethernet_lib.c 13 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
}

navid's avatar
navid committed
351
352
353
354
int trx_eth_start(openair0_device *device){

  return ethernet_socket_init(device);
}
knopp's avatar
 
knopp committed
355

356
357
358
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
359
360
}

361
362
363
364
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
365
366
}

367
int openair0_stop(int card) {
368

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

}

373
int openair0_print_stats(openair0_device* device) {
knopp's avatar
 
knopp committed
374

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

377
378
}
int openair0_reset_stats(openair0_device* device) {
knopp's avatar
 
knopp committed
379

380
  return(0);
knopp's avatar
 
knopp committed
381

382
}
383
384
void trx_eth_end(openair0_device *device) {
  // close all the sockets
385

386
  
knopp's avatar
 
knopp committed
387
388
389
}


390
391
392
393
394
395
396
397
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
398

399
400
  printf("ETHERNET: Initializing openair0_device for %s ...\n", ((device->func_type == BBU_FUNC) ? "BBU": "RRH"));
  device->Mod_id           = num_devices++;
navid's avatar
navid committed
401
  device->trx_start_func   = trx_eth_start;
402
403
404
405
406
407
  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
408
  memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
409

navid's avatar
navid committed
410
  /*  if (ethernet_socket_init(device)!=0){
411
    return -1;
navid's avatar
navid committed
412
    }*/ 
413
414
  
  return 0;
knopp's avatar
 
knopp committed
415
}