enb_app.c 14.9 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
Cedric Roux's avatar
Cedric Roux committed
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
 */
nikaeinn's avatar
nikaeinn committed
21

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

#include <string.h>
gauthier's avatar
 
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"
46 47 48 49 50 51 52 53
/* temporary warning removale while implementing noS1 */
/* as config option                                   */
#   else
#     ifdef EPC_MODE_ENABLED
#       undef  EPC_MODE_ENABLED
#     endif
#     define EPC_MODE_ENABLED 0
#   endif
54
#   include "x2ap_eNB.h"
55 56 57
#   include "x2ap_messages_types.h"
#   define X2AP_ENB_REGISTER_RETRY_DELAY   10

knopp's avatar
knopp committed
58
#include "openair1/PHY/INIT/phy_init.h"
59
extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
60 61
#endif

62 63
extern RAN_CONTEXT_t RC;

winckel's avatar
winckel committed
64 65
#if defined(ENABLE_ITTI)

66
/*------------------------------------------------------------------------------*/
67 68 69
# if defined(ENABLE_USE_MME)
#   define ENB_REGISTER_RETRY_DELAY 10
# endif
winckel's avatar
winckel committed
70

71 72
#include "targets/RT/USER/lte-softmodem.h"

73
/*------------------------------------------------------------------------------*/
74 75

/*
76
static void configure_phy(module_id_t enb_id, const Enb_properties_array_t* enb_properties)
77
{
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
  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];
  }

94
  itti_send_msg_to_task (TASK_PHY_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
95
}
96
*/
97 98

/*------------------------------------------------------------------------------*/
99
static void configure_rrc(uint32_t enb_id)
winckel's avatar
winckel committed
100
{
101
  MessageDef *msg_p = NULL;
102
  //  int CC_id;
103 104 105

  msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);

106
  if (RC.rrc[enb_id]) {
Cedric Roux's avatar
Cedric Roux committed
107
    RCconfig_RRC(msg_p,enb_id, RC.rrc[enb_id]);
108 109 110 111
    

    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);
112

113 114
  }
  else AssertFatal(0,"RRC context for eNB %d not allocated\n",enb_id);
winckel's avatar
winckel committed
115 116
}

117
/*------------------------------------------------------------------------------*/
118
# if defined(ENABLE_USE_MME)
119
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
120
{
121 122 123
  uint32_t         enb_id;
  MessageDef      *msg_p;
  uint32_t         register_enb_pending = 0;
124

125 126 127 128 129
  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);

130 131 132 133
      RCconfig_S1(msg_p, enb_id);

      if (enb_id == 0) RCconfig_gtpu();

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

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

138
      itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
139 140

      register_enb_pending++;
141
    }
142
  }
winckel's avatar
winckel committed
143

144
  return register_enb_pending;
winckel's avatar
winckel committed
145 146 147 148
}
# endif
#endif

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
/*------------------------------------------------------------------------------*/
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);

164
      itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
165 166 167 168 169 170 171 172

      register_enb_x2_pending++;
    }
  }

  return register_enb_x2_pending;
}

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

195
  itti_mark_task_ready (TASK_ENB_APP);
196

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

199 200 201 202
  RCconfig_L1();

  RCconfig_macrlc();

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

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

207
  AssertFatal (enb_nb <= RC.nb_inst,
208
               "Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
209 210 211 212 213
               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 *));
214
  LOG_I(PHY, "%s() RC.nb_inst:%d RC.rrc:%p\n", __FUNCTION__, RC.nb_inst, RC.rrc);
215

216 217
  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));
218
    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);
219 220 221
    memset((void *)RC.rrc[enb_id],0,sizeof(eNB_RRC_INST));
    configure_rrc(enb_id);
  }
222

winckel's avatar
winckel committed
223
# if defined(ENABLE_USE_MME)
224
  /* Try to register each eNB */
225 226
    registered_enb = 0;
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);//, enb_properties_p);
frtabu's avatar
frtabu committed
227
#else
228
  /* Start L2L1 task */
229 230
    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
231
#endif
winckel's avatar
winckel committed
232

233
  /* Try to register each eNB with each other */
234
  x2_registered_enb = 0;
235
  x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
winckel's avatar
winckel committed
236

237 238 239
  do {
    // Wait for a message
    itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
240

241
    instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
242

243 244
    switch (ITTI_MSG_ID(msg_p)) {
    case TERMINATE_MESSAGE:
245
      LOG_W(ENB_APP, " *** Exiting ENB_APP thread\n");
246 247
      itti_exit_task ();
      break;
winckel's avatar
winckel committed
248

249 250 251
    case MESSAGE_TEST:
      LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
      break;
winckel's avatar
winckel committed
252

253 254 255 256
    case SOFT_RESTART_MESSAGE:
      handle_reconfiguration(instance);
      break;

257
    case S1AP_REGISTER_ENB_CNF:
frtabu's avatar
frtabu committed
258
# if defined(ENABLE_USE_MME)
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 291 292 293 294
  	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
295
#endif
296 297 298
      break;

    case S1AP_DEREGISTERED_ENB_IND:
299 300 301
      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);
302

303 304
  	/* TODO handle recovering of registration */
      }
305 306 307
      break;

    case TIMER_HAS_EXPIRED:
frtabu's avatar
frtabu committed
308
# if defined(ENABLE_USE_MME)
309
      LOG_I(ENB_APP, " Received %s: timer_id %ld\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id);
310 311 312 313

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

317 318 319 320 321
      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
322
# endif
323 324
      break;

325 326 327 328 329
    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 */
330
      break;
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 366 367 368 369
    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
370

371
    default:
372
      LOG_E(ENB_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
373 374 375 376 377 378
      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
379 380 381

#endif

Cedric Roux's avatar
Cedric Roux committed
382

383
  return NULL;
winckel's avatar
winckel committed
384
}
385 386 387 388 389 390 391

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];

Robert Schmidt's avatar
Robert Schmidt committed
392
  LOG_I(ENB_APP, "lte-softmodem soft-restart requested\n");
393

394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
  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) {
Robert Schmidt's avatar
Robert Schmidt committed
411
    LOG_I(ENB_APP, " * eNB %d: Waiting for FlexRAN RTController command *\n", mod_id);
412 413 414 415 416 417 418 419
    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) {
420
    LOG_E(ENB_APP, "can not restart, killing lte-softmodem\n");
421
    exit_fun("can not restart L1L2, killing lte-softmodem");
422 423 424 425 426 427 428 429 430 431 432
    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;
  }
Robert Schmidt's avatar
Robert Schmidt committed
433
  LOG_I(ENB_APP, "lte-softmodem restart succeeded in %ld.%ld s\n", end.tv_sec, end.tv_nsec / 1000000);
434
}