enb_app.c 14.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
 * 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
 */
21

22 23 24
/*
                                enb_app.c
                             -------------------
25
  AUTHOR  : Laurent Winckel, Sebastien ROUX, Lionel GAUTHIER, Navid Nikaein
26
  COMPANY : EURECOM
27
  EMAIL   : Lionel.Gauthier@eurecom.fr and Navid Nikaein
28
*/
winckel's avatar
winckel committed
29 30

#include <string.h>
Lionel Gauthier's avatar
 
Lionel Gauthier committed
31
#include <stdio.h>
winckel's avatar
winckel committed
32 33

#include "enb_app.h"
34
#include "enb_config.h"
winckel's avatar
winckel committed
35
#include "assertions.h"
36
#include "common/ran_context.h"
winckel's avatar
winckel committed
37

38
#include "common/utils/LOG/log.h"
winckel's avatar
winckel committed
39 40 41 42 43 44

#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
# if defined(ENABLE_USE_MME)
#   include "s1ap_eNB.h"
#   include "sctp_eNB_task.h"
45
#   include "gtpv1u_eNB_task.h"
frtabu's avatar
frtabu committed
46 47
# else
#    define EPC_MODE_ENABLED 0
winckel's avatar
winckel committed
48
# endif
49

50
#   include "x2ap_eNB.h"
51 52 53
#   include "x2ap_messages_types.h"
#   define X2AP_ENB_REGISTER_RETRY_DELAY   10

54
#include "openair1/PHY/INIT/phy_init.h"
55
extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
56 57
#endif

58 59
extern RAN_CONTEXT_t RC;

winckel's avatar
winckel committed
60 61
#if defined(ENABLE_ITTI)

62
/*------------------------------------------------------------------------------*/
63 64 65
# if defined(ENABLE_USE_MME)
#   define ENB_REGISTER_RETRY_DELAY 10
# endif
winckel's avatar
winckel committed
66

67 68
#include "targets/RT/USER/lte-softmodem.h"

69
/*------------------------------------------------------------------------------*/
70 71

/*
72
static void configure_phy(module_id_t enb_id, const Enb_properties_array_t* enb_properties)
73
{
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
  MessageDef *msg_p;
  int CC_id;

  msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);

  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
    PHY_CONFIGURATION_REQ (msg_p).frame_type[CC_id]              = enb_properties->properties[enb_id]->frame_type[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).prefix_type[CC_id]             = enb_properties->properties[enb_id]->prefix_type[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).downlink_frequency[CC_id]      = enb_properties->properties[enb_id]->downlink_frequency[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[CC_id] = enb_properties->properties[enb_id]->uplink_frequency_offset[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).nb_antennas_tx[CC_id]          = enb_properties->properties[enb_id]->nb_antennas_tx[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).nb_antennas_rx[CC_id]          = enb_properties->properties[enb_id]->nb_antennas_rx[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).tx_gain[CC_id]                 = enb_properties->properties[enb_id]->tx_gain[CC_id];
    PHY_CONFIGURATION_REQ (msg_p).rx_gain[CC_id]                 = enb_properties->properties[enb_id]->rx_gain[CC_id];
  }

90
  itti_send_msg_to_task (TASK_PHY_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
91
}
92
*/
93 94

/*------------------------------------------------------------------------------*/
95
static void configure_rrc(uint32_t enb_id)
96
{
97
  MessageDef *msg_p = NULL;
98
  //  int CC_id;
99 100 101

  msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);

102
  if (RC.rrc[enb_id]) {
Cedric Roux's avatar
Cedric Roux committed
103
    RCconfig_RRC(msg_p,enb_id, RC.rrc[enb_id]);
104 105 106 107
    

    LOG_I(ENB_APP,"Sending configuration message to RRC task\n");
    itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
108

109 110
  }
  else AssertFatal(0,"RRC context for eNB %d not allocated\n",enb_id);
111 112
}

113
/*------------------------------------------------------------------------------*/
114
# if defined(ENABLE_USE_MME)
115
static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end)//, const Enb_properties_array_t *enb_properties)
winckel's avatar
winckel committed
116
{
117 118 119
  uint32_t         enb_id;
  MessageDef      *msg_p;
  uint32_t         register_enb_pending = 0;
120

121 122 123 124 125
  for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
    {
      /* note:  there is an implicit relationship between the data structure and the message name */
      msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);

126 127 128 129
      RCconfig_S1(msg_p, enb_id);

      if (enb_id == 0) RCconfig_gtpu();

130
      LOG_I(ENB_APP,"default drx %d\n",((S1AP_REGISTER_ENB_REQ(msg_p)).default_drx));
131

132 133
      LOG_I(ENB_APP,"[eNB %d] eNB_app_register for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id));

134
      itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
135 136

      register_enb_pending++;
137
    }
138
  }
winckel's avatar
winckel committed
139

140
  return register_enb_pending;
winckel's avatar
winckel committed
141 142 143 144
}
# endif
#endif

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/*------------------------------------------------------------------------------*/
static uint32_t eNB_app_register_x2(uint32_t enb_id_start, uint32_t enb_id_end)
{
  uint32_t         enb_id;
  MessageDef      *msg_p;
  uint32_t         register_enb_x2_pending = 0;

  for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {

    {

      msg_p = itti_alloc_new_message (TASK_ENB_APP, X2AP_REGISTER_ENB_REQ);

      RCconfig_X2(msg_p, enb_id);

160
      itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
161 162 163 164 165 166 167 168

      register_enb_x2_pending++;
    }
  }

  return register_enb_x2_pending;
}

169 170 171
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
winckel's avatar
winckel committed
172
#if defined(ENABLE_ITTI)
173
  uint32_t                        enb_nb = RC.nb_inst; 
174 175
  uint32_t                        enb_id_start = 0;
  uint32_t                        enb_id_end = enb_id_start + enb_nb;
winckel's avatar
winckel committed
176
# if defined(ENABLE_USE_MME)
177
  uint32_t                        register_enb_pending=0;
178 179
  uint32_t                        registered_enb;
  long                            enb_register_retry_timer_id;
180
# endif
181
  uint32_t                        x2_register_enb_pending;
182 183
  uint32_t                        x2_registered_enb;
  long                            x2_enb_register_retry_timer_id;
184
  uint32_t                        enb_id;
185 186 187
  MessageDef                     *msg_p           = NULL;
  instance_t                      instance;
  int                             result;
Cedric Roux's avatar
Cedric Roux committed
188 189 190
  /* for no gcc warnings */
  (void)instance;

191
  itti_mark_task_ready (TASK_ENB_APP);
192

193 194
  LOG_I(PHY, "%s() Task ready initialise structures\n", __FUNCTION__);

195 196 197 198
  RCconfig_L1();

  RCconfig_macrlc();

199
  LOG_I(PHY, "%s() RC.nb_L1_inst:%d\n", __FUNCTION__, RC.nb_L1_inst);
winckel's avatar
winckel committed
200

201
  if (RC.nb_L1_inst>0) AssertFatal(l1_north_init_eNB()==0,"could not initialize L1 north interface\n");
202

203
  AssertFatal (enb_nb <= RC.nb_inst,
204
               "Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
205 206 207 208 209
               enb_nb, RC.nb_inst);

  LOG_I(ENB_APP,"Allocating eNB_RRC_INST for %d instances\n",RC.nb_inst);

  RC.rrc = (eNB_RRC_INST **)malloc(RC.nb_inst*sizeof(eNB_RRC_INST *));
210
  LOG_I(PHY, "%s() RC.nb_inst:%d RC.rrc:%p\n", __FUNCTION__, RC.nb_inst, RC.rrc);
211

212 213
  for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
    RC.rrc[enb_id] = (eNB_RRC_INST*)malloc(sizeof(eNB_RRC_INST));
214
    LOG_I(PHY, "%s() Creating RRC instance RC.rrc[%d]:%p (%d of %d)\n", __FUNCTION__, enb_id, RC.rrc[enb_id], enb_id+1, enb_id_end);
215 216 217
    memset((void *)RC.rrc[enb_id],0,sizeof(eNB_RRC_INST));
    configure_rrc(enb_id);
  }
218

winckel's avatar
winckel committed
219
# if defined(ENABLE_USE_MME)
220
  /* Try to register each eNB */
221 222
    registered_enb = 0;
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);//, enb_properties_p);
frtabu's avatar
frtabu committed
223
#else
224
  /* Start L2L1 task */
225 226
    msg_p = itti_alloc_new_message(TASK_ENB_APP, INITIALIZE_MESSAGE);
    itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p);
frtabu's avatar
frtabu committed
227
#endif
winckel's avatar
winckel committed
228

229
  /* Try to register each eNB with each other */
230
  x2_registered_enb = 0;
231
  x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
winckel's avatar
winckel committed
232

233 234 235
  do {
    // Wait for a message
    itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
236

237
    instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
238

239 240
    switch (ITTI_MSG_ID(msg_p)) {
    case TERMINATE_MESSAGE:
241
      LOG_W(ENB_APP, " *** Exiting ENB_APP thread\n");
242 243
      itti_exit_task ();
      break;
winckel's avatar
winckel committed
244

245 246 247
    case MESSAGE_TEST:
      LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
      break;
winckel's avatar
winckel committed
248

249 250 251 252
    case SOFT_RESTART_MESSAGE:
      handle_reconfiguration(instance);
      break;

253
    case S1AP_REGISTER_ENB_CNF:
frtabu's avatar
frtabu committed
254
# if defined(ENABLE_USE_MME)
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
  	LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p),
  	      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);

  	DevAssert(register_enb_pending > 0);
  	register_enb_pending--;

  	/* Check if at least eNB is registered with one MME */
  	if (S1AP_REGISTER_ENB_CNF(msg_p).nb_mme > 0) {
  	  registered_enb++;
  	}

  	/* Check if all register eNB requests have been processed */
  	if (register_enb_pending == 0) {
  	  if (registered_enb == enb_nb) {
  	    /* If all eNB are registered, start L2L1 task */
  	    MessageDef *msg_init_p;

  	    msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE);
  	    itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p);

  	  } else {
  	    LOG_W(ENB_APP, " %d eNB not associated with a MME, retrying registration in %d seconds ...\n",
  		  enb_nb - registered_enb,  ENB_REGISTER_RETRY_DELAY);

  	    /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
  	    if (timer_setup (ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
  			     NULL, &enb_register_retry_timer_id) < 0) {
  	      LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");

  	      sleep(ENB_REGISTER_RETRY_DELAY);
  	      /* Restart the registration process */
  	      registered_enb = 0;
  	      register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);//, enb_properties_p);
  	    }
  	  }
  	}
frtabu's avatar
frtabu committed
291
#endif
292 293 294
      break;

    case S1AP_DEREGISTERED_ENB_IND:
295 296 297
      if (EPC_MODE_ENABLED) {
  	LOG_W(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p),
  	      S1AP_DEREGISTERED_ENB_IND(msg_p).nb_mme);
298

299 300
  	/* TODO handle recovering of registration */
      }
301 302 303
      break;

    case TIMER_HAS_EXPIRED:
frtabu's avatar
frtabu committed
304
# if defined(ENABLE_USE_MME)
305
      LOG_I(ENB_APP, " Received %s: timer_id %ld\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id);
306 307 308 309

      if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id) {
        /* Restart the registration process */
        registered_enb = 0;
310
        register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);//, enb_properties_p);
311 312
      }

313 314 315 316 317
      if (TIMER_HAS_EXPIRED (msg_p).timer_id == x2_enb_register_retry_timer_id) {
        /* Restart the registration process */
	x2_registered_enb = 0;
        x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
      }
winckel's avatar
winckel committed
318
# endif
319 320
      break;

321 322 323 324 325
    case X2AP_DEREGISTERED_ENB_IND:
      LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p),
            X2AP_DEREGISTERED_ENB_IND(msg_p).nb_x2);

      /* TODO handle recovering of registration */
326
      break;
327

328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    case X2AP_REGISTER_ENB_CNF:
      LOG_I(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p),
            X2AP_REGISTER_ENB_CNF(msg_p).nb_x2);

      DevAssert(x2_register_enb_pending > 0);
      x2_register_enb_pending--;

      /* Check if at least eNB is registered with one target eNB */
      if (X2AP_REGISTER_ENB_CNF(msg_p).nb_x2 > 0) {
        x2_registered_enb++;
      }

      /* Check if all register eNB requests have been processed */
      if (x2_register_enb_pending == 0) {
        if (x2_registered_enb == enb_nb) {
          /* If all eNB are registered, start RRC HO task */

	}else {
          uint32_t x2_not_associated = enb_nb - x2_registered_enb;

          LOG_W(ENB_APP, " %d eNB %s not associated with the target\n",
                x2_not_associated, x2_not_associated > 1 ? "are" : "is");
	  // timer to retry
	  /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
          if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP,
			   INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL,
			   &x2_enb_register_retry_timer_id) < 0) {
            LOG_E(ENB_APP, " Can not start eNB X2AP register: retry timer, use \"sleep\" instead!\n");

            sleep(X2AP_ENB_REGISTER_RETRY_DELAY);
            /* Restart the registration process */
            x2_registered_enb = 0;
            x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
          }
        }
      }

      break;
winckel's avatar
winckel committed
366

367
    default:
368
      LOG_E(ENB_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
369 370 371 372 373 374
      break;
    }

    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
  } while (1);
winckel's avatar
winckel committed
375 376 377

#endif

Cedric Roux's avatar
Cedric Roux committed
378

379
  return NULL;
winckel's avatar
winckel committed
380
}
381 382 383 384 385 386 387

void handle_reconfiguration(module_id_t mod_id)
{
  struct timespec start, end;
  clock_gettime(CLOCK_MONOTONIC, &start);
  flexran_agent_info_t *flexran = RC.flexran[mod_id];

388
  LOG_I(ENB_APP, "lte-softmodem soft-restart requested\n");
389

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
  if (ENB_WAIT == flexran->node_ctrl_state) {
    /* this is already waiting, just release */
    pthread_mutex_lock(&flexran->mutex_node_ctrl);
    flexran->node_ctrl_state = ENB_NORMAL_OPERATION;
    pthread_mutex_unlock(&flexran->mutex_node_ctrl);
    pthread_cond_signal(&flexran->cond_node_ctrl);
    return;
  }

  if (stop_L1L2(mod_id) < 0) {
    LOG_E(ENB_APP, "can not stop lte-softmodem, aborting restart\n");
    return;
  }

  /* node_ctrl_state should have value ENB_MAKE_WAIT only if this method is not
   * executed by the FlexRAN thread */
  if (ENB_MAKE_WAIT == flexran->node_ctrl_state) {
407
    LOG_I(ENB_APP, " * eNB %d: Waiting for FlexRAN RTController command *\n", mod_id);
408 409 410 411 412 413 414 415
    pthread_mutex_lock(&flexran->mutex_node_ctrl);
    flexran->node_ctrl_state = ENB_WAIT;
    while (ENB_NORMAL_OPERATION != flexran->node_ctrl_state)
      pthread_cond_wait(&flexran->cond_node_ctrl, &flexran->mutex_node_ctrl);
    pthread_mutex_unlock(&flexran->mutex_node_ctrl);
  }

  if (restart_L1L2(mod_id) < 0) {
416
    LOG_E(ENB_APP, "can not restart, killing lte-softmodem\n");
417
    exit_fun("can not restart L1L2, killing lte-softmodem");
418 419 420 421 422 423 424 425 426 427 428
    return;
  }

  clock_gettime(CLOCK_MONOTONIC, &end);
  end.tv_sec -= start.tv_sec;
  if (end.tv_nsec >= start.tv_nsec) {
    end.tv_nsec -= start.tv_nsec;
  } else {
    end.tv_sec -= 1;
    end.tv_nsec = end.tv_nsec - start.tv_nsec + 1000000000;
  }
429
  LOG_I(ENB_APP, "lte-softmodem restart succeeded in %ld.%ld s\n", end.tv_sec, end.tv_nsec / 1000000);
430
}