rrh_gw.c 12.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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.0  (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
 */

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

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

Aikaterini's avatar
Aikaterini committed
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;
Aikaterini's avatar
Aikaterini committed
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) {
Cedric Roux's avatar
Cedric Roux committed
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;

Aikaterini's avatar
Aikaterini committed
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;
Aikaterini's avatar
Aikaterini committed
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);   
	}
Aikaterini's avatar
Aikaterini committed
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 345 346 347

  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);
    } 
    ether_ntoa_r ((unsigned char *)ifr.ifr_hwaddr.sa_data, rrh_mac);
    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 379
  timer_t             timerid;    
  struct itimerspec   *timer= (struct itimerspec *)arg ; // the timer data structure
  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 410
  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");
  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);
}