rrh_gw.c 12.7 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 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
 */

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

/*! \file rrh_gw.h
 * \brief top-level for the remote radio head gateway (RRH_gw) module reusing the ethernet library 
 * \author Navid Nikaein,  Katerina Trilyraki, Raymond Knopp
 * \date 2015
 * \version 0.1
 * \company Eurecom
 * \maintainer:  navid.nikaein@eurecom.fr
 * \note
 * \warning very experimental 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <time.h>

#include "common_lib.h"
46
#include "rrh_gw.h"
47
#include "rt_wrapper.h"
48
#include "rrh_gw_externs.h"
49 50 51 52 53 54


#include "log_if.h"
#include "log_extern.h"
#include "vcd_signal_dumper.h"

55 56 57 58 59 60 61 62 63 64
/*****************************************************************************************
 *                                                                        ----------     *
 *     -------    RRH_BBU_IF    -------    RRH_RF_IF     -------USRP      - COTS_UE-     *
 *     - BBU - ---------------  - RRH -  -------------   -------BLADERF   ----------     *
 *     -------                  -------                  -------EXMIMO                   *
 *                                                                        ---------      *
 *                                                       -------ETH_IF    - EMU_UE-      *
 *                                                                        ---------      *                              
 *****************************************************************************************/

65

66 67
/* local IP/MAC address is detected*/
char rrh_ip[20] = "0.0.0.0"; 
68
unsigned char rrh_mac[20] = "0:0:0:0:0:0";
69 70 71 72 73 74 75 76 77 78 79 80 81
int  rrh_port = 50000; // has to be an option

/* log */
int16_t           glog_level          = LOG_DEBUG;
int16_t           glog_verbosity      = LOG_MED;
int16_t           rrh_log_level       = LOG_INFO;
int16_t           rrh_log_verbosity   = LOG_MED;
int16_t           enb_log_level       = LOG_INFO;
int16_t           enb_log_verbosity   = LOG_MED;
int16_t           ue_log_level        = LOG_INFO;
int16_t           ue_log_verbosity    = LOG_MED;


82
/* flag definitions */
83 84 85 86 87 88 89 90
uint8_t 	eNB_flag=0;
uint8_t 	UE_flag=0;
uint8_t 	EXMIMO_flag=0;
uint8_t 	USRP_flag=0;
uint8_t 	RT_flag=0, NRT_flag=1;
uint8_t 	rrh_exit=0;
uint8_t         loopback_flag=0;
uint8_t         measurements_flag=0;
91 92

/* Default operation as RRH:
93
   - there are neither eNB nor UE modules
94 95
   - no RF hardware is specified (NONE_IF)
   - default ethernet interface is local */
96 97
uint8_t 	    num_eNB_mod=0;
uint8_t 	    num_UE_mod=0;
98 99
char*           if_name="lo";
uint8_t         eth_mode=ETH_UDP_MODE;
100

101 102 103
rrh_module_t 	        *enb_array;
rrh_module_t            *ue_array;

104 105
openair0_vtimestamp 	hw_counter=0;

106
char   rf_config_file[1024];
107 108 109 110 111 112 113 114 115 116 117 118 119 120

static void debug_init(void);
static void get_options(int argc, char *argv[]);
static void print_help(void);

/*!\fn static rrh_module_t new_module(unsigned int id);
* \brief creation of a eNB/UE module
* \param[in] module id
* \return module
* \note
* @ingroup  _oai
*/
static rrh_module_t new_module(unsigned int id);

121
/*!\fn static int get_address(char* if_name, uint8_t flag);
122 123 124 125 126 127
 * \brief retrieves IP address from the specified network interface
 * \param[in] name of network interface
 * \return 0 
 * \note
 * @ingroup  _oai
 */
128
static int get_address(char* if_name, uint8_t flag);
129 130 131 132 133 134 135





int main(int argc, char **argv) {
  
136
  unsigned int i;
137
  rf_config_file[0]='\0';
138 139 140 141
  /* parse input arguments */
  get_options(argc, argv);
  /* initialize logger and signal analyzer */
  debug_init();
142
  /* */
143
  set_latency_target();
144
  /* make a graceful exit when ctrl-c is pressed */
145 146
  signal(SIGSEGV, signal_handler);
  signal(SIGINT, signal_handler);
147
  
148
  /* create modules based on input arguments */
149
  if (eNB_flag==1){    
150
    enb_array=(rrh_module_t*)malloc(num_eNB_mod*sizeof(rrh_module_t));	
151 152
    for(i=0;i<num_eNB_mod;i++){  
      enb_array[i]=new_module(i);//enb_array[i]=new_module(i, get_RF_interfaces(&hardware_target));	
153
      config_BBU_mod(&enb_array[i],RT_flag,NRT_flag);
154
      LOG_I(RRH,"[eNB %d] module(s) created (out of %u) \n",i,num_eNB_mod);		
155 156
    }
  }
157
  if (UE_flag==1){    
158 159
    ue_array=(rrh_module_t*)malloc(num_UE_mod*sizeof(rrh_module_t));	
    for(i=0;i<num_UE_mod;i++){
160
      ue_array[i]=new_module(i);
161
      config_UE_mod(&ue_array[i],RT_flag,NRT_flag);			
162
      LOG_I(RRH,"[UE %d] module(s) created (out of %u)\n",i, num_UE_mod);
163 164
    }
  }
165
 
166 167 168 169 170 171 172 173 174
  printf("TYPE <CTRL-C> TO TERMINATE\n");
  
  while (rrh_exit==0)
    sleep(1);

  return EXIT_SUCCESS;
}


175
static rrh_module_t new_module (unsigned int id) {
176 177 178

  rrh_module_t 	  	rrh_mod;
  openair0_config_t 	openair0_cfg;
179

180 181 182
  rrh_mod.id=id;
  rrh_mod.loopback=loopback_flag;
  rrh_mod.measurements=measurements_flag;
183

184
  /* each module is associated with an ethernet device */
185 186
  rrh_mod.eth_dev.type=NONE_DEV;
  rrh_mod.eth_dev.transp_type=NONE_TP;
187
  /* ethernet device is functioning within RRH */
188 189 190 191
  rrh_mod.eth_dev.host_type=RRH_HOST;
  /* */
  rrh_mod.eth_dev.openair0_cfg = (openair0_config_t*)malloc(sizeof(openair0_config_t));
  memset(rrh_mod.eth_dev.openair0_cfg,0,sizeof(openair0_config_t));
192 193
  /* get IP and MAC address */
  get_address(if_name,eth_mode);
194
  
195 196 197 198 199
  if(eth_mode==ETH_UDP_MODE) {
    openair0_cfg.my_addr = &rrh_ip[0];
    openair0_cfg.my_port = rrh_port;
    LOG_I(RRH,"UDP mode selected for ethernet.\n");
  } else if (eth_mode==ETH_RAW_MODE) {
200
    openair0_cfg.my_addr = (char*)&rrh_mac[0];
201 202 203 204
    openair0_cfg.my_port = rrh_port;
    LOG_I(RRH,"RAW mode selected for ethernet.\n");
  } 

205 206 207 208 209
  /* */
  eth_params_t *eth_params = (eth_params_t*)malloc(sizeof(eth_params_t));
  memset(eth_params, 0, sizeof(eth_params_t));
  eth_params->local_if_name     = if_name;
  eth_params->transp_preference = eth_mode;
210

211
  /* ethernet device initialization */
212
  if (openair0_transport_load(&rrh_mod.eth_dev, &openair0_cfg,eth_params)<0) {
213 214 215
    LOG_E(RRH,"Exiting, cannot initialize ethernet interface.\n");
    exit(-1);
  }
216 217

  /* allocate space and specify associated RF device */
218
  openair0_device *oai_dv = (openair0_device *)malloc(sizeof(openair0_device));
219
  memset(oai_dv,0,sizeof(openair0_device));
220

221
  rrh_mod.devs=oai_dv;   
222 223 224 225
  rrh_mod.devs->type=NONE_DEV;
  rrh_mod.devs->transp_type=NONE_TP;
  rrh_mod.devs->host_type=RRH_HOST; 

226 227 228 229
  return rrh_mod;
}

static void debug_init(void) {
230
  
231
  /* log initialization */
232 233 234 235 236 237 238
  logInit();
  set_glog(glog_level,  glog_verbosity);
  
  set_comp_log(RRH,     rrh_log_level,   rrh_log_verbosity, 1);
  //set_comp_log(ENB_LOG, enb_log_level,   enb_log_verbosity, 1);
  //set_comp_log(UE_LOG,  ue_log_level,    ue_log_verbosity,  1);
  
239
  /* vcd initialization */
240
  if (ouput_vcd) {
241
    vcd_signal_dumper_init("/tmp/openair_dump_rrh.vcd");
242
    
243
  }
244
}
245

246

247 248 249 250
static void get_options(int argc, char *argv[]) {

  int 	opt;

251
  while ((opt = getopt(argc, argv, "xvhlte:n:u:g:r:m:i:f:")) != -1) {
252 253 254 255 256 257 258 259 260 261 262 263 264
    
    switch (opt) {
    case 'n':
      eNB_flag=1;
      num_eNB_mod=atoi(optarg);
      break;
    case 'u':
      UE_flag=1;
      num_UE_mod=atoi(optarg);
      break;
    case 'g':
      glog_level=atoi(optarg);
      break;
265 266 267 268 269 270
    case 'i':  
      if (optarg) {
	if_name=strdup(optarg); 
	printf("RRH interface name is set to %s\n", if_name);	
      }
      break;
271 272 273
    case 'm':  
      eth_mode=atoi(optarg);      
      break;
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    case 'r':
      //rrh_log_level=atoi(optarg);
      break;
    case 'e':
      //enb_log_level=atoi(optarg);
      break;
    case 'x':
      rt_period = DEFAULT_PERIOD_NS;
      RT_flag=1;
      NRT_flag=0;
      break;
    case 'v':
      /* extern from vcd */
      ouput_vcd=1;  
      break;
    case 'l':
      /*In loopback mode rrh sends back to bbu what it receives*/
      loopback_flag=1; 
      break;
293
    case 'f':
294 295 296 297 298 299 300 301 302 303 304
      if (optarg){
	if ((strcmp("null", optarg) == 0) || (strcmp("NULL", optarg) == 0)) {
	  printf("no configuration filename is provided\n");
	}
	else if (strlen(optarg)<=1024){
	  // rf_config_file = strdup(optarg);
	  strcpy(rf_config_file,optarg);
	}else {
	  printf("Configuration filename is too long\n");
	  exit(-1);   
	}
305 306
      }
      break;
307
    case 't':
308
      /* When measurements are enabled statistics related to TX/RX time are printed */
309
      measurements_flag=1; 
310 311 312 313
      break;      
    case 'h':
      print_help();
      exit(-1);
314 315 316 317 318 319
    default: /* '?' */
      //fprintf(stderr, "Usage: \n", argv[0]);
      exit(-1);
  }
}

320 321
}

322
static int get_address(char* if_name, uint8_t flag) {
323 324 325
  
  int fd;
  struct ifreq ifr;
326 327
    
  fd = socket(AF_INET, SOCK_DGRAM, 0);  
328
  /* I want to get an IPv4 IP address */
329
  ifr.ifr_addr.sa_family = AF_INET;  
330
  /* I want IP address attached to "if_name" */
331
  strncpy(ifr.ifr_name, if_name, IFNAMSIZ-1);
332 333 334 335 336 337 338 339 340 341 342 343 344

  if (flag==ETH_UDP_MODE) {
    if ( ioctl(fd, SIOCGIFADDR, &ifr)<0 ) {
      perror("IOCTL:");
      exit(-1);
    } 
    snprintf(&rrh_ip[0],20,"%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
    LOG_I(RRH,"%s: IP address: %s\n",if_name,rrh_ip);
  } else if (flag==ETH_RAW_MODE) {
    if ( ioctl(fd, SIOCGIFHWADDR, &ifr)<0 ) {
      perror("IOCTL:");
      exit(-1);
    } 
345
    ether_ntoa_r ((struct ether_addr *)ifr.ifr_hwaddr.sa_data, (char*)rrh_mac);
346 347
    LOG_I(RRH,"%s: MAC address: %s\n",if_name,rrh_mac);    
  }
348 349 350
  
  close(fd);
  return 0;
351
}
352

353

354 355 356
static void print_help(void) {

  puts("Usage: \n");
357
  puts("     sudo -E chrt 99 ./rrh -n1 -g6 -v -t -i lo -m1");
358 359 360 361
  puts("Options:\n");
  puts("\t -n create eNB module\n");
  puts("\t -u create UE module\n");
  puts("\t -g define global log level\n");
362
  puts("\t -i set the RRH interface (default lo)\n");
363
  puts("\t -m set ethernet mode to be used by RRH, valid options: (1:raw, 0:udp) \n");
364 365 366 367 368 369 370 371 372 373
  puts("\t -r define rrh log level\n");
  puts("\t -e define eNB log level\n");
  puts("\t -x enable real time bahaviour\n");
  puts("\t -v enable vcd dump\n");
  puts("\t -l enable loopback mode\n");
  puts("\t -t enable measurements\n");
  puts("\t -h display info\n");

}

374

375
void *timer_proc(void *arg) {
376

377 378
  timer_t             timerid;    
  struct itimerspec   *timer= (struct itimerspec *)arg ; // the timer data structure
Cedric Roux's avatar
Cedric Roux committed
379
  struct itimerspec   old_value;
380

381
  
laurent's avatar
laurent committed
382
#ifdef DEADLINE_SCHEDULER
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
  struct sched_attr attr;
  unsigned int flags = 0;
  
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
  
  attr.sched_policy   = SCHED_DEADLINE;
  attr.sched_runtime  =  (0.1  *  100) * 10000; // 
  attr.sched_deadline =  rt_period-30000;//(0.1  *  100) * 10000; 
  attr.sched_period   =  rt_period;//(0.1  *  100) * 10000; // each TX/RX thread has, as a function of RT PERIOD ?? 
  
  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] timer thread: sched_setattr failed\n");
    exit(-1);
  }
#endif  
  
 if (timer_create (CLOCK_REALTIME, NULL, &timerid) == -1) {
    fprintf (stderr, "couldn't create a timer\n");
    perror (NULL);
    exit (EXIT_FAILURE);
  }
  
  signal(SIGALRM, timer_signal_handler);
  LOG_I(RRH,"Timer has started!\n");
Cedric Roux's avatar
Cedric Roux committed
410
  timer_settime (timerid, 0, timer, &old_value);
411

412 413 414 415 416 417 418
  while (!rrh_exit) {
    sleep(1);
  }
  
  timer_delete(timerid);
  
  return (0);
419 420 421
}


422
void timer_signal_handler(int sig) {
423
  
424 425 426 427 428 429 430
  if (sig == SIGALRM) {
    pthread_mutex_lock(&timer_mutex);
    hw_counter ++;
    pthread_mutex_unlock(&timer_mutex);
     VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_CNT, hw_counter);//USED ELSEWHERE
  }
}
431

432 433

void signal_handler(int sig) {
434
  
435 436
  void *array[10];
  size_t size;
437
  
438 439 440 441 442 443 444
  if (sig==SIGSEGV) {
    // get void*'s for all entries on the stack
    size = backtrace(array, 10);
    
    // print out all the frames to stderr
    fprintf(stderr, "Error: signal %d:\n", sig);
    backtrace_symbols_fd(array, size, 2);
445
    exit(-1);
446 447 448
  } else {
    printf("trying to exit gracefully...\n");
    rrh_exit = 1;
449 450
  }
}
451 452 453 454 455 456 457 458 459 460

void exit_fun(const char* s) {
  if (s != NULL) {
    printf("%s %s() Exiting RRH: %s\n",__FILE__, __FUNCTION__, s);
  }
  rrh_exit = 1;
  exit (-1);
}