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

laurent's avatar
laurent committed
58
#include <nr-softmodem.h>
59 60
extern RAN_CONTEXT_t RC;

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

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

68
/*------------------------------------------------------------------------------*/
69 70

/*
71
static void configure_phy(module_id_t enb_id, const Enb_properties_array_t* enb_properties)
72
{
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
  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];
  }

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

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

  msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);

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

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

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

112
/*------------------------------------------------------------------------------*/
113
# if defined(ENABLE_USE_MME)
114
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
115
{
116 117 118
  uint32_t         enb_id;
  MessageDef      *msg_p;
  uint32_t         register_enb_pending = 0;
119

120 121 122 123 124
  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);

125 126 127 128
      RCconfig_S1(msg_p, enb_id);

      if (enb_id == 0) RCconfig_gtpu();

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

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

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

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

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

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/*------------------------------------------------------------------------------*/
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);

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

      register_enb_x2_pending++;
    }
  }

  return register_enb_x2_pending;
}

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

190
  itti_mark_task_ready (TASK_ENB_APP);
191

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

194 195 196 197
  RCconfig_L1();

  RCconfig_macrlc();

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

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

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

211 212
  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));
213
    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);
214 215 216
    memset((void *)RC.rrc[enb_id],0,sizeof(eNB_RRC_INST));
    configure_rrc(enb_id);
  }
217

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

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

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

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

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

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

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

252
    case S1AP_REGISTER_ENB_CNF:
frtabu's avatar
frtabu committed
253
# if defined(ENABLE_USE_MME)
254 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
  	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
290
#endif
291 292 293
      break;

    case S1AP_DEREGISTERED_ENB_IND:
294 295 296
      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);
297

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

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

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

312 313 314 315 316
      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
317
# endif
318 319
      break;

320 321 322 323 324
    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 */
325
      break;
326

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
    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
365

366
    default:
367
      LOG_E(ENB_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
368 369 370 371 372 373
      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
374 375 376

#endif

Cedric Roux's avatar
Cedric Roux committed
377

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

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

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

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