Merge branch 'fhg-ta' into fhg-ra
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -51,8 +51,15 @@ int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg);
|
||||
int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg);
|
||||
int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg);
|
||||
|
||||
/* Statistics reply protocol message constructor and destructor */
|
||||
int flexran_agent_mac_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
|
||||
/* Statistics reply protocol message constructors (for UE and cell stats) and destructor */
|
||||
int flexran_agent_mac_stats_reply_ue(mid_t mod_id,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags);
|
||||
int flexran_agent_mac_stats_reply_cell(mid_t mod_id,
|
||||
Protocol__FlexCellStatsReport **cell_report,
|
||||
int n_cc,
|
||||
uint32_t cc_flags);
|
||||
int flexran_agent_mac_destroy_stats_reply(Protocol__FlexStatsReply *reply);
|
||||
|
||||
/* DL MAC scheduling decision protocol message constructor (empty command) and destructor */
|
||||
|
||||
@@ -54,10 +54,9 @@ typedef struct {
|
||||
void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id,
|
||||
Protocol__FlexranMessage **msg);
|
||||
|
||||
/// Notify the controller for a state change of a particular UE, by sending the proper
|
||||
/// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER)
|
||||
// int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti,
|
||||
// uint8_t state_change);
|
||||
/// Notify the controller of another (RU) tick, i.e. new subframe. Used to
|
||||
/// synchronize the eNB and the agent.
|
||||
void (*flexran_agent_notify_tick)(mid_t mod_id);
|
||||
|
||||
|
||||
void *dl_scheduler_loaded_lib;
|
||||
|
||||
@@ -61,12 +61,6 @@ err_code_t flexran_agent_init_cont_mac_stats_update(mid_t mod_id);
|
||||
err_code_t flexran_agent_destroy_cont_mac_stats_update(mid_t mod_id);
|
||||
|
||||
|
||||
/*Enable/Disable the continuous stats update service for the MAC*/
|
||||
err_code_t flexran_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid,
|
||||
stats_request_config_t *stats_req);
|
||||
|
||||
err_code_t flexran_agent_disable_cont_mac_stats_update(mid_t mod_id);
|
||||
|
||||
Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_report,
|
||||
Protocol__FlexranMessage *old_report);
|
||||
|
||||
|
||||
@@ -65,25 +65,17 @@ void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id,
|
||||
|
||||
|
||||
int flexran_agent_pdcp_stats_reply(mid_t mod_id,
|
||||
const report_config_t *report_config,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
Protocol__FlexCellStatsReport **cell_report) {
|
||||
|
||||
|
||||
// Protocol__FlexHeader *header;
|
||||
int i;
|
||||
// int cc_id = 0;
|
||||
|
||||
|
||||
/* Allocate memory for list of UE reports */
|
||||
if (report_config->nr_ue > 0) {
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags) {
|
||||
if (n_ue > 0) {
|
||||
|
||||
for (i = 0; i < report_config->nr_ue; i++) {
|
||||
const rnti_t rnti = report_config->ue_report_type[i].ue_rnti;
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
const rnti_t rnti = ue_report[i]->rnti;
|
||||
const uint16_t uid = flexran_get_pdcp_uid_from_rnti(mod_id, rnti);
|
||||
|
||||
/* Check flag for creation of buffer status report */
|
||||
if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PDCP_STATS) {
|
||||
if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PDCP_STATS) {
|
||||
|
||||
Protocol__FlexPdcpStats *pdcp_aggr_stats;
|
||||
pdcp_aggr_stats = malloc(sizeof(Protocol__FlexPdcpStats));
|
||||
@@ -129,12 +121,6 @@ int flexran_agent_pdcp_stats_reply(mid_t mod_id,
|
||||
|
||||
error:
|
||||
LOG_W(FLEXRAN_AGENT, "Can't allocate PDCP stats\n");
|
||||
|
||||
/* if (cell_report != NULL)
|
||||
free(cell_report);
|
||||
if (ue_report != NULL)
|
||||
free(ue_report);
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
/* Send to the controller all the pdcp stat updates that occured during this subframe*/
|
||||
int flexran_agent_pdcp_stats_reply(mid_t mod_id,
|
||||
const report_config_t *report_config,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
Protocol__FlexCellStatsReport **cell_report);
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags);
|
||||
int flexran_agent_pdcp_destroy_stats_reply(Protocol__FlexStatsReply *reply);
|
||||
|
||||
/* Get the stats from RAN API and aggregate them per USER*/
|
||||
|
||||
@@ -380,18 +380,15 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t* measRes
|
||||
|
||||
|
||||
int flexran_agent_rrc_stats_reply(mid_t mod_id,
|
||||
const report_config_t *report_config,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
Protocol__FlexCellStatsReport **cell_report) {
|
||||
|
||||
if (report_config->nr_ue > 0) {
|
||||
rnti_t rntis[report_config->nr_ue];
|
||||
flexran_get_rrc_rnti_list(mod_id, rntis, report_config->nr_ue);
|
||||
for (int i = 0; i < report_config->nr_ue; i++) {
|
||||
const rnti_t rnti = rntis[i];
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags) {
|
||||
if (n_ue > 0) {
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
const rnti_t rnti = ue_report[i]->rnti;
|
||||
|
||||
/* Check flag for creation of buffer status report */
|
||||
if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) {
|
||||
if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) {
|
||||
|
||||
/*Source cell EUTRA Measurements*/
|
||||
Protocol__FlexRrcMeasurements *rrc_measurements;
|
||||
@@ -531,7 +528,7 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id,
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
for (int i = 0; i < report_config->nr_ue; i++) {
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
if (ue_report[i]->rrc_measurements && ue_report[i]->rrc_measurements->neigh_meas != NULL) {
|
||||
for (int j = 0; j < ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++) {
|
||||
free(ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]);
|
||||
@@ -540,8 +537,6 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id,
|
||||
}
|
||||
}
|
||||
|
||||
if (cell_report != NULL)
|
||||
free(cell_report);
|
||||
if (ue_report != NULL)
|
||||
free(ue_report);
|
||||
return -1;
|
||||
@@ -575,20 +570,18 @@ int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply)
|
||||
}
|
||||
|
||||
int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id,
|
||||
const report_config_t *report_config,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
Protocol__FlexCellStatsReport **cell_report) {
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags) {
|
||||
/* This function fills the GTP part of the statistics. The necessary
|
||||
* information is, for our purposes, completely maintained in the RRC layer.
|
||||
* It would be possible to add a GTP module that handles this, though. */
|
||||
if (report_config->nr_ue > 0) {
|
||||
rnti_t rntis[report_config->nr_ue];
|
||||
flexran_get_rrc_rnti_list(mod_id, rntis, report_config->nr_ue);
|
||||
for (int i = 0; i < report_config->nr_ue; i++) {
|
||||
const rnti_t rnti = rntis[i];
|
||||
if (n_ue > 0) {
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
const rnti_t rnti = ue_report[i]->rnti;
|
||||
|
||||
/* Check flag for creation of buffer status report */
|
||||
if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) {
|
||||
if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) {
|
||||
|
||||
/* get number of rabs for this UE */
|
||||
const int num_e_rab = flexran_agent_rrc_gtp_num_e_rab(mod_id, rnti);
|
||||
@@ -618,7 +611,7 @@ int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id,
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
for (int i = 0; i < report_config->nr_ue; i++) {
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
if (!ue_report[i]->gtp_stats) continue;
|
||||
for (int r = 0; r < ue_report[i]->n_gtp_stats; ++r) {
|
||||
if (ue_report[i]->gtp_stats[r]) {
|
||||
|
||||
@@ -57,12 +57,18 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg);
|
||||
void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t *);
|
||||
|
||||
/* Statistics reply protocol message constructor and destructor */
|
||||
int flexran_agent_rrc_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
|
||||
int flexran_agent_rrc_stats_reply(mid_t mod_id,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags);
|
||||
int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply);
|
||||
|
||||
/* Statistic reply for GTP statistics which OAI stores also in the RRC layer.
|
||||
* This might be moved to a separate GTP module in the future */
|
||||
int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
|
||||
int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags);
|
||||
int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply);
|
||||
|
||||
/* Fill the RRC part of a ue_config message */
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.1 (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
|
||||
*/
|
||||
|
||||
/*! \file flexran_agent_s1ap.c
|
||||
* \brief FlexRAN agent Control Module S1AP
|
||||
* \author Navid Nikaein
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include "flexran_agent_s1ap.h"
|
||||
|
||||
|
||||
/*Array containing the Agent-S1AP interfaces*/
|
||||
AGENT_S1AP_xface *agent_s1ap_xface[NUM_MAX_ENB];
|
||||
|
||||
void flexran_agent_fill_s1ap_cell_config(mid_t mod_id,
|
||||
Protocol__FlexS1apConfig **s1ap_config) {
|
||||
*s1ap_config = malloc(sizeof(Protocol__FlexS1apConfig));
|
||||
if (!*s1ap_config) return;
|
||||
protocol__flex_s1ap_config__init(*s1ap_config);
|
||||
LOG_D(FLEXRAN_AGENT, "flexran_agent_fill_s1ap_cell_config %d\n", mod_id);
|
||||
|
||||
// S1AP status
|
||||
(*s1ap_config)->has_pending = 1;
|
||||
(*s1ap_config)->pending = flexran_get_s1ap_mme_pending(mod_id);
|
||||
|
||||
(*s1ap_config)->has_connected = 1;
|
||||
(*s1ap_config)->connected = flexran_get_s1ap_mme_connected(mod_id);
|
||||
|
||||
(*s1ap_config)->enb_s1_ip = flexran_get_s1ap_enb_s1_ip(mod_id);
|
||||
if (!(*s1ap_config)->enb_s1_ip)
|
||||
(*s1ap_config)->enb_s1_ip = "";
|
||||
|
||||
(*s1ap_config)->enb_name = flexran_get_s1ap_enb_name(mod_id);
|
||||
|
||||
(*s1ap_config)->mme = NULL;
|
||||
(*s1ap_config)->n_mme = flexran_get_s1ap_nb_mme(mod_id);
|
||||
if ((*s1ap_config)->n_mme > 0) {
|
||||
Protocol__FlexS1apMme **mme_conf = calloc((*s1ap_config)->n_mme,
|
||||
sizeof(Protocol__FlexS1apMme *));
|
||||
AssertFatal(mme_conf, "%s(): MME malloc failed\n", __func__);
|
||||
for(int i = 0; i < (*s1ap_config)->n_mme; i++){
|
||||
mme_conf[i] = malloc(sizeof(Protocol__FlexS1apMme));
|
||||
AssertFatal(mme_conf[i], "%s(): MME malloc failed\n", __func__);
|
||||
protocol__flex_s1ap_mme__init(mme_conf[i]);
|
||||
if (flexran_get_s1ap_mme_conf(mod_id, i, mme_conf[i]) < 0) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"error in flexran_get_s1ap_mme_conf(): cannot retrieve MME state\n");
|
||||
(*s1ap_config)->n_mme = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
(*s1ap_config)->mme = mme_conf;
|
||||
}
|
||||
}
|
||||
|
||||
int flexran_agent_s1ap_stats_reply(mid_t mod_id,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags) {
|
||||
if (n_ue <= 0)
|
||||
return 0;
|
||||
if (!(ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_S1AP_STATS))
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
const rnti_t rnti = ue_report[i]->rnti;
|
||||
Protocol__FlexS1apUe *ue = malloc(sizeof(Protocol__FlexS1apUe));
|
||||
AssertFatal(ue, "%s(): MME malloc failed\n", __func__);
|
||||
protocol__flex_s1ap_ue__init(ue);
|
||||
if (flexran_get_s1ap_ue(mod_id, rnti, ue) < 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "error in %s(): cannot retrieve UE conf\n", __func__);
|
||||
break;
|
||||
}
|
||||
ue_report[i]->s1ap_stats = ue;
|
||||
ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_S1AP_STATS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexran_agent_free_s1ap_cell_config(Protocol__FlexS1apConfig **s1ap) {
|
||||
for (int i = 0; i < (*s1ap)->n_mme; i++) {
|
||||
/* following structures allocated in the RAN API */
|
||||
for(int j = 0; j < (*s1ap)->mme[i]->n_served_gummeis; j++) {
|
||||
free((*s1ap)->mme[i]->served_gummeis[j]->plmn);
|
||||
free((*s1ap)->mme[i]->served_gummeis[j]);
|
||||
}
|
||||
free((*s1ap)->mme[i]->served_gummeis);
|
||||
for (int j = 0; j < (*s1ap)->mme[i]->n_requested_plmns; j++)
|
||||
free((*s1ap)->mme[i]->requested_plmns[j]);
|
||||
free((*s1ap)->mme[i]->requested_plmns);
|
||||
free((*s1ap)->mme[i]);
|
||||
}
|
||||
free((*s1ap)->mme);
|
||||
free(*s1ap);
|
||||
*s1ap = NULL;
|
||||
}
|
||||
|
||||
void flexran_agent_s1ap_destroy_stats_reply(Protocol__FlexStatsReply *reply) {
|
||||
for (int i = 0; i < reply->n_ue_report; ++i) {
|
||||
if (!reply->ue_report[i]->s1ap_stats)
|
||||
continue;
|
||||
free(reply->ue_report[i]->s1ap_stats->selected_plmn);
|
||||
free(reply->ue_report[i]->s1ap_stats);
|
||||
reply->ue_report[i]->s1ap_stats = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int flexran_agent_register_s1ap_xface(mid_t mod_id) {
|
||||
if (agent_s1ap_xface[mod_id]) {
|
||||
LOG_E(FLEXRAN_AGENT, "S1AP agent CM for eNB %d is already registered\n", mod_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AGENT_S1AP_xface *xface = malloc(sizeof(AGENT_S1AP_xface));
|
||||
if (!xface) {
|
||||
LOG_E(FLEXRAN_AGENT, "could not allocate memory for S1AP agent xface %d\n", mod_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// not implemented yet
|
||||
xface->flexran_s1ap_notify_release_request=NULL;
|
||||
|
||||
agent_s1ap_xface[mod_id] = xface;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexran_agent_unregister_s1ap_xface(mid_t mod_id) {
|
||||
if (!agent_s1ap_xface[mod_id]) {
|
||||
LOG_E(FLEXRAN_AGENT, "S1AP agent for eNB %d is not registered\n", mod_id);
|
||||
return -1;
|
||||
}
|
||||
agent_s1ap_xface[mod_id]->flexran_s1ap_notify_release_request=NULL;
|
||||
free(agent_s1ap_xface[mod_id]);
|
||||
agent_s1ap_xface[mod_id] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
AGENT_S1AP_xface *flexran_agent_get_s1ap_xface(mid_t mod_id) {
|
||||
return agent_s1ap_xface[mod_id];
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.1 (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
|
||||
*/
|
||||
|
||||
/*! \file flexran_agent_s1ap.h
|
||||
* \brief FlexRAN agent S1AP Control Module
|
||||
* \author navid nikaein
|
||||
* \date 2017
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#ifndef FLEXRAN_AGENT_S1AP_H_
|
||||
#define FLEXRAN_AGENT_S1AP_H_
|
||||
|
||||
#include "header.pb-c.h"
|
||||
#include "flexran.pb-c.h"
|
||||
#include "stats_messages.pb-c.h"
|
||||
#include "stats_common.pb-c.h"
|
||||
|
||||
|
||||
#include "flexran_agent_common.h"
|
||||
#include "flexran_agent_defs.h"
|
||||
#include "flexran_agent_s1ap_defs.h"
|
||||
#include "flexran_agent_ran_api.h"
|
||||
|
||||
/***************************************
|
||||
* FlexRAN agent - technology S1AP API *
|
||||
***************************************/
|
||||
|
||||
/* Send to the controller all the S1AP configs */
|
||||
void flexran_agent_fill_s1ap_cell_config(mid_t mod_id,
|
||||
Protocol__FlexS1apConfig **s1ap_config);
|
||||
|
||||
/* Free allocated S1AP cell configs */
|
||||
void flexran_agent_free_s1ap_cell_config(Protocol__FlexS1apConfig **s1ap);
|
||||
|
||||
/* Fill the stats message for S1AP */
|
||||
int flexran_agent_s1ap_stats_reply(mid_t mod_id,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
int n_ue,
|
||||
uint32_t ue_flags);
|
||||
|
||||
/* Free allocated S1AP stats message */
|
||||
void flexran_agent_s1ap_destroy_stats_reply(Protocol__FlexStatsReply *reply);
|
||||
|
||||
/* Register technology specific interface callbacks */
|
||||
int flexran_agent_register_s1ap_xface(mid_t mod_id);
|
||||
|
||||
/* Unregister technology specific callbacks */
|
||||
int flexran_agent_unregister_s1ap_xface(mid_t mod_id);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.1 (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
|
||||
*/
|
||||
#ifndef __FLEXRAN_AGENT_S1AP_PRIMITIVES_H__
|
||||
#define __FLEXRAN_AGENT_S1AP_PRIMITIVES_H__
|
||||
|
||||
#include "flexran_agent_defs.h"
|
||||
|
||||
/* FLEXRAN AGENT-S1AP Interface */
|
||||
typedef struct {
|
||||
// S1AP statistics
|
||||
void (*flexran_s1ap_notify_release_request)(mid_t mod_id);
|
||||
} AGENT_S1AP_xface;
|
||||
|
||||
#endif
|
||||
@@ -336,3 +336,28 @@ message flex_a5_event {
|
||||
optional int64 time_to_trigger = 4;
|
||||
optional int64 max_report_cells = 5;
|
||||
}
|
||||
|
||||
//
|
||||
// S1AP cell configuration
|
||||
//
|
||||
message flex_gummei {
|
||||
optional flex_plmn plmn = 1;
|
||||
optional uint32 mme_group_id = 2;
|
||||
optional uint32 mme_code = 3;
|
||||
}
|
||||
|
||||
message flex_s1ap_mme {
|
||||
optional string s1_ip = 1; // S1-MME IP of MME
|
||||
optional string name = 2; // S1-MME name of MME
|
||||
optional flex_mme_state state = 3; // State of the MME
|
||||
repeated flex_gummei served_gummeis = 4; // GUMMEIs served by the MME
|
||||
repeated flex_plmn requested_plmns = 5; // PLMNs communicated to MME
|
||||
optional uint32 rel_capacity = 6; // Relative MME capacity, TS23.401
|
||||
}
|
||||
|
||||
enum flex_mme_state {
|
||||
FLMMES_DISCONNECTED = 0;
|
||||
FLMMES_WAITING = 1;
|
||||
FLMMES_CONNECTED = 2;
|
||||
FLMMES_OVERLOAD = 3;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,10 @@ message flex_lc_ue_config {
|
||||
repeated flex_lc_config lc_config = 2; // A list of LC configurations for the given UE
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
message flex_s1ap_config {
|
||||
optional uint32 pending = 1; // number of pending (to be connected) MMEs
|
||||
optional uint32 connected = 2; // number of connected MMEs
|
||||
optional string enb_s1_ip = 3; // S1-MME IP of eNodeB
|
||||
optional string enb_name = 4; // S1-MME name of eNodeB
|
||||
repeated flex_s1ap_mme mme = 5;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import "header.proto";
|
||||
import "time_common.proto";
|
||||
import "config_messages.proto";
|
||||
import "controller_commands.proto";
|
||||
import "control_delegation.proto";
|
||||
import "config_common.proto";
|
||||
|
||||
message flexran_message {
|
||||
@@ -75,12 +74,22 @@ enum flex_bs_capability {
|
||||
PDCP = 5;
|
||||
SDAP = 6;
|
||||
RRC = 7;
|
||||
S1AP = 8;
|
||||
}
|
||||
|
||||
enum flex_bs_split {
|
||||
F1 = 0;
|
||||
nFAPI = 1;
|
||||
IF4 = 2;
|
||||
IF4p5 = 3;
|
||||
IF5 = 4;
|
||||
}
|
||||
|
||||
message flex_hello {
|
||||
optional flex_header header = 1;
|
||||
optional uint64 bs_id = 2; // Unique id to distinguish the eNB
|
||||
repeated flex_bs_capability capabilities = 3;
|
||||
repeated flex_bs_split splits = 4;
|
||||
}
|
||||
|
||||
message flex_echo_request {
|
||||
@@ -147,6 +156,7 @@ message flex_enb_config_reply {
|
||||
optional flex_header header = 1;
|
||||
repeated flex_cell_config cell_config = 3;
|
||||
optional uint32 device_spec = 4;
|
||||
optional flex_s1ap_config s1ap = 5;
|
||||
}
|
||||
|
||||
message flex_ue_config_request {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
syntax = "proto2";
|
||||
package protocol;
|
||||
|
||||
import "config_common.proto"; // for flex_plmn
|
||||
|
||||
//
|
||||
// UE related statistics
|
||||
//
|
||||
@@ -218,25 +220,16 @@ message flex_eutra_cgi_measurements {
|
||||
// Tracking area code of the neighbor cell.
|
||||
optional uint32 tracking_area_code = 2;
|
||||
// Public land mobile network identifiers of neighbor cell.
|
||||
repeated flex_plmn_identity plmn_id = 3;
|
||||
repeated flex_plmn plmn = 3;
|
||||
}
|
||||
|
||||
message flex_cell_global_eutra_id {
|
||||
// Public land mobile network identifier of neighbor cell.
|
||||
optional flex_plmn_identity plmn_id = 1;
|
||||
optional flex_plmn plmn = 1;
|
||||
// Cell identifier of neighbor cell.
|
||||
optional uint32 cell_id = 2;
|
||||
}
|
||||
|
||||
message flex_plmn_identity {
|
||||
// Mobile Network Code (MNC).
|
||||
repeated uint32 mnc = 1;
|
||||
// Mobile Country Code (MCC).
|
||||
repeated uint32 mcc = 2;
|
||||
// tracking area code
|
||||
repeated uint32 tac = 3;
|
||||
}
|
||||
|
||||
message flex_eutra_ref_signal_meas {
|
||||
// Neighboring Cell RSRP
|
||||
optional int32 rsrp = 1;
|
||||
@@ -317,3 +310,15 @@ message flex_gtp_stats {
|
||||
optional uint32 teid_sgw = 4;
|
||||
optional string addr_sgw = 5;
|
||||
}
|
||||
|
||||
//
|
||||
// S1AP stats
|
||||
//
|
||||
|
||||
message flex_s1ap_ue {
|
||||
optional string mme_s1_ip = 1; // IP of MME to which UE is connected
|
||||
optional uint32 enb_ue_s1ap_id = 2; // S1AP ID on eNodeB side for UE
|
||||
optional uint32 mme_ue_s1ap_id = 3; // S1AP ID on MME side for UE
|
||||
optional flex_plmn selected_plmn = 4; // UE-selected PLMN in RRC Conn Setup Cplt
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ message flex_ue_stats_report {
|
||||
optional flex_pdcp_stats pdcp_stats = 11;
|
||||
optional flex_mac_stats mac_stats = 12;
|
||||
repeated flex_gtp_stats gtp_stats = 13;
|
||||
optional flex_s1ap_ue s1ap_stats = 14;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -91,6 +92,7 @@ enum flex_ue_stats_type {
|
||||
|
||||
FLUST_PDCP_STATS = 1024;
|
||||
FLUST_GTP_STATS = 2048;
|
||||
FLUST_S1AP_STATS = 4096;
|
||||
FLUST_RRC_MEASUREMENTS = 65536;
|
||||
// To be extended with more types of stats
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
# include "x2ap_eNB.h"
|
||||
# include "x2ap_messages_types.h"
|
||||
# include "m2ap_eNB.h"
|
||||
# include "m2ap_messages_types.h"
|
||||
# define X2AP_ENB_REGISTER_RETRY_DELAY 10
|
||||
|
||||
#include "openair1/PHY/INIT/phy_init.h"
|
||||
@@ -56,6 +58,90 @@ extern RAN_CONTEXT_t RC;
|
||||
|
||||
# define ENB_REGISTER_RETRY_DELAY 10
|
||||
|
||||
#include "targets/RT/USER/lte-softmodem.h"
|
||||
|
||||
|
||||
/*************************** ENB M2AP **************************/
|
||||
//static uint32_t eNB_app_register_MBMS_STA(ngran_node_t node_type,uint32_t enb_id_start, uint32_t enb_id_end) {
|
||||
// uint32_t enb_id;
|
||||
// //MessageDef *msg_p;
|
||||
// uint32_t register_enb_pending = 0;
|
||||
//
|
||||
// for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
|
||||
// {
|
||||
//
|
||||
// //msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);
|
||||
// //RCconfig_S1(msg_p, enb_id);
|
||||
//
|
||||
// if (enb_id == 0) RCconfig_gtpu();
|
||||
//
|
||||
// //LOG_I(ENB_APP,"default drx %d\n",((S1AP_REGISTER_ENB_REQ(msg_p)).default_drx));
|
||||
//
|
||||
// //LOG_I(ENB_APP,"[eNB %d] eNB_app_register via S1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id));
|
||||
// //itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
|
||||
//
|
||||
// register_enb_pending++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return register_enb_pending;
|
||||
//}
|
||||
//*****end M2AP ****/
|
||||
|
||||
static uint32_t eNB_app_register_m2(uint32_t enb_id_start, uint32_t enb_id_end) {
|
||||
uint32_t enb_id;
|
||||
MessageDef *msg_p;
|
||||
uint32_t register_enb_m2_pending = 0;
|
||||
|
||||
// msg_p = itti_alloc_new_message (TASK_ENB_APP,MESSAGE_TEST );
|
||||
// itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
|
||||
|
||||
LOG_D(ENB_APP,"Register ...\n");
|
||||
|
||||
for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
|
||||
{
|
||||
msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_REGISTER_ENB_REQ);
|
||||
RCconfig_M2(msg_p, enb_id);
|
||||
itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
|
||||
register_enb_m2_pending++;
|
||||
}
|
||||
}
|
||||
|
||||
return register_enb_m2_pending;
|
||||
}
|
||||
|
||||
|
||||
/*************************** M2AP ENB handle **********************************/
|
||||
static uint32_t eNB_app_handle_m2ap_mbms_scheduling_information(instance_t instance){
|
||||
//uint32_t mce_id=0;
|
||||
MessageDef *msg_p;
|
||||
msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SCHEDULING_INFORMATION_RESP);
|
||||
itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
|
||||
return 0;
|
||||
}
|
||||
static uint32_t eNB_app_handle_m2ap_mbms_session_start_req(instance_t instance){
|
||||
//uint32_t mce_id=0;
|
||||
MessageDef *msg_p;
|
||||
msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SESSION_START_RESP);
|
||||
itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
|
||||
return 0;
|
||||
}
|
||||
static uint32_t eNB_app_handle_m2ap_mbms_session_stop_req(instance_t instance){
|
||||
//uint32_t mce_id=0;
|
||||
MessageDef *msg_p;
|
||||
msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SESSION_STOP_RESP);
|
||||
itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
|
||||
return 0;
|
||||
}
|
||||
static uint32_t eNB_app_handle_m2ap_mbms_session_update_req(instance_t instance){
|
||||
//uint32_t mce_id=0;
|
||||
MessageDef *msg_p;
|
||||
msg_p = itti_alloc_new_message (TASK_ENB_APP, M2AP_MBMS_SESSION_UPDATE_RESP);
|
||||
itti_send_msg_to_task (TASK_M2AP_ENB, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//// end M2AP ENB handle **********************************/
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
@@ -126,6 +212,9 @@ void *eNB_app_task(void *args_p) {
|
||||
uint32_t x2_register_enb_pending = 0;
|
||||
uint32_t x2_registered_enb = 0;
|
||||
long x2_enb_register_retry_timer_id;
|
||||
uint32_t m2_register_enb_pending = 0;
|
||||
uint32_t m2_registered_enb = 0;
|
||||
long m2_enb_register_retry_timer_id;
|
||||
MessageDef *msg_p = NULL;
|
||||
instance_t instance;
|
||||
int result;
|
||||
@@ -144,6 +233,22 @@ void *eNB_app_task(void *args_p) {
|
||||
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
|
||||
}
|
||||
|
||||
/* Try to register each eNB with MCE each other */
|
||||
if (is_m2ap_eNB_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) {
|
||||
//eNB_app_register_MBMS_STA(RC.rrc[0]->node_type, enb_id_start, enb_id_end);
|
||||
//m2_register_enb_pending = eNB_app_register_m2 (enb_id_start, enb_id_end);
|
||||
|
||||
if (timer_setup (5, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
|
||||
NULL, &m2_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 (RC.rrc[0]->node_type,enb_id_start, enb_id_end);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
// Wait for a message
|
||||
itti_receive_msg (TASK_ENB_APP, &msg_p);
|
||||
@@ -272,6 +377,12 @@ void *eNB_app_task(void *args_p) {
|
||||
}
|
||||
} /* if (EPC_MODE_ENABLED) */
|
||||
|
||||
if(TIMER_HAS_EXPIRED (msg_p).timer_id == m2_enb_register_retry_timer_id) {
|
||||
|
||||
LOG_I(ENB_APP, " Received %s: timer_id %ld M2 register\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id);
|
||||
m2_register_enb_pending = eNB_app_register_m2 (enb_id_start, enb_id_end);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case X2AP_DEREGISTERED_ENB_IND:
|
||||
@@ -316,6 +427,123 @@ void *eNB_app_task(void *args_p) {
|
||||
|
||||
break;
|
||||
|
||||
case M2AP_DEREGISTERED_ENB_IND:
|
||||
LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p),
|
||||
M2AP_DEREGISTERED_ENB_IND(msg_p).nb_m2);
|
||||
/* TODO handle recovering of registration */
|
||||
break;
|
||||
|
||||
case M2AP_REGISTER_ENB_CNF:
|
||||
LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p),
|
||||
M2AP_REGISTER_ENB_CNF(msg_p).nb_m2);
|
||||
DevAssert(m2_register_enb_pending > 0);
|
||||
m2_register_enb_pending--;
|
||||
|
||||
/* Check if at least eNB is registered with one target eNB */
|
||||
if (M2AP_REGISTER_ENB_CNF(msg_p).nb_m2 > 0) {
|
||||
m2_registered_enb++;
|
||||
}
|
||||
|
||||
/* Check if all register eNB requests have been processed */
|
||||
if (m2_register_enb_pending == 0) {
|
||||
if (m2_registered_enb == enb_nb) {
|
||||
/* If all eNB are registered, start RRC HO task */
|
||||
} else {
|
||||
uint32_t m2_not_associated = enb_nb - m2_registered_enb;
|
||||
LOG_W(ENB_APP, " %d eNB %s not associated with the target\n",
|
||||
m2_not_associated, m2_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;
|
||||
|
||||
case M2AP_SETUP_RESP:
|
||||
LOG_I(ENB_APP,"M2AP_SETUP_RESP RESPONSE received\n");
|
||||
// AssertFatal(NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received F1AP_REGISTER_ENB_CNF in CU/eNB\n");
|
||||
|
||||
// LOG_I(ENB_APP, "Received %s: associated ngran_eNB_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p),
|
||||
// F1AP_SETUP_RESP(msg_p).gNB_CU_name,F1AP_SETUP_RESP(msg_p).num_cells_to_activate);
|
||||
//
|
||||
// handle_f1ap_setup_resp(&F1AP_SETUP_RESP(msg_p));
|
||||
|
||||
// DevAssert(register_enb_pending > 0);
|
||||
// register_enb_pending--;
|
||||
|
||||
// /* Check if at least eNB is registered with one MME */
|
||||
// if (F1AP_SETUP_RESP(msg_p).num_cells_to_activate > 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 cells 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 (RC.rrc[0]->node_type,enb_id_start, enb_id_end);//, enb_properties_p);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
break;
|
||||
|
||||
case M2AP_MBMS_SCHEDULING_INFORMATION:
|
||||
LOG_I(ENB_APP,"M2AP_SCHEDULING_INFORMATION received\n");
|
||||
eNB_app_handle_m2ap_mbms_scheduling_information(ITTI_MESSAGE_GET_INSTANCE(msg_p));
|
||||
break;
|
||||
case M2AP_MBMS_SESSION_START_REQ:
|
||||
LOG_I(ENB_APP,"M2AP_MBMS_SESSION_START_REQ received\n");
|
||||
eNB_app_handle_m2ap_mbms_session_start_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
|
||||
break;
|
||||
case M2AP_MBMS_SESSION_STOP_REQ:
|
||||
LOG_I(ENB_APP,"M2AP_MBMS_SESSION_STOP_REQ received\n");
|
||||
eNB_app_handle_m2ap_mbms_session_stop_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
|
||||
break;
|
||||
case M2AP_RESET:
|
||||
LOG_I(ENB_APP,"M2AP_RESET received\n");
|
||||
break;
|
||||
case M2AP_ENB_CONFIGURATION_UPDATE_ACK:
|
||||
LOG_I(ENB_APP,"M2AP_ENB_CONFIGURATION_UPDATE_ACK received\n");
|
||||
break;
|
||||
case M2AP_ENB_CONFIGURATION_UPDATE_FAILURE:
|
||||
LOG_I(ENB_APP,"M2AP_ENB_CONFIGURATION_UPDATE_FAILURE received\n");
|
||||
break;
|
||||
case M2AP_ERROR_INDICATION:
|
||||
LOG_I(ENB_APP,"M2AP_MBMS_SESSION_UPDATE_REQ\n");
|
||||
eNB_app_handle_m2ap_mbms_session_update_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
|
||||
break;
|
||||
case M2AP_MBMS_SERVICE_COUNTING_REQ:
|
||||
LOG_I(ENB_APP,"M2AP_MBMS_SERVICE_COUNTING_REQ\n");
|
||||
break;
|
||||
case M2AP_MCE_CONFIGURATION_UPDATE:
|
||||
LOG_I(ENB_APP,"M2AP_MCE_CONFIGURATION_UPDATE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(ENB_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
|
||||
break;
|
||||
|
||||
@@ -380,7 +380,6 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) {
|
||||
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
|
||||
//RRC_CONFIGURATION_REQ (msg_p).rrc_inactivity_timer_thres = RRC_INACTIVITY_THRESH; // set to 0 to deactivate
|
||||
// In the configuration file it is in seconds. For RRC it has to be in milliseconds
|
||||
RRC_CONFIGURATION_REQ (msg_p).rrc_inactivity_timer_thres = (*ENBParamList.paramarray[i][ENB_RRC_INACTIVITY_THRES_IDX].uptr) * 1000;
|
||||
RRC_CONFIGURATION_REQ (msg_p).cell_identity = enb_id;
|
||||
@@ -428,6 +427,14 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) {
|
||||
else
|
||||
RRC_CONFIGURATION_REQ (msg_p).enable_x2 = 0;
|
||||
|
||||
/* m2 enabled */
|
||||
if (ENBParamList.paramarray[i][ENB_ENABLE_ENB_M2].strptr != NULL &&
|
||||
*(ENBParamList.paramarray[i][ENB_ENABLE_ENB_M2].strptr) != NULL &&
|
||||
!strcmp(*(ENBParamList.paramarray[i][ENB_ENABLE_ENB_M2].strptr), "yes"))
|
||||
RRC_CONFIGURATION_REQ (msg_p).eMBMS_M2_configured = 1;
|
||||
else
|
||||
RRC_CONFIGURATION_REQ (msg_p).eMBMS_M2_configured = 0;
|
||||
|
||||
// Parse optional physical parameters
|
||||
config_getlist( &CCsParamList,NULL,0,enbpath);
|
||||
LOG_I(RRC,"num component carriers %d \n",CCsParamList.numelt);
|
||||
@@ -2044,6 +2051,266 @@ int RCconfig_gtpu(void ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RCconfig_M2(MessageDef *msg_p, uint32_t i) {
|
||||
int I, J, j, k, l;
|
||||
int enb_id;
|
||||
char *address = NULL;
|
||||
char *cidr = NULL;
|
||||
ccparams_lte_t ccparams_lte;
|
||||
memset((void *)&ccparams_lte,0,sizeof(ccparams_lte_t));
|
||||
paramdef_t ENBSParams[] = ENBSPARAMS_DESC;
|
||||
paramdef_t ENBParams[] = ENBPARAMS_DESC;
|
||||
paramlist_def_t ENBParamList = {ENB_CONFIG_STRING_ENB_LIST,NULL,0};
|
||||
/* get global parameters, defined outside any section in the config file */
|
||||
config_get( ENBSParams,sizeof(ENBSParams)/sizeof(paramdef_t),NULL);
|
||||
checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK;
|
||||
paramdef_t CCsParams[] = CCPARAMS_DESC(ccparams_lte);
|
||||
paramlist_def_t CCsParamList = {ENB_CONFIG_STRING_COMPONENT_CARRIERS, NULL, 0};
|
||||
|
||||
// ccparams_MCE_t MCEconfig;
|
||||
// memset((void *)&MCEconfig,0,sizeof(ccparams_MCE_t));
|
||||
// paramdef_t MCEParams[] = MCEPARAMS_DESC((&MCEconfig));
|
||||
// checkedparam_t config_check_MCEparams[] = MCEPARAMS_CHECK;
|
||||
|
||||
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
for (I = 0; I < (sizeof(CCsParams) / sizeof(paramdef_t)); I++) {
|
||||
CCsParams[I].chkPptr = &(config_check_CCparams[I]);
|
||||
}
|
||||
|
||||
AssertFatal(i < ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt,
|
||||
"Failed to parse config file %s, %uth attribute %s \n",
|
||||
RC.config_file_name, i, ENB_CONFIG_STRING_ACTIVE_ENBS);
|
||||
|
||||
if (ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt > 0) {
|
||||
// Output a list of all eNBs.
|
||||
config_getlist( &ENBParamList,ENBParams,sizeof(ENBParams)/sizeof(paramdef_t),NULL);
|
||||
|
||||
if (ENBParamList.numelt > 0) {
|
||||
for (k = 0; k < ENBParamList.numelt; k++) {
|
||||
if (ENBParamList.paramarray[k][ENB_ENB_ID_IDX].uptr == NULL) {
|
||||
// Calculate a default eNB ID
|
||||
if (EPC_MODE_ENABLED) {
|
||||
uint32_t hash;
|
||||
hash = s1ap_generate_eNB_id ();
|
||||
enb_id = k + (hash & 0xFFFF8);
|
||||
} else {
|
||||
enb_id = k;
|
||||
}
|
||||
} else {
|
||||
enb_id = *(ENBParamList.paramarray[k][ENB_ENB_ID_IDX].uptr);
|
||||
}
|
||||
|
||||
// search if in active list
|
||||
for (j = 0; j < ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt; j++) {
|
||||
if (strcmp(ENBSParams[ENB_ACTIVE_ENBS_IDX].strlistptr[j], *(ENBParamList.paramarray[k][ENB_ENB_NAME_IDX].strptr)) == 0) {
|
||||
paramdef_t PLMNParams[] = PLMNPARAMS_DESC;
|
||||
paramlist_def_t PLMNParamList = {ENB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
||||
|
||||
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
|
||||
paramdef_t M2Params[] = M2PARAMS_DESC;
|
||||
paramlist_def_t M2ParamList = {ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS,NULL,0};
|
||||
paramdef_t SCTPParams[] = SCTPPARAMS_DESC;
|
||||
paramdef_t NETParams[] = NETPARAMS_DESC;
|
||||
paramdef_t MBMSConfigParams[] = MBMS_CONFIG_PARAMS_DESC;
|
||||
paramdef_t MBMSParams[] = MBMSPARAMS_DESC;
|
||||
paramlist_def_t MBMSConfigParamList = {ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST,NULL,0};
|
||||
paramlist_def_t MBMSParamList = {ENB_CONFIG_STRING_MBMS_SERVICE_AREA_LIST,NULL,0};
|
||||
/* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */
|
||||
/* this is most probably a problem with the config module */
|
||||
char aprefix[MAX_OPTNAME_SIZE*80 + 8];
|
||||
sprintf(aprefix,"%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k);
|
||||
/* Some default/random parameters */
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).eNB_id = enb_id;
|
||||
|
||||
if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_MACRO_ENB") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_ENB;
|
||||
} else if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_HOME_ENB") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_HOME_ENB;
|
||||
} else {
|
||||
AssertFatal (0,
|
||||
"Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n",
|
||||
RC.config_file_name, i, *(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr));
|
||||
}
|
||||
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(ENBParamList.paramarray[k][ENB_ENB_NAME_IDX].strptr));
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).tac = *ENBParamList.paramarray[k][ENB_TRACKING_AREA_CODE_IDX].uptr;
|
||||
config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix);
|
||||
|
||||
|
||||
|
||||
// char aprefix2[MAX_OPTNAME_SIZE*80 + 8];
|
||||
// sprintf(aprefix2,"%s.[%i].%s.[0]",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST);
|
||||
// config_getlist(&MBMSParamList, MBMSParams, sizeof(MBMSParams)/sizeof(paramdef_t), aprefix2);
|
||||
// if (MBMSParamList.numelt < 1 || MBMSParamList.numelt > 8)
|
||||
// AssertFatal(0, "The number of MBMS Areas must be in [1,8], but is %d\n",
|
||||
// MBMSParamList.numelt);
|
||||
// M2AP_REGISTER_ENB_REQ (msg_p).num_mbms_service_area_list = MBMSParamList.numelt;
|
||||
// for(J=0; J<MBMSParamList.numelt;J++){
|
||||
// M2AP_REGISTER_ENB_REQ (msg_p).mbms_service_area_list[J] = *MBMSParamList.paramarray[J][ENB_MBMS_SERVICE_AREA_IDX].uptr;
|
||||
// }
|
||||
//
|
||||
|
||||
char aprefix2[MAX_OPTNAME_SIZE*80 + 8];
|
||||
sprintf(aprefix2,"%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k);
|
||||
config_getlist(&MBMSConfigParamList, MBMSConfigParams, sizeof(MBMSConfigParams)/sizeof(paramdef_t), aprefix2);
|
||||
if (MBMSConfigParamList.numelt < 1 || MBMSConfigParamList.numelt > 8)
|
||||
AssertFatal(0, "The number of MBMS Config Data must be in [1,8], but is %d\n",
|
||||
MBMSConfigParamList.numelt);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).num_mbms_configuration_data_list = MBMSConfigParamList.numelt;
|
||||
for(int I=0; I < MBMSConfigParamList.numelt; I++){
|
||||
|
||||
sprintf(aprefix2,"%s.[%i].%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST,I);
|
||||
config_getlist(&MBMSParamList, MBMSParams, sizeof(MBMSParams)/sizeof(paramdef_t), aprefix2);
|
||||
if (MBMSParamList.numelt < 1 || MBMSParamList.numelt > 8)
|
||||
AssertFatal(0, "The number of MBMS Areas must be in [1,8], but is %d\n",
|
||||
MBMSParamList.numelt);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).mbms_configuration_data_list[I].num_mbms_service_area_list = MBMSParamList.numelt;
|
||||
for(J=0; J<MBMSParamList.numelt;J++){
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).mbms_configuration_data_list[I].mbms_service_area_list[J] = *MBMSParamList.paramarray[J][ENB_MBMS_SERVICE_AREA_IDX].uptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
||||
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
||||
PLMNParamList.numelt);
|
||||
|
||||
if (PLMNParamList.numelt > 1)
|
||||
LOG_W(M2AP, "M2AP currently handles only one PLMN, ignoring the others!\n");
|
||||
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][ENB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][ENB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][ENB_MNC_DIGIT_LENGTH].u8ptr;
|
||||
AssertFatal(M2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3
|
||||
|| M2AP_REGISTER_ENB_REQ(msg_p).mnc < 100,
|
||||
"MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n",
|
||||
M2AP_REGISTER_ENB_REQ(msg_p).mnc);
|
||||
/* CC params */
|
||||
config_getlist(&CCsParamList, NULL, 0, aprefix);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).num_cc = CCsParamList.numelt;
|
||||
|
||||
if (CCsParamList.numelt > 0) {
|
||||
//char ccspath[MAX_OPTNAME_SIZE*2 + 16];
|
||||
for (J = 0; J < CCsParamList.numelt ; J++) {
|
||||
sprintf(aprefix, "%s.[%i].%s.[%i]", ENB_CONFIG_STRING_ENB_LIST, k, ENB_CONFIG_STRING_COMPONENT_CARRIERS, J);
|
||||
config_get(CCsParams, sizeof(CCsParams)/sizeof(paramdef_t), aprefix);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).eutra_band[J] = ccparams_lte.eutra_band;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).downlink_frequency[J] = (uint32_t) ccparams_lte.downlink_frequency;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).uplink_frequency_offset[J] = (unsigned int) ccparams_lte.uplink_frequency_offset;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).Nid_cell[J]= ccparams_lte.Nid_cell;
|
||||
|
||||
if (ccparams_lte.Nid_cell>503) {
|
||||
AssertFatal (0,
|
||||
"Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for Nid_cell choice: 0...503 !\n",
|
||||
RC.config_file_name, k, ccparams_lte.Nid_cell);
|
||||
}
|
||||
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J]= ccparams_lte.N_RB_DL;
|
||||
|
||||
if ((ccparams_lte.N_RB_DL!=6) && (ccparams_lte.N_RB_DL!=15) && (ccparams_lte.N_RB_DL!=25) && (ccparams_lte.N_RB_DL!=50) && (ccparams_lte.N_RB_DL!=75) && (ccparams_lte.N_RB_DL!=100)) {
|
||||
AssertFatal (0,
|
||||
"Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for N_RB_DL choice: 6,15,25,50,75,100 !\n",
|
||||
RC.config_file_name, k, ccparams_lte.N_RB_DL);
|
||||
}
|
||||
|
||||
if (strcmp(ccparams_lte.frame_type, "FDD") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = FDD;
|
||||
} else if (strcmp(ccparams_lte.frame_type, "TDD") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
|
||||
} else {
|
||||
AssertFatal (0,
|
||||
"Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n",
|
||||
RC.config_file_name, k, ccparams_lte.frame_type);
|
||||
}
|
||||
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_DL[J] = to_earfcn_DL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency, ccparams_lte.N_RB_DL);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_UL[J] = to_earfcn_UL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency + ccparams_lte.uplink_frequency_offset, ccparams_lte.N_RB_DL);
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(aprefix,"%s.[%i]",ENB_CONFIG_STRING_ENB_LIST,k);
|
||||
config_getlist( &M2ParamList,M2Params,sizeof(M2Params)/sizeof(paramdef_t),aprefix);
|
||||
AssertFatal(M2ParamList.numelt <= M2AP_MAX_NB_ENB_IP_ADDRESS,
|
||||
"value of M2ParamList.numelt %d must be lower than M2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase M2AP_MAX_NB_ENB_IP_ADDRESS\n",
|
||||
M2ParamList.numelt,M2AP_MAX_NB_ENB_IP_ADDRESS);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).nb_m2 = 0;
|
||||
|
||||
for (l = 0; l < M2ParamList.numelt; l++) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).nb_m2 += 1;
|
||||
strcpy(M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4_address,*(M2ParamList.paramarray[l][ENB_M2_IPV4_ADDRESS_IDX].strptr));
|
||||
strcpy(M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6_address,*(M2ParamList.paramarray[l][ENB_M2_IPV6_ADDRESS_IDX].strptr));
|
||||
|
||||
if (strcmp(*(M2ParamList.paramarray[l][ENB_M2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4 = 1;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6 = 0;
|
||||
} else if (strcmp(*(M2ParamList.paramarray[l][ENB_M2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4 = 0;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6 = 1;
|
||||
} else if (strcmp(*(M2ParamList.paramarray[l][ENB_M2_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) {
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv4 = 1;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).target_mce_m2_ip_address[l].ipv6 = 1;
|
||||
}
|
||||
}
|
||||
// timers
|
||||
//{
|
||||
// int t_reloc_prep = 0;
|
||||
// int tx2_reloc_overall = 0;
|
||||
// paramdef_t p[] = {
|
||||
// { "t_reloc_prep", "t_reloc_prep", 0, iptr:&t_reloc_prep, defintval:0, TYPE_INT, 0 },
|
||||
// { "tx2_reloc_overall", "tx2_reloc_overall", 0, iptr:&tx2_reloc_overall, defintval:0, TYPE_INT, 0 }
|
||||
// };
|
||||
// config_get(p, sizeof(p)/sizeof(paramdef_t), aprefix);
|
||||
|
||||
// if (t_reloc_prep <= 0 || t_reloc_prep > 10000 ||
|
||||
// tx2_reloc_overall <= 0 || tx2_reloc_overall > 20000) {
|
||||
// LOG_E(M2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_overall <= 20000]\n");
|
||||
// exit(1);
|
||||
// }
|
||||
|
||||
// M2AP_REGISTER_ENB_REQ (msg_p).t_reloc_prep = t_reloc_prep;
|
||||
// M2AP_REGISTER_ENB_REQ (msg_p).tx2_reloc_overall = tx2_reloc_overall;
|
||||
//}
|
||||
// SCTP SETTING
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
||||
|
||||
if (EPC_MODE_ENABLED) {
|
||||
sprintf(aprefix,"%s.[%i].%s",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_SCTP_CONFIG);
|
||||
config_get( SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[ENB_SCTP_INSTREAMS_IDX].uptr);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[ENB_SCTP_OUTSTREAMS_IDX].uptr);
|
||||
}
|
||||
|
||||
sprintf(aprefix,"%s.[%i].%s",ENB_CONFIG_STRING_ENB_LIST,k,ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
||||
// NETWORK_INTERFACES
|
||||
config_get( NETParams,sizeof(NETParams)/sizeof(paramdef_t),aprefix);
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_M2C = (uint32_t)*(NETParams[ENB_PORT_FOR_M2C_IDX].uptr);
|
||||
|
||||
if ((NETParams[ENB_IPV4_ADDR_FOR_M2C_IDX].strptr == NULL) || (M2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_M2C == 0)) {
|
||||
LOG_E(RRC,"Add eNB IPv4 address and/or port for M2C in the CONF file!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cidr = *(NETParams[ENB_IPV4_ADDR_FOR_M2C_IDX].strptr);
|
||||
address = strtok(cidr, "/");
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).enb_m2_ip_address.ipv6 = 0;
|
||||
M2AP_REGISTER_ENB_REQ (msg_p).enb_m2_ip_address.ipv4 = 1;
|
||||
strcpy(M2AP_REGISTER_ENB_REQ (msg_p).enb_m2_ip_address.ipv4_address, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
* Configure the s1ap_register_enb_req in itti message for future
|
||||
@@ -2842,4 +3109,6 @@ void read_config_and_init(void) {
|
||||
memset((void *)RC.rrc[enb_id], 0, sizeof(eNB_RRC_INST));
|
||||
RCconfig_RRC(enb_id, RC.rrc[enb_id],macrlc_has_f1[enb_id]);
|
||||
}
|
||||
|
||||
RCconfig_flexran();
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ int RCconfig_S1(MessageDef *msg_p, uint32_t i);
|
||||
|
||||
void read_config_and_init(void);
|
||||
int RCconfig_X2(MessageDef *msg_p, uint32_t i);
|
||||
int RCconfig_M2(MessageDef *msg_p, uint32_t i);
|
||||
|
||||
void fill_SL_configuration(MessageDef *msg_p, ccparams_sidelink_t *SLconfig,int cell_idx,int cc_idx,char *config_fname);
|
||||
void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, int cell_idx,int cc_idx,char *config_fname,char *brparamspath);
|
||||
|
||||
@@ -205,6 +205,8 @@ typedef enum {
|
||||
#define ENB_CONFIG_STRING_RRC_INACTIVITY_THRESHOLD "rrc_inactivity_threshold"
|
||||
#define ENB_CONFIG_STRING_MEASUREMENT_REPORTS "enable_measurement_reports"
|
||||
#define ENB_CONFIG_STRING_X2 "enable_x2"
|
||||
#define ENB_CONFIG_STRING_ENB_M2 "enable_enb_m2"
|
||||
#define ENB_CONFIG_STRING_MCE_M2 "enable_mce_m2"
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* cell configuration parameters */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
@@ -228,7 +230,10 @@ typedef enum {
|
||||
{ENB_CONFIG_STRING_RRC_INACTIVITY_THRESHOLD, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
|
||||
{ENB_CONFIG_STRING_MEASUREMENT_REPORTS, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_X2, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_ENB_M2, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_MCE_M2, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
|
||||
}
|
||||
|
||||
#define ENB_ENB_ID_IDX 0
|
||||
#define ENB_CELL_TYPE_IDX 1
|
||||
#define ENB_ENB_NAME_IDX 2
|
||||
@@ -247,6 +252,8 @@ typedef enum {
|
||||
#define ENB_RRC_INACTIVITY_THRES_IDX 15
|
||||
#define ENB_ENABLE_MEASUREMENT_REPORTS 16
|
||||
#define ENB_ENABLE_X2 17
|
||||
#define ENB_ENABLE_ENB_M2 18
|
||||
#define ENB_ENABLE_MCE_M2 19
|
||||
|
||||
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
|
||||
#define ENBPARAMS_CHECK { \
|
||||
@@ -266,6 +273,8 @@ typedef enum {
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
@@ -300,6 +309,32 @@ typedef enum {
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define ENB_CONFIG_STRING_MBMS_CONFIGURATION_DATA_LIST "mbms_configuration_data_list"
|
||||
|
||||
#define ENB_CONFIG_STRING_MBMS_SYNC_AREA "mbms_sync_area"
|
||||
|
||||
#define ENB_MBMS_SYNC_AREA_IDX 0
|
||||
|
||||
#define MBMS_CONFIG_PARAMS_DESC { \
|
||||
/* optname helpstr paramflags XXXptr def val type numelt */ \
|
||||
{ENB_CONFIG_STRING_MBMS_SYNC_AREA , NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define ENB_CONFIG_STRING_MBMS_SERVICE_AREA_LIST "mbms_service_area_list"
|
||||
|
||||
#define ENB_CONFIG_STRING_MBMS_SERVICE_AREA "mbms_service_area"
|
||||
|
||||
#define ENB_MBMS_SERVICE_AREA_IDX 0
|
||||
|
||||
#define MBMSPARAMS_DESC { \
|
||||
/* optname helpstr paramflags XXXptr def val type numelt */ \
|
||||
{ENB_CONFIG_STRING_MBMS_SERVICE_AREA, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
/* component carries configuration parameters name */
|
||||
|
||||
#define ENB_CONFIG_STRING_NB_ANT_PORTS "nb_antenna_ports"
|
||||
@@ -912,6 +947,39 @@ typedef struct srb1_params_s {
|
||||
#define ENB_X2_IPV4_ADDRESS_IDX 0
|
||||
#define ENB_X2_IPV6_ADDRESS_IDX 1
|
||||
#define ENB_X2_IP_ADDRESS_PREFERENCE_IDX 2
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* M2 configuration parameters section name */
|
||||
#define ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS "target_mce_m2_ip_address"
|
||||
|
||||
/* M2 configuration parameters names */
|
||||
|
||||
|
||||
#define ENB_CONFIG_STRING_TARGET_MCE_M2_IPV4_ADDRESS "ipv4"
|
||||
#define ENB_CONFIG_STRING_TARGET_MCE_M2_IPV6_ADDRESS "ipv6"
|
||||
#define ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS_PREFERENCE "preference"
|
||||
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* M2 configuration parameters */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define M2PARAMS_DESC { \
|
||||
{ENB_CONFIG_STRING_TARGET_MCE_M2_IPV4_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_TARGET_MCE_M2_IPV6_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_TARGET_MCE_M2_IP_ADDRESS_PREFERENCE, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
}
|
||||
|
||||
#define ENB_M2_IPV4_ADDRESS_IDX 0
|
||||
#define ENB_M2_IPV6_ADDRESS_IDX 1
|
||||
#define ENB_M2_IP_ADDRESS_PREFERENCE_IDX 2
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* SCTP configuration parameters section name */
|
||||
#define ENB_CONFIG_STRING_SCTP_CONFIG "SCTP"
|
||||
@@ -945,7 +1013,10 @@ typedef struct srb1_params_s {
|
||||
#define ENB_PORT_FOR_S1U_IDX 4
|
||||
#define ENB_IPV4_ADDR_FOR_X2C_IDX 5
|
||||
#define ENB_PORT_FOR_X2C_IDX 6
|
||||
|
||||
#define ENB_IPV4_ADDR_FOR_M2C_IDX 7
|
||||
#define ENB_PORT_FOR_M2C_IDX 8
|
||||
#define MCE_IPV4_ADDR_FOR_M2C_IDX 9
|
||||
#define MCE_PORT_FOR_M2C_IDX 10
|
||||
|
||||
/* S1 interface configuration parameters names */
|
||||
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME "ENB_INTERFACE_NAME_FOR_S1_MME"
|
||||
@@ -958,6 +1029,13 @@ typedef struct srb1_params_s {
|
||||
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C "ENB_IPV4_ADDRESS_FOR_X2C"
|
||||
#define ENB_CONFIG_STRING_ENB_PORT_FOR_X2C "ENB_PORT_FOR_X2C"
|
||||
|
||||
/* M2 interface configuration parameters names */
|
||||
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_M2C "ENB_IPV4_ADDRESS_FOR_M2C"
|
||||
#define ENB_CONFIG_STRING_ENB_PORT_FOR_M2C "ENB_PORT_FOR_M2C"
|
||||
#define ENB_CONFIG_STRING_MCE_IPV4_ADDR_FOR_M2C "MCE_IPV4_ADDRESS_FOR_M2C"
|
||||
#define ENB_CONFIG_STRING_MCE_PORT_FOR_M2C "MCE_PORT_FOR_M2C"
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* S1/X2 interface configuration parameters */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
@@ -970,6 +1048,10 @@ typedef struct srb1_params_s {
|
||||
{ENB_CONFIG_STRING_ENB_PORT_FOR_S1U, NULL, 0, uptr:NULL, defintval:2152L, TYPE_UINT, 0}, \
|
||||
{ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_ENB_PORT_FOR_X2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0}, \
|
||||
{ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_M2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_ENB_PORT_FOR_M2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0}, \
|
||||
{ENB_CONFIG_STRING_MCE_IPV4_ADDR_FOR_M2C, NULL, 0, strptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{ENB_CONFIG_STRING_MCE_PORT_FOR_M2C, NULL, 0, uptr:NULL, defintval:0L, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
@@ -988,8 +1070,6 @@ typedef struct srb1_params_s {
|
||||
#define CONFIG_STRING_L1_LIST "L1s"
|
||||
#define CONFIG_STRING_L1_CONFIG "l1_config"
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
@@ -1145,4 +1225,6 @@ typedef struct srb1_params_s {
|
||||
|
||||
#include "enb_paramdef_emtc.h"
|
||||
#include "enb_paramdef_sidelink.h"
|
||||
#include "enb_paramdef_mce.h"
|
||||
#include "enb_paramdef_mme.h"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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.1 (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
|
||||
*/
|
||||
|
||||
/*! \file openair2/ENB_APP/enb_paramdef_mce.h
|
||||
* \brief definition of configuration parameters for MCE modules
|
||||
* \author Javier MORGADE
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
* \company VICOMTECH Spain
|
||||
* \email: javier.morgade@ieee.org
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include "common/config/config_paramdesc.h"
|
||||
#include "RRC_paramsvalues.h"
|
||||
|
||||
|
||||
|
||||
/* mce configuration parameters names */
|
||||
|
||||
#define MCE_CONFIG_STRING_MCE_ID "MCE_ID"
|
||||
#define MCE_CONFIG_STRING_MCE_NAME "MCE_name"
|
||||
#define MCE_CONFIG_STRING_MCE_M2 "enable_mce_m2"
|
||||
#define MCE_CONFIG_STRING_MCE_M3 "enable_mce_m3"
|
||||
|
||||
#define MCE_PARAMS_DESC {\
|
||||
{MCE_CONFIG_STRING_MCE_ID, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_NAME, NULL, 0, strptr:NULL, defstrval:"OAIMCE", TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_M2, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_M3, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
|
||||
}
|
||||
|
||||
#define MCE_MCE_ID_IDX 0
|
||||
#define MCE_MCE_NAME_IDX 1
|
||||
#define MCE_ENABLE_MCE_M2_IDX 2
|
||||
#define MCE_ENABLE_MCE_M3_IDX 3
|
||||
|
||||
#define MCE_PARAMS_CHECK { \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
}
|
||||
|
||||
|
||||
#define MCE_CONFIG_STRING_NETWORK_INTERFACES_CONFIG "NETWORK_INTERFACES"
|
||||
|
||||
#define MCE2_INTERFACE_NAME_FOR_M2_ENB_IDX 0
|
||||
#define MCE2_IPV4_ADDR_FOR_M2C_IDX 1
|
||||
#define MCE2_PORT_FOR_M2C_IDX 2
|
||||
#define MCE2_INTERFACE_NAME_FOR_M3_MME_IDX 3
|
||||
#define MCE2_IPV4_ADDR_FOR_M3C_IDX 4
|
||||
#define MCE2_PORT_FOR_M3C_IDX 5
|
||||
|
||||
/* interface configuration parameters names */
|
||||
/* M2 interface configuration parameters names */
|
||||
#define MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M2_ENB "ENB_INTERFACE_NAME_FOR_M2_ENB"
|
||||
#define MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M2C "MCE_IPV4_ADDRESS_FOR_M2C"
|
||||
#define MCE_CONFIG_STRING_MCE_PORT_FOR_M2C "MCE_PORT_FOR_M2C"
|
||||
|
||||
/* M3 interface configuration parameters names */
|
||||
#define MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M3_MME "MCE_INTERFACE_NAME_FOR_M3_MME"
|
||||
#define MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M3C "MCE_IPV4_ADDRESS_FOR_M3C"
|
||||
#define MCE_CONFIG_STRING_MCE_PORT_FOR_M3C "MCE_PORT_FOR_M3C"
|
||||
|
||||
|
||||
#define MCE_NETPARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M2_ENB, NULL, 0, strptr:&mce_interface_name_for_m2_enb, defstrval:"lo", TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M2C, NULL, 0, strptr:&mce_ipv4_address_for_m2c, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_PORT_FOR_M2C, NULL, 0, uptr:&mce_port_for_m2c, defintval:36443L, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_INTERFACE_NAME_FOR_M3_MME, NULL, 0, strptr:&mce_interface_name_for_m3_mme, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_IPV4_ADDRESS_FOR_M3C, NULL, 0, strptr:&mce_ipv4_address_for_m3c, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_MCE_PORT_FOR_M3C, NULL, 0, uptr:&mce_port_for_m3c, defintval:36444L, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* M3 configuration parameters */
|
||||
/* M3 configuration parameters section name */
|
||||
#define MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS "target_mme_m3_ip_address"
|
||||
/* M3 configuration parameters names */
|
||||
#define MCE_CONFIG_STRING_TARGET_MME_M3_IPV4_ADDRESS "ipv4"
|
||||
#define MCE_CONFIG_STRING_TARGET_MME_M3_IPV6_ADDRESS "ipv6"
|
||||
#define MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS_PREFERENCE "preference"
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
#define M3PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_TARGET_MME_M3_IPV4_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_TARGET_MME_M3_IPV6_ADDRESS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_TARGET_MME_M3_IP_ADDRESS_PREFERENCE, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
}
|
||||
|
||||
#define MCE2_M3_IPV4_ADDRESS_IDX 0
|
||||
#define MCE2_M3_IPV6_ADDRESS_IDX 1
|
||||
#define MCE2_M3_IP_ADDRESS_PREFERENCE_IDX 2
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* MCCH related BCCH Configuration per MBSFN area configuration parameters */
|
||||
/* MCCH configuration parameters section */
|
||||
#define MCE_CONFIG_STRING_MCCH_CONFIG_PER_MBSFN_AREA "mcch_config_per_mbsfn_area"
|
||||
/* M3 configuration parameters names */
|
||||
#define MCE_CONFIG_STRING_MCCH_MBSFN_AREA "mbsfn_area"
|
||||
#define MCE_CONFIG_STRING_MCCH_PDCCH_LENGTH "pdcch_length"
|
||||
#define MCE_CONFIG_STRING_MCCH_REPETITION_PERIOD "repetition_period"
|
||||
#define MCE_CONFIG_STRING_MCCH_OFFSET "offset"
|
||||
#define MCE_CONFIG_STRING_MCCH_MODIFICATION_PERIOD "modification_period"
|
||||
#define MCE_CONFIG_STRING_MCCH_SF_ALLOCATION_INFO "subframe_allocation_info"
|
||||
#define MCE_CONFIG_STRING_MCCH_MCS "mcs"
|
||||
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
|
||||
#define MCCH_PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_MCCH_MBSFN_AREA, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCCH_PDCCH_LENGTH, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCCH_REPETITION_PERIOD, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCCH_OFFSET, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCCH_MODIFICATION_PERIOD,NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCCH_SF_ALLOCATION_INFO, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCCH_MCS, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
#define MCCH_MBSFN_AREA_IDX 0
|
||||
#define MCCH_PDCCH_LENGTH_IDX 1
|
||||
#define MCCH_REPETITION_PERIOD_IDX 2
|
||||
#define MCCH_OFFSET_IDX 3
|
||||
#define MCCH_MODIFICATION_PERIOD_IDX 4
|
||||
#define MCCH_SF_ALLOCATION_INFO_IDX 5
|
||||
#define MCCH_MCS_IDX 6
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* M3 configuration parameters section name */
|
||||
#define MCE_CONFIG_STRING_PLMN "plnm"
|
||||
/* M3 configuration parameters names */
|
||||
#define MCE_CONFIG_STRING_MCC "mcc"
|
||||
#define MCE_CONFIG_STRING_MNC "mnc"
|
||||
#define MCE_CONFIG_STRING_MNC_LENGTH "mnc_length"
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
#define MCE_PLMN_PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_MCC, NULL, 0, uptr:NULL, defuintval:1000, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MNC, NULL, 0, uptr:NULL, defuintval:1000, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MNC_LENGTH, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
#define MCE_CONFIG_STRING_MCC_IDX 0
|
||||
#define MCE_CONFIG_STRING_MNC_IDX 1
|
||||
#define MCE_CONFIG_STRING_MNC_LENGTH_IDX 2
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define MCE_CONFIG_STRING_MBMS_SCHEDULING_INFO "mbms_sched_info"
|
||||
|
||||
#define MCE_CONFIG_STRING_MCCH_UPDATE_TIME "mcch_update_time"
|
||||
#define MCE_MBMS_SCHEDULING_INFO_PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_MCCH_UPDATE_TIME, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
#define MCE_CONFIG_STRING_MCCH_UPDATE_TIME_IDX 0
|
||||
|
||||
///*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define MCE_CONFIG_STRING_MBMS_AREA_CONFIGURATION_LIST "mbms_area_config_list"
|
||||
|
||||
#define MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD "common_sf_allocation_period"
|
||||
#define MCE_CONFIG_STRING_MBMS_AREA_ID "mbms_area_id"
|
||||
|
||||
#define MCE_MBMS_AREA_CONFIGURATION_LIST_PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MBMS_AREA_ID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
#define MCE_CONFIG_STRING_COMMON_SF_ALLOCATION_PERIOD_IDX 0
|
||||
#define MCE_CONFIG_STRING_MBMS_AREA_ID_IDX 1
|
||||
//
|
||||
///*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define MCE_CONFIG_STRING_PMCH_CONFIGURATION_LIST "pmch_config_list"
|
||||
|
||||
#define MCE_CONFIG_STRING_ALLOCATED_SF_END "allocated_sf_end"
|
||||
#define MCE_CONFIG_STRING_DATA_MCS "data_mcs"
|
||||
#define MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD "mch_scheduling_period"
|
||||
|
||||
#define MCE_MBMS_PMCH_CONFIGURATION_LIST_PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_ALLOCATED_SF_END, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_DATA_MCS, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
#define MCE_CONFIG_STRING_ALLOCATED_SF_END_IDX 0
|
||||
#define MCE_CONFIG_STRING_DATA_MCS_IDX 1
|
||||
#define MCE_CONFIG_STRING_MCH_SCHEDULING_PERIOD_IDX 2
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define MCE_CONFIG_STRING_MBMS_SESSION_LIST "mbms_session_list"
|
||||
|
||||
#define MCE_CONFIG_STRING_MBMS_SERVICE_ID "service_id"
|
||||
#define MCE_CONFIG_STRING_MBMS_LCID_ID "lcid_id"
|
||||
#define MCE_CONFIG_STRING_MBMS_LCID "lcid"
|
||||
|
||||
#define MCE_MBMS_MBMS_SESSION_LIST_DESC { \
|
||||
{MCE_CONFIG_STRING_MBMS_SERVICE_ID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT32, 0}, \
|
||||
{MCE_CONFIG_STRING_MBMS_LCID_ID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_MBMS_LCID, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
#define MCE_CONFIG_STRING_MBMS_SERVICE_ID_IDX 0
|
||||
#define MCE_CONFIG_STRING_MBMS_LCID_ID_IDX 1
|
||||
#define MCE_CONFIG_STRING_MBMS_LCID_IDX 2
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define MCE_CONFIG_STRING_MBMS_SF_CONFIGURATION_LIST "mbms_sf_config_list"
|
||||
|
||||
#define MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD "radioframe_allocation_period"
|
||||
#define MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET "radioframe_alloocation_offset"
|
||||
#define MCE_CONFIG_STRING_NUM_FRAME "num_frame"
|
||||
#define MCE_CONFIG_STRING_SUBFRAME_ALLOCATION "subframe_allocation"
|
||||
|
||||
#define MCE_MBMS_MBMS_SF_CONFIGURATION_LIST_PARAMS_DESC { \
|
||||
{MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
|
||||
{MCE_CONFIG_STRING_NUM_FRAME, NULL, 0, strptr:NULL, defstrval:"oneFrame", TYPE_STRING, 0}, \
|
||||
{MCE_CONFIG_STRING_SUBFRAME_ALLOCATION, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
|
||||
}
|
||||
#define MCE_CONFIG_STRING_RADIOFRAME_ALLOCATION_PERIOD_IDX 0
|
||||
#define MCE_CONFIG_STRING_RADIOFRAME_ALLOOCATION_OFFSET_IDX 1
|
||||
#define MCE_CONFIG_STRING_NUM_FRAME_IDX 2
|
||||
#define MCE_CONFIG_STRING_SUBFRAME_ALLOCATION_IDX 3
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.1 (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
|
||||
*/
|
||||
|
||||
/*! \file openair2/ENB_APP/enb_paramdef_mme.h
|
||||
* \brief definition of configuration parameters for MME modules
|
||||
* \author Javier MORGADE
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
* \company VICOMTECH Spain
|
||||
* \email: javier.morgade@ieee.org
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include "common/config/config_paramdesc.h"
|
||||
#include "RRC_paramsvalues.h"
|
||||
|
||||
|
||||
|
||||
/* mme configuration parameters names */
|
||||
|
||||
#define MME_CONFIG_STRING_MME_ID "MME_ID"
|
||||
#define MME_CONFIG_STRING_MME_NAME "MME_name"
|
||||
#define MME_CONFIG_STRING_MME_M3 "enable_mme_m3"
|
||||
|
||||
#define MMEPARAMS_DESC {\
|
||||
{MME_CONFIG_STRING_MME_ID, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
|
||||
{MME_CONFIG_STRING_MME_NAME, NULL, 0, strptr:NULL, defstrval:"OAIMME", TYPE_STRING, 0}, \
|
||||
{MME_CONFIG_STRING_MME_M3, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
|
||||
}
|
||||
|
||||
#define MME_MME_ID_IDX 0
|
||||
#define MME_MME_NAME_IDX 1
|
||||
#define MME_ENABLE_MME_M3_IDX 2
|
||||
|
||||
#define MMEPARAMS_CHECK { \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
}
|
||||
|
||||
|
||||
#define MME_CONFIG_STRING_NETWORK_INTERFACES_CONFIG "NETWORK_INTERFACES"
|
||||
|
||||
#define MME_INTERFACE_NAME_FOR_M3_MME_IDX 0
|
||||
#define MME_IPV4_ADDRESS_FOR_M3C_IDX 1
|
||||
#define MME_PORT_FOR_M3C_IDX 2
|
||||
|
||||
/* interface configuration parameters names */
|
||||
/* M3 interface configuration parameters names */
|
||||
#define MME_CONFIG_STRING_MME_INTERFACE_NAME_FOR_M3_MCE "MME_INTERFACE_NAME_FOR_M3_MCE"
|
||||
#define MME_CONFIG_STRING_MME_IPV4_ADDRESS_FOR_M3C "MME_IPV4_ADDRESS_FOR_M3C"
|
||||
#define MME_CONFIG_STRING_MME_PORT_FOR_M3C "MME_PORT_FOR_M3C"
|
||||
|
||||
|
||||
#define MME_NETPARAMS_DESC { \
|
||||
{MME_CONFIG_STRING_MME_INTERFACE_NAME_FOR_M3_MCE, NULL, 0, strptr:&mme_interface_name_for_m3_mce, defstrval:"lo", TYPE_STRING, 0}, \
|
||||
{MME_CONFIG_STRING_MME_IPV4_ADDRESS_FOR_M3C, NULL, 0, strptr:&mme_ipv4_address_for_m3c, defstrval:"127.0.0.18/24", TYPE_STRING, 0}, \
|
||||
{MME_CONFIG_STRING_MME_PORT_FOR_M3C, NULL, 0, uptr:&mme_port_for_m3c, defintval:36444L, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,27 +33,14 @@
|
||||
#include <pthread.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
void *receive_thread(void *args);
|
||||
Protocol__FlexranMessage *flexran_agent_timeout(void* args);
|
||||
|
||||
|
||||
int agent_task_created = 0;
|
||||
/*
|
||||
* enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller
|
||||
* and can interact with other itti tasks
|
||||
*/
|
||||
void *flexran_agent_task(void *args){
|
||||
|
||||
//flexran_agent_info_t *d = (flexran_agent_info_t *) args;
|
||||
Protocol__FlexranMessage *msg;
|
||||
void *data;
|
||||
int size;
|
||||
err_code_t err_code=0;
|
||||
int priority = 0;
|
||||
|
||||
MessageDef *msg_p = NULL;
|
||||
int result;
|
||||
struct flexran_agent_timer_element_s * elem = NULL;
|
||||
MessageDef *msg_p = NULL;
|
||||
int result;
|
||||
|
||||
itti_mark_task_ready(TASK_FLEXRAN_AGENT);
|
||||
|
||||
@@ -71,20 +58,6 @@ void *flexran_agent_task(void *args){
|
||||
case MESSAGE_TEST:
|
||||
LOG_I(FLEXRAN_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p));
|
||||
break;
|
||||
|
||||
case TIMER_HAS_EXPIRED:
|
||||
msg = flexran_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg);
|
||||
if (msg != NULL){
|
||||
data=flexran_agent_pack_message(msg,&size);
|
||||
elem = get_timer_entry(msg_p->ittiMsg.timer_has_expired.timer_id);
|
||||
if (flexran_agent_msg_send(elem->agent_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING;
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(FLEXRAN_AGENT, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
|
||||
@@ -93,10 +66,6 @@ void *flexran_agent_task(void *args){
|
||||
|
||||
result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
continue;
|
||||
error:
|
||||
if (err_code != 0)
|
||||
LOG_E(FLEXRAN_AGENT,"flexran_agent_task: error %d occured\n",err_code);
|
||||
} while (1);
|
||||
|
||||
return NULL;
|
||||
@@ -202,16 +171,14 @@ int flexran_agent_start(mid_t mod_id)
|
||||
*flexran_agent_register_channel(mod_id, channel, FLEXRAN_AGENT_MAC);
|
||||
*/
|
||||
|
||||
/*Initialize the continuous stats update mechanism*/
|
||||
flexran_agent_init_cont_stats_update(mod_id);
|
||||
pthread_t t;
|
||||
threadCreate(&t, receive_thread, flexran, "flexran", -1, OAI_PRIORITY_RT);
|
||||
|
||||
/* Register and initialize the control modules depending on capabilities.
|
||||
* After registering, calling flexran_agent_get_*_xface() tells whether a
|
||||
* control module is operational */
|
||||
uint16_t caps = flexran_get_capabilities_mask(mod_id);
|
||||
LOG_I(FLEXRAN_AGENT, "Agent handles BS ID %ld, capabilities=0x%x => handling%s%s%s%s%s%s%s%s\n",
|
||||
uint32_t caps = flexran_get_capabilities_mask(mod_id);
|
||||
LOG_I(FLEXRAN_AGENT, "Agent handles BS ID %ld, capabilities=0x%x => handling%s%s%s%s%s%s%s%s%s\n",
|
||||
flexran_get_bs_id(mod_id), caps,
|
||||
FLEXRAN_CAP_LOPHY(caps) ? " LOPHY" : "",
|
||||
FLEXRAN_CAP_HIPHY(caps) ? " HIPHY" : "",
|
||||
@@ -220,7 +187,8 @@ int flexran_agent_start(mid_t mod_id)
|
||||
FLEXRAN_CAP_RLC(caps) ? " RLC" : "",
|
||||
FLEXRAN_CAP_PDCP(caps) ? " PDCP" : "",
|
||||
FLEXRAN_CAP_SDAP(caps) ? " SDAP" : "",
|
||||
FLEXRAN_CAP_RRC(caps) ? " RRC" : "");
|
||||
FLEXRAN_CAP_RRC(caps) ? " RRC" : "",
|
||||
FLEXRAN_CAP_S1AP(caps) ? " S1AP" : "");
|
||||
|
||||
if (FLEXRAN_CAP_LOPHY(caps) || FLEXRAN_CAP_HIPHY(caps)) {
|
||||
flexran_agent_register_phy_xface(mod_id);
|
||||
@@ -243,11 +211,16 @@ int flexran_agent_start(mid_t mod_id)
|
||||
LOG_I(FLEXRAN_AGENT, "registered PDCP interface/CM for eNB %d\n", mod_id);
|
||||
}
|
||||
|
||||
if (FLEXRAN_CAP_S1AP(caps)) {
|
||||
flexran_agent_register_s1ap_xface(mod_id);
|
||||
LOG_I(FLEXRAN_AGENT, "registered S1AP interface/CM for eNB %d\n", mod_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* initilize a timer
|
||||
*/
|
||||
|
||||
flexran_agent_init_timer();
|
||||
flexran_agent_timer_init(mod_id);
|
||||
|
||||
/*
|
||||
* start the enb agent task for tx and interaction with the underlying network function
|
||||
@@ -288,16 +261,3 @@ error:
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
Protocol__FlexranMessage *flexran_agent_timeout(void* args){
|
||||
|
||||
// flexran_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args));
|
||||
//memcpy (timer_args, args, sizeof(*timer_args));
|
||||
flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args;
|
||||
|
||||
LOG_UI(FLEXRAN_AGENT, "flexran_agent %d timeout\n", timer_args->mod_id);
|
||||
//LOG_I(FLEXRAN_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags);
|
||||
//LOG_I(FLEXRAN_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "flexran_agent_mac.h"
|
||||
#include "flexran_agent_rrc.h"
|
||||
#include "flexran_agent_pdcp.h"
|
||||
#include "flexran_agent_s1ap.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "assertions.h"
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
/*! \file flexran_agent_common.c
|
||||
* \brief common primitives for all agents
|
||||
* \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein, shahab SHARIAT BAGHERI
|
||||
* \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein
|
||||
* \date 2017
|
||||
* \version 0.1
|
||||
*/
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "flexran_agent_phy.h"
|
||||
#include "flexran_agent_mac.h"
|
||||
#include "flexran_agent_rrc.h"
|
||||
#include "flexran_agent_s1ap.h"
|
||||
//#include "PHY/extern.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "flexran_agent_mac_internal.h"
|
||||
@@ -128,6 +129,7 @@ int flexran_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessa
|
||||
hello_msg->bs_id = flexran_get_bs_id(mod_id);
|
||||
hello_msg->has_bs_id = 1;
|
||||
hello_msg->n_capabilities = flexran_get_capabilities(mod_id, &hello_msg->capabilities);
|
||||
hello_msg->n_splits = flexran_get_splits(mod_id, &hello_msg->splits);
|
||||
*msg = malloc(sizeof(Protocol__FlexranMessage));
|
||||
|
||||
if(*msg == NULL)
|
||||
@@ -161,6 +163,7 @@ int flexran_agent_destroy_hello(Protocol__FlexranMessage *msg) {
|
||||
|
||||
free(msg->hello_msg->header);
|
||||
free(msg->hello_msg->capabilities);
|
||||
free(msg->hello_msg->splits);
|
||||
free(msg->hello_msg);
|
||||
free(msg);
|
||||
return 0;
|
||||
@@ -337,6 +340,9 @@ int flexran_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) {
|
||||
|
||||
free(reply->cell_config[i]);
|
||||
}
|
||||
|
||||
if (reply->s1ap)
|
||||
flexran_agent_free_s1ap_cell_config(&reply->s1ap);
|
||||
|
||||
free(reply->cell_config);
|
||||
free(reply);
|
||||
@@ -598,21 +604,7 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl
|
||||
goto error;
|
||||
|
||||
ue_config_reply_msg->header = header;
|
||||
ue_config_reply_msg->n_ue_config = 0;
|
||||
|
||||
if (flexran_agent_get_rrc_xface(mod_id))
|
||||
ue_config_reply_msg->n_ue_config = flexran_get_rrc_num_ues(mod_id);
|
||||
else if (flexran_agent_get_mac_xface(mod_id))
|
||||
ue_config_reply_msg->n_ue_config = flexran_get_mac_num_ues(mod_id);
|
||||
|
||||
if (flexran_agent_get_rrc_xface(mod_id) && flexran_agent_get_mac_xface(mod_id)
|
||||
&& flexran_get_rrc_num_ues(mod_id) != flexran_get_mac_num_ues(mod_id)) {
|
||||
const int nrrc = flexran_get_rrc_num_ues(mod_id);
|
||||
const int nmac = flexran_get_mac_num_ues(mod_id);
|
||||
ue_config_reply_msg->n_ue_config = nrrc < nmac ? nrrc : nmac;
|
||||
LOG_E(FLEXRAN_AGENT, "%s(): different numbers of UEs in RRC (%d) and MAC (%d), reporting for %lu UEs\n",
|
||||
__func__, nrrc, nmac, ue_config_reply_msg->n_ue_config);
|
||||
}
|
||||
ue_config_reply_msg->n_ue_config = flexran_agent_get_num_ues(mod_id);
|
||||
|
||||
Protocol__FlexUeConfig **ue_config;
|
||||
|
||||
@@ -769,9 +761,12 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F
|
||||
cell_conf[i]->carrier_index = i;
|
||||
cell_conf[i]->has_carrier_index = 1;
|
||||
}
|
||||
|
||||
|
||||
enb_config_reply_msg->cell_config=cell_conf;
|
||||
}
|
||||
|
||||
if (flexran_agent_get_s1ap_xface(mod_id))
|
||||
flexran_agent_fill_s1ap_cell_config(mod_id, &enb_config_reply_msg->s1ap);
|
||||
|
||||
*msg = malloc(sizeof(Protocol__FlexranMessage));
|
||||
|
||||
@@ -910,14 +905,19 @@ int flexran_agent_handle_enb_config_reply(mid_t mod_id, const void *params, Prot
|
||||
|
||||
if (flexran_agent_get_mac_xface(mod_id) && enb_config->cell_config[0]->slice_config) {
|
||||
prepare_update_slice_config(mod_id, enb_config->cell_config[0]->slice_config);
|
||||
//} else {
|
||||
// initiate_soft_restart(mod_id, enb_config->cell_config[0]);
|
||||
}
|
||||
|
||||
if (flexran_agent_get_rrc_xface(mod_id) && enb_config->cell_config[0]->has_x2_ho_net_control) {
|
||||
if (flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control) < 0) {
|
||||
} else if (enb_config->cell_config[0]->has_eutra_band
|
||||
&& enb_config->cell_config[0]->has_dl_freq
|
||||
&& enb_config->cell_config[0]->has_ul_freq
|
||||
&& enb_config->cell_config[0]->has_dl_bandwidth) {
|
||||
initiate_soft_restart(mod_id, enb_config->cell_config[0]);
|
||||
} else if (flexran_agent_get_rrc_xface(mod_id)
|
||||
&& enb_config->cell_config[0]->has_x2_ho_net_control) {
|
||||
LOG_I(FLEXRAN_AGENT,
|
||||
"setting X2 HO NetControl to %d\n",
|
||||
enb_config->cell_config[0]->x2_ho_net_control);
|
||||
const int rc = flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control);
|
||||
if (rc < 0)
|
||||
LOG_E(FLEXRAN_AGENT, "Error in configuring X2 handover controlled by network");
|
||||
}
|
||||
}
|
||||
|
||||
*msg = NULL;
|
||||
@@ -935,3 +935,24 @@ int flexran_agent_handle_ue_config_reply(mid_t mod_id, const void *params, Proto
|
||||
*msg = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexran_agent_get_num_ues(mid_t mod_id) {
|
||||
const int has_rrc = flexran_agent_get_rrc_xface(mod_id) != NULL;
|
||||
const int has_mac = flexran_agent_get_mac_xface(mod_id) != NULL;
|
||||
DevAssert(has_rrc || has_mac);
|
||||
if (has_rrc && !has_mac)
|
||||
return flexran_get_rrc_num_ues(mod_id);
|
||||
if (!has_rrc && has_mac)
|
||||
return flexran_get_mac_num_ues(mod_id);
|
||||
|
||||
/* has both */
|
||||
const int nrrc = flexran_get_rrc_num_ues(mod_id);
|
||||
const int nmac = flexran_get_mac_num_ues(mod_id);
|
||||
if (nrrc != nmac) {
|
||||
const int n_ue = nrrc < nmac ? nrrc : nmac;
|
||||
LOG_E(FLEXRAN_AGENT, "%s(): different numbers of UEs in RRC (%d) and MAC (%d), reporting for %d UEs\n",
|
||||
__func__, nrrc, nmac, n_ue);
|
||||
return n_ue;
|
||||
}
|
||||
return nrrc;
|
||||
}
|
||||
|
||||
@@ -150,24 +150,25 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id,
|
||||
uint32_t size);
|
||||
|
||||
/* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */
|
||||
Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args);
|
||||
Protocol__FlexranMessage *flexran_agent_handle_timed_task(
|
||||
mid_t mod_id,
|
||||
Protocol__FlexranMessage *msg);
|
||||
|
||||
/*Top level Statistics hanlder*/
|
||||
Protocol__FlexranMessage *flexran_agent_send_stats_reply(
|
||||
mid_t mod_id,
|
||||
const Protocol__FlexranMessage *msg);
|
||||
|
||||
int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg);
|
||||
|
||||
/* Function to be used to handle reply message . */
|
||||
int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg);
|
||||
int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const Protocol__FlexStatsRequest *stats_req, Protocol__FlexranMessage **msg);
|
||||
int flexran_agent_destroy_stats_reply(Protocol__FlexranMessage *msg);
|
||||
|
||||
/* Top level Statistics request protocol message constructor and destructor */
|
||||
int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg);
|
||||
//int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg);
|
||||
int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg);
|
||||
|
||||
err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id);
|
||||
|
||||
err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) ;
|
||||
err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id);
|
||||
|
||||
/* Handle a received eNB config reply message as an "order" to reconfigure. It
|
||||
* does not come as a reconfiguration message as this is a "structured"
|
||||
* ProtoBuf message (as opposed to "unstructured" YAML). There is no destructor
|
||||
@@ -183,4 +184,8 @@ int flexran_agent_handle_enb_config_reply(mid_t mod_id, const void* params, Prot
|
||||
* request message. */
|
||||
int flexran_agent_handle_ue_config_reply(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg);
|
||||
|
||||
/* Return the number of UEs in the BS of this agent across RRC/MAC. If they
|
||||
* disagree, prints an error and returns the minimum of both. */
|
||||
int flexran_agent_get_num_ues(mid_t mod_id);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -107,36 +107,6 @@ typedef uint8_t lcid_t;
|
||||
typedef int32_t err_code_t;
|
||||
|
||||
|
||||
/*---------Timer Enums --------- */
|
||||
|
||||
typedef enum {
|
||||
/* oneshot timer: */
|
||||
FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0,
|
||||
|
||||
/* periodic timer */
|
||||
FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 1,
|
||||
|
||||
/* Inactive state: initial state for any timer. */
|
||||
FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 2,
|
||||
|
||||
/* Max number of states available */
|
||||
FLEXRAN_AGENT_TIMER_TYPE_MAX,
|
||||
} flexran_agent_timer_type_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
/* Inactive state: initial state for any timer. */
|
||||
FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0,
|
||||
|
||||
/* Inactive state: initial state for any timer. */
|
||||
FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1,
|
||||
|
||||
/* Inactive state: initial state for any timer. */
|
||||
FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2,
|
||||
|
||||
/* Max number of states available */
|
||||
FLEXRAN_AGENT_TIMER_STATE_MAX,
|
||||
} flexran_agent_timer_state_t;
|
||||
|
||||
#define FLEXRAN_CAP_LOPHY(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)) > 0)
|
||||
#define FLEXRAN_CAP_HIPHY(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)) > 0)
|
||||
@@ -146,6 +116,7 @@ typedef enum {
|
||||
#define FLEXRAN_CAP_PDCP(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)) > 0)
|
||||
#define FLEXRAN_CAP_SDAP(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)) > 0)
|
||||
#define FLEXRAN_CAP_RRC(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC)) > 0)
|
||||
#define FLEXRAN_CAP_S1AP(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP)) > 0)
|
||||
|
||||
typedef enum {
|
||||
ENB_NORMAL_OPERATION = 0x0,
|
||||
@@ -193,38 +164,4 @@ typedef struct {
|
||||
|
||||
} agent_reconf_rrc;
|
||||
|
||||
|
||||
/* These structs will be used to give
|
||||
instructions for the type of stats reports
|
||||
we need to create */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16_t ue_rnti;
|
||||
uint32_t ue_report_flags; /* Indicates the report elements
|
||||
required for this UE id. See
|
||||
FlexRAN specification 1.2.4.2 */
|
||||
} ue_report_type_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t cc_id;
|
||||
uint32_t cc_report_flags; /* Indicates the report elements
|
||||
required for this CC index. See
|
||||
FlexRAN specification 1.2.4.3 */
|
||||
} cc_report_type_t;
|
||||
|
||||
typedef struct {
|
||||
int nr_ue;
|
||||
ue_report_type_t *ue_report_type;
|
||||
int nr_cc;
|
||||
cc_report_type_t *cc_report_type;
|
||||
} report_config_t;
|
||||
|
||||
typedef struct stats_request_config_s{
|
||||
uint8_t report_type;
|
||||
uint8_t report_frequency;
|
||||
uint16_t period; /*In number of subframes*/
|
||||
report_config_t *config;
|
||||
} stats_request_config_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "flexran_agent_mac_defs.h"
|
||||
#include "flexran_agent_rrc_defs.h"
|
||||
#include "flexran_agent_pdcp_defs.h"
|
||||
#include "flexran_agent_s1ap_defs.h"
|
||||
|
||||
/* Control module interface for the communication of the PHY control module with the agent */
|
||||
AGENT_PHY_xface *flexran_agent_get_phy_xface(mid_t mod_id);
|
||||
@@ -48,6 +49,9 @@ AGENT_RRC_xface *flexran_agent_get_rrc_xface(mid_t mod_id);
|
||||
/* Control module interface for the communication of the RRC Control Module with the agent */
|
||||
AGENT_PDCP_xface *flexran_agent_get_pdcp_xface(mid_t mod_id);
|
||||
|
||||
/* Control module interface for the communication of the S1AP Control Module with the agent */
|
||||
AGENT_S1AP_xface *flexran_agent_get_s1ap_xface(mid_t mod_id);
|
||||
|
||||
/* Requried to know which UEs had a harq updated over some subframe */
|
||||
extern int harq_pid_updated[NUM_MAX_UE][8];
|
||||
extern int harq_pid_round[NUM_MAX_UE][8];
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "flexran_agent_mac.h"
|
||||
#include "flexran_agent_rrc.h"
|
||||
#include "flexran_agent_pdcp.h"
|
||||
#include "flexran_agent_s1ap.h"
|
||||
#include "flexran_agent_timer.h"
|
||||
#include "flexran_agent_ran_api.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
@@ -154,39 +155,20 @@ void * flexran_agent_pack_message(Protocol__FlexranMessage *msg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args) {
|
||||
Protocol__FlexranMessage *flexran_agent_handle_timed_task(
|
||||
mid_t mod_id,
|
||||
Protocol__FlexranMessage *msg) {
|
||||
err_code_t err_code;
|
||||
flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args;
|
||||
|
||||
Protocol__FlexranMessage *timed_task, *reply_message;
|
||||
timed_task = timer_args->msg;
|
||||
err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message));
|
||||
if ( err_code < 0 ){
|
||||
goto error;
|
||||
Protocol__FlexranMessage *reply_message;
|
||||
err_code = ((*agent_messages_callback[msg->msg_case-1][msg->msg_dir-1])(
|
||||
mod_id, msg, &reply_message));
|
||||
if (err_code < 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "could not handle message: errno %d occured\n", err_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return reply_message;
|
||||
|
||||
error:
|
||||
LOG_E(FLEXRAN_AGENT,"errno %d occured\n",err_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Protocol__FlexranMessage* flexran_agent_process_timeout(long timer_id, void* timer_args){
|
||||
|
||||
struct flexran_agent_timer_element_s *found = get_timer_entry(timer_id);
|
||||
|
||||
if (found == NULL ) goto error;
|
||||
LOG_D(FLEXRAN_AGENT, "Found the entry (%p): timer_id is 0x%lx 0x%lx\n", found, timer_id, found->timer_id);
|
||||
|
||||
if (timer_args == NULL)
|
||||
LOG_W(FLEXRAN_AGENT,"null timer args\n");
|
||||
|
||||
return found->cb(timer_args);
|
||||
|
||||
error:
|
||||
LOG_E(FLEXRAN_AGENT, "can't get the timer element\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) {
|
||||
@@ -196,335 +178,175 @@ err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg)
|
||||
|
||||
/*
|
||||
Top Level Statistics Report
|
||||
*/
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){
|
||||
|
||||
// TODO: Must deal with sanitization of input
|
||||
// TODO: Must check if RNTIs and cell ids of the request actually exist
|
||||
// TODO: Must resolve conflicts among stats requests
|
||||
|
||||
int i;
|
||||
err_code_t err_code = 0;
|
||||
xid_t xid;
|
||||
uint32_t usec_interval, sec_interval;
|
||||
|
||||
//TODO: We do not deal with multiple CCs at the moment and eNB id is 0
|
||||
int enb_id = mod_id;
|
||||
|
||||
//eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id];
|
||||
//UE_list_t *eNB_UE_list= &eNB->UE_list;
|
||||
|
||||
report_config_t report_config;
|
||||
|
||||
uint32_t ue_flags = 0;
|
||||
uint32_t c_flags = 0;
|
||||
|
||||
int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) {
|
||||
*msg = NULL;
|
||||
Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params;
|
||||
|
||||
Protocol__FlexStatsRequest *stats_req = input->stats_request_msg;
|
||||
xid = (stats_req->header)->xid;
|
||||
const xid_t xid = stats_req->header->xid;
|
||||
|
||||
// Check the type of request that is made
|
||||
switch(stats_req->body_case) {
|
||||
case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ;
|
||||
Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request;
|
||||
if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) {
|
||||
/*Disable both periodic and continuous updates*/
|
||||
// flexran_agent_disable_cont_stats_update(mod_id);
|
||||
flexran_agent_destroy_timer_by_task_id(xid);
|
||||
*msg = NULL;
|
||||
return 0;
|
||||
} else { //One-off, periodical or continuous reporting
|
||||
//Set the proper flags
|
||||
ue_flags = comp_req->ue_report_flags;
|
||||
c_flags = comp_req->cell_report_flags;
|
||||
//Create a list of all eNB RNTIs and cells
|
||||
if (stats_req->body_case != PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST) {
|
||||
LOG_E(FLEXRAN_AGENT, "only complete stats are supported at the moment\n");
|
||||
return -1;
|
||||
}
|
||||
Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request;
|
||||
|
||||
//Set the number of UEs and create list with their RNTIs stats configs
|
||||
report_config.nr_ue = 0;
|
||||
if (flexran_agent_get_rrc_xface(mod_id))
|
||||
report_config.nr_ue = flexran_get_rrc_num_ues(mod_id);
|
||||
else if (flexran_agent_get_mac_xface(mod_id))
|
||||
report_config.nr_ue = flexran_get_mac_num_ues(mod_id);
|
||||
|
||||
if (flexran_agent_get_rrc_xface(mod_id) && flexran_agent_get_mac_xface(mod_id)
|
||||
&& flexran_get_rrc_num_ues(mod_id) != flexran_get_mac_num_ues(mod_id)) {
|
||||
const int nrrc = flexran_get_rrc_num_ues(mod_id);
|
||||
const int nmac = flexran_get_mac_num_ues(mod_id);
|
||||
report_config.nr_ue = nrrc < nmac ? nrrc : nmac;
|
||||
LOG_E(FLEXRAN_AGENT, "%s(): different numbers of UEs in RRC (%d) and MAC (%d), reporting for %d UEs\n",
|
||||
__func__, nrrc, nmac, report_config.nr_ue);
|
||||
}
|
||||
report_config.ue_report_type = malloc(sizeof(ue_report_type_t) * report_config.nr_ue);
|
||||
if (report_config.ue_report_type == NULL) {
|
||||
// TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
if (flexran_agent_get_rrc_xface(mod_id)) {
|
||||
rnti_t rntis[report_config.nr_ue];
|
||||
flexran_get_rrc_rnti_list(mod_id, rntis, report_config.nr_ue);
|
||||
for (i = 0; i < report_config.nr_ue; i++) {
|
||||
report_config.ue_report_type[i].ue_rnti = rntis[i];
|
||||
report_config.ue_report_type[i].ue_report_flags = ue_flags;
|
||||
}
|
||||
}
|
||||
if (flexran_agent_get_mac_xface(mod_id) && !flexran_agent_get_rrc_xface(mod_id)) {
|
||||
for (i = 0; i < report_config.nr_ue; i++) {
|
||||
const int UE_id = flexran_get_mac_ue_id(mod_id, i);
|
||||
report_config.ue_report_type[i].ue_rnti = flexran_get_mac_ue_crnti(enb_id, UE_id);
|
||||
report_config.ue_report_type[i].ue_report_flags = ue_flags;
|
||||
}
|
||||
}
|
||||
//Set the number of CCs and create a list with the cell stats configs
|
||||
report_config.nr_cc = MAX_NUM_CCs;
|
||||
report_config.cc_report_type = malloc(sizeof(cc_report_type_t) * report_config.nr_cc);
|
||||
if (report_config.cc_report_type == NULL) {
|
||||
// TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < report_config.nr_cc; i++) {
|
||||
//TODO: Must fill in the proper cell ids
|
||||
report_config.cc_report_type[i].cc_id = i;
|
||||
report_config.cc_report_type[i].cc_report_flags = c_flags;
|
||||
}
|
||||
/* Check if request was periodical */
|
||||
if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) {
|
||||
/* Create a one off flexran message as an argument for the periodical task */
|
||||
Protocol__FlexranMessage *timer_msg = NULL;
|
||||
stats_request_config_t request_config;
|
||||
request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS;
|
||||
request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE;
|
||||
request_config.period = 0;
|
||||
/* Need to make sure that the ue flags are saved (Bug) */
|
||||
if (report_config.nr_ue == 0) {
|
||||
report_config.nr_ue = 1;
|
||||
report_config.ue_report_type = malloc(sizeof(ue_report_type_t));
|
||||
if (report_config.ue_report_type == NULL) {
|
||||
// TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
report_config.ue_report_type[0].ue_rnti = 0; // Dummy value
|
||||
report_config.ue_report_type[0].ue_report_flags = ue_flags;
|
||||
}
|
||||
request_config.config = &report_config;
|
||||
if (flexran_agent_stats_request(enb_id, xid, &request_config, &timer_msg) == -1) {
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
/* Create a timer */
|
||||
long timer_id = 0;
|
||||
flexran_agent_timer_args_t *timer_args = malloc(sizeof(flexran_agent_timer_args_t));
|
||||
memset (timer_args, 0, sizeof(flexran_agent_timer_args_t));
|
||||
timer_args->mod_id = enb_id;
|
||||
timer_args->msg = timer_msg;
|
||||
/*Convert subframes to usec time*/
|
||||
usec_interval = 1000*comp_req->sf;
|
||||
sec_interval = 0;
|
||||
/*add seconds if required*/
|
||||
if (usec_interval >= 1000*1000) {
|
||||
sec_interval = usec_interval/(1000*1000);
|
||||
usec_interval = usec_interval%(1000*1000);
|
||||
}
|
||||
flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT,
|
||||
enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid,
|
||||
flexran_agent_handle_timed_task,(void*) timer_args, &timer_id);
|
||||
} else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) {
|
||||
/*If request was for continuous updates, disable the previous configuration and
|
||||
set up a new one*/
|
||||
flexran_agent_disable_cont_stats_update(mod_id);
|
||||
stats_request_config_t request_config;
|
||||
request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS;
|
||||
request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE;
|
||||
request_config.period = 0;
|
||||
/* Need to make sure that the ue flags are saved (Bug) */
|
||||
if (report_config.nr_ue == 0) {
|
||||
report_config.nr_ue = 1;
|
||||
report_config.ue_report_type = malloc(sizeof(ue_report_type_t));
|
||||
if (report_config.ue_report_type == NULL) {
|
||||
// TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
report_config.ue_report_type[0].ue_rnti = 0; // Dummy value
|
||||
report_config.ue_report_type[0].ue_report_flags = ue_flags;
|
||||
}
|
||||
request_config.config = &report_config;
|
||||
flexran_agent_enable_cont_stats_update(enb_id, xid, &request_config);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:;
|
||||
Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request;
|
||||
// UE report config will be blank
|
||||
report_config.nr_ue = 0;
|
||||
report_config.ue_report_type = NULL;
|
||||
report_config.nr_cc = cell_req->n_cell;
|
||||
report_config.cc_report_type = malloc(sizeof(cc_report_type_t) * report_config.nr_cc);
|
||||
if (report_config.cc_report_type == NULL) {
|
||||
// TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < report_config.nr_cc; i++) {
|
||||
//TODO: Must fill in the proper cell ids
|
||||
report_config.cc_report_type[i].cc_id = cell_req->cell[i];
|
||||
report_config.cc_report_type[i].cc_report_flags = cell_req->flags;
|
||||
}
|
||||
break;
|
||||
case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:;
|
||||
Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request;
|
||||
// Cell report config will be blank
|
||||
report_config.nr_cc = 0;
|
||||
report_config.cc_report_type = NULL;
|
||||
report_config.nr_ue = ue_req->n_rnti;
|
||||
report_config.ue_report_type = malloc(sizeof(ue_report_type_t) * report_config.nr_ue);
|
||||
if (report_config.ue_report_type == NULL) {
|
||||
// TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < report_config.nr_ue; i++) {
|
||||
const int UE_id = flexran_get_mac_ue_id(mod_id, i);
|
||||
report_config.ue_report_type[i].ue_rnti = ue_req->rnti[UE_id];
|
||||
report_config.ue_report_type[i].ue_report_flags = ue_req->flags;
|
||||
}
|
||||
break;
|
||||
switch (comp_req->report_frequency) {
|
||||
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF:
|
||||
flexran_agent_destroy_timer(mod_id, xid);
|
||||
return 0;
|
||||
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE:
|
||||
LOG_E(FLEXRAN_AGENT, "one-shot timer not implemented yet\n");
|
||||
return -1;
|
||||
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL:
|
||||
/* Create a one off flexran message as an argument for the periodical task */
|
||||
LOG_I(FLEXRAN_AGENT, "periodical timer xid %d cell_flags %d ue_flags %d\n",
|
||||
xid, comp_req->cell_report_flags, comp_req->ue_report_flags);
|
||||
flexran_agent_create_timer(mod_id, comp_req->sf,
|
||||
FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid,
|
||||
flexran_agent_send_stats_reply, input);
|
||||
/* return 1: do not dispose comp_req message we received, we still need it */
|
||||
return 1;
|
||||
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS:
|
||||
LOG_E(FLEXRAN_AGENT, "unsupported report frequency continuous\n");
|
||||
return -1;
|
||||
default:
|
||||
//TODO: Add appropriate error code
|
||||
err_code = -100;
|
||||
goto error;
|
||||
LOG_E(FLEXRAN_AGENT, "unknown report frequency\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flexran_agent_stats_reply(enb_id, xid, &report_config, msg )) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (report_config.ue_report_type)
|
||||
free(report_config.ue_report_type);
|
||||
if (report_config.cc_report_type)
|
||||
free(report_config.cc_report_type);
|
||||
|
||||
return 0;
|
||||
|
||||
error :
|
||||
LOG_E(FLEXRAN_AGENT, "%s(): errno %d occured\n", __func__, err_code);
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/*
|
||||
Top level reply
|
||||
*/
|
||||
Protocol__FlexranMessage *flexran_agent_send_stats_reply(
|
||||
mid_t mod_id,
|
||||
const Protocol__FlexranMessage *msg) {
|
||||
const Protocol__FlexStatsRequest *stats_req = msg->stats_request_msg;
|
||||
const xid_t xid = stats_req->header->xid;
|
||||
|
||||
int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg){
|
||||
Protocol__FlexranMessage *reply = NULL;
|
||||
err_code_t rc = flexran_agent_stats_reply(mod_id, xid, stats_req, &reply);
|
||||
if (rc < 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "%s(): errno %d occured, cannot send stats_reply\n",
|
||||
__func__, rc);
|
||||
return NULL;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
int flexran_agent_stats_reply(mid_t enb_id,
|
||||
xid_t xid,
|
||||
const Protocol__FlexStatsRequest *stats_req,
|
||||
Protocol__FlexranMessage **msg) {
|
||||
|
||||
Protocol__FlexHeader *header = NULL;
|
||||
Protocol__FlexUeStatsReport **ue_report = NULL;
|
||||
Protocol__FlexCellStatsReport **cell_report = NULL;
|
||||
Protocol__FlexStatsReply *stats_reply_msg = NULL;
|
||||
err_code_t err_code = PROTOCOL__FLEXRAN_ERR__UNEXPECTED;
|
||||
int i,j;
|
||||
AssertFatal(stats_req->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST,
|
||||
"%s() handles only complete stats requests\n",
|
||||
__func__);
|
||||
const uint32_t cell_flags = stats_req->complete_stats_request->cell_report_flags;
|
||||
const uint32_t ue_flags = stats_req->complete_stats_request->ue_report_flags;
|
||||
|
||||
if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) {
|
||||
goto error;
|
||||
int n_ue = flexran_agent_get_num_ues(enb_id);
|
||||
|
||||
rnti_t rntis[n_ue];
|
||||
if (flexran_agent_get_rrc_xface(enb_id))
|
||||
flexran_get_rrc_rnti_list(enb_id, rntis, n_ue);
|
||||
if (flexran_agent_get_mac_xface(enb_id) && !flexran_agent_get_rrc_xface(enb_id)) {
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
const int UE_id = flexran_get_mac_ue_id(enb_id, i);
|
||||
rntis[i] = flexran_get_mac_ue_crnti(enb_id, UE_id);
|
||||
}
|
||||
}
|
||||
|
||||
stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply));
|
||||
|
||||
if (stats_reply_msg == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
protocol__flex_stats_reply__init(stats_reply_msg);
|
||||
stats_reply_msg->header = header;
|
||||
|
||||
stats_reply_msg->n_ue_report = report_config->nr_ue;
|
||||
stats_reply_msg->n_cell_report = report_config->nr_cc;
|
||||
|
||||
// UE report
|
||||
|
||||
ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue);
|
||||
int n_cc = MAX_NUM_CCs;
|
||||
|
||||
ue_report = calloc(n_ue, sizeof(Protocol__FlexUeStatsReport *));
|
||||
if (ue_report == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < report_config->nr_ue; i++) {
|
||||
|
||||
ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport));
|
||||
if (ue_report[i] == NULL) {
|
||||
goto error;
|
||||
}
|
||||
protocol__flex_ue_stats_report__init(ue_report[i]);
|
||||
ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti;
|
||||
ue_report[i]->has_rnti = 1;
|
||||
ue_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */
|
||||
|
||||
for (int i = 0; i < n_ue; i++) {
|
||||
ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport));
|
||||
if (ue_report[i] == NULL) {
|
||||
goto error;
|
||||
}
|
||||
protocol__flex_ue_stats_report__init(ue_report[i]);
|
||||
ue_report[i]->rnti = rntis[i];
|
||||
ue_report[i]->has_rnti = 1;
|
||||
ue_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */
|
||||
}
|
||||
|
||||
// cell rpoert
|
||||
|
||||
cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc);
|
||||
cell_report = calloc(n_cc, sizeof(Protocol__FlexCellStatsReport *));
|
||||
if (cell_report == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < report_config->nr_cc; i++) {
|
||||
|
||||
cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport));
|
||||
if(cell_report[i] == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
protocol__flex_cell_stats_report__init(cell_report[i]);
|
||||
cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id;
|
||||
cell_report[i]->has_carrier_index = 1;
|
||||
cell_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */
|
||||
|
||||
for (int i = 0; i < n_cc; i++) {
|
||||
cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport));
|
||||
if(cell_report[i] == NULL) {
|
||||
goto error;
|
||||
}
|
||||
protocol__flex_cell_stats_report__init(cell_report[i]);
|
||||
cell_report[i]->carrier_index = i;
|
||||
cell_report[i]->has_carrier_index = 1;
|
||||
cell_report[i]->has_flags = 1; /* actual flags are filled in the CMs below */
|
||||
}
|
||||
|
||||
/* MAC reply split */
|
||||
if (flexran_agent_get_mac_xface(enb_id)
|
||||
&& flexran_agent_mac_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) {
|
||||
&& (flexran_agent_mac_stats_reply_ue(enb_id, ue_report, n_ue, ue_flags) < 0
|
||||
|| flexran_agent_mac_stats_reply_cell(enb_id, cell_report, n_cc, cell_flags) < 0)) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* RRC reply split */
|
||||
if (flexran_agent_get_rrc_xface(enb_id)
|
||||
&& flexran_agent_rrc_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) {
|
||||
&& flexran_agent_rrc_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* PDCP reply split */
|
||||
if (flexran_agent_get_pdcp_xface(enb_id)
|
||||
&& flexran_agent_pdcp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) {
|
||||
&& flexran_agent_pdcp_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* GTP reply split, currently performed through RRC module */
|
||||
if (flexran_agent_get_rrc_xface(enb_id)
|
||||
&& flexran_agent_rrc_gtp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) {
|
||||
&& flexran_agent_rrc_gtp_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
stats_reply_msg->cell_report = cell_report;
|
||||
stats_reply_msg->ue_report = ue_report;
|
||||
|
||||
*msg = malloc(sizeof(Protocol__FlexranMessage));
|
||||
if(*msg == NULL) {
|
||||
/* S1AP statistics, depends on RRC to find S1AP ID */
|
||||
if (flexran_agent_get_rrc_xface(enb_id)
|
||||
&& flexran_agent_get_s1ap_xface(enb_id)
|
||||
&& flexran_agent_s1ap_stats_reply(enb_id, ue_report, n_ue, ue_flags) < 0) {
|
||||
err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) {
|
||||
goto error;
|
||||
}
|
||||
stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply));
|
||||
AssertFatal(stats_reply_msg, "no memory for stats_reply_msg\n");
|
||||
protocol__flex_stats_reply__init(stats_reply_msg);
|
||||
stats_reply_msg->header = header;
|
||||
stats_reply_msg->n_ue_report = n_ue;
|
||||
stats_reply_msg->ue_report = ue_report;
|
||||
stats_reply_msg->n_cell_report = n_cc;
|
||||
stats_reply_msg->cell_report = cell_report;
|
||||
|
||||
*msg = malloc(sizeof(Protocol__FlexranMessage));
|
||||
AssertFatal(*msg, "no memory for stats_reply container msg\n");
|
||||
protocol__flexran_message__init(*msg);
|
||||
(*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG;
|
||||
(*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME;
|
||||
@@ -546,7 +368,7 @@ error :
|
||||
}
|
||||
|
||||
if (ue_report != NULL) {
|
||||
for (j = 0; j < report_config->nr_ue; j++) {
|
||||
for (int j = 0; j < n_ue; j++) {
|
||||
if (ue_report[j] != NULL) {
|
||||
free(ue_report[j]);
|
||||
}
|
||||
@@ -556,7 +378,7 @@ error :
|
||||
}
|
||||
|
||||
if (cell_report != NULL) {
|
||||
for (j = 0; j < report_config->nr_cc; j++) {
|
||||
for (int j = 0; j < n_cc; j++) {
|
||||
if (cell_report[j] != NULL) {
|
||||
free(cell_report[j]);
|
||||
}
|
||||
@@ -572,6 +394,7 @@ error :
|
||||
Top Level Request
|
||||
*/
|
||||
|
||||
/*
|
||||
int flexran_agent_stats_request(mid_t mod_id,
|
||||
xid_t xid,
|
||||
const stats_request_config_t *report_config,
|
||||
@@ -678,6 +501,7 @@ int flexran_agent_stats_request(mid_t mod_id,
|
||||
//LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg) {
|
||||
if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG)
|
||||
@@ -708,6 +532,8 @@ int flexran_agent_destroy_stats_reply(Protocol__FlexranMessage *msg)
|
||||
flexran_agent_mac_destroy_stats_reply(msg->stats_reply_msg);
|
||||
flexran_agent_rrc_destroy_stats_reply(msg->stats_reply_msg);
|
||||
flexran_agent_pdcp_destroy_stats_reply(msg->stats_reply_msg);
|
||||
flexran_agent_rrc_gtp_destroy_stats_reply(msg->stats_reply_msg);
|
||||
flexran_agent_s1ap_destroy_stats_reply(msg->stats_reply_msg);
|
||||
for (int i = 0; i < msg->stats_reply_msg->n_cell_report; ++i)
|
||||
free(msg->stats_reply_msg->cell_report[i]);
|
||||
for (int i = 0; i < msg->stats_reply_msg->n_ue_report; ++i)
|
||||
@@ -719,88 +545,3 @@ int flexran_agent_destroy_stats_reply(Protocol__FlexranMessage *msg)
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id) {
|
||||
/*Disable the continuous updates for the MAC*/
|
||||
if (pthread_mutex_lock(stats_context[mod_id].mutex)) {
|
||||
goto error;
|
||||
}
|
||||
stats_context[mod_id].cont_update = 0;
|
||||
stats_context[mod_id].xid = 0;
|
||||
if (stats_context[mod_id].stats_req != NULL) {
|
||||
flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req);
|
||||
}
|
||||
if (stats_context[mod_id].prev_stats_reply != NULL) {
|
||||
flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply);
|
||||
}
|
||||
if (pthread_mutex_unlock(stats_context[mod_id].mutex)) {
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id,
|
||||
xid_t xid, stats_request_config_t *stats_req) {
|
||||
|
||||
if (pthread_mutex_lock(stats_context[mod_id].mutex)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
Protocol__FlexranMessage *req_msg = NULL;
|
||||
|
||||
flexran_agent_stats_request(mod_id, xid, stats_req, &req_msg);
|
||||
|
||||
if (req_msg != NULL) {
|
||||
stats_context[mod_id].stats_req = req_msg;
|
||||
stats_context[mod_id].prev_stats_reply = NULL;
|
||||
|
||||
stats_context[mod_id].cont_update = 1;
|
||||
stats_context[mod_id].xid = xid;
|
||||
}
|
||||
|
||||
if (pthread_mutex_unlock(stats_context[mod_id].mutex)) {
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id) {
|
||||
|
||||
|
||||
/*Initially the continuous update is set to false*/
|
||||
stats_context[mod_id].cont_update = 0;
|
||||
stats_context[mod_id].is_initialized = 1;
|
||||
stats_context[mod_id].stats_req = NULL;
|
||||
stats_context[mod_id].prev_stats_reply = NULL;
|
||||
stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t));
|
||||
if (stats_context[mod_id].mutex == NULL)
|
||||
goto error;
|
||||
if (pthread_mutex_init(stats_context[mod_id].mutex, NULL) != 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_destroy_cont_stats_update(mid_t mod_id) {
|
||||
|
||||
stats_context[mod_id].cont_update = 0;
|
||||
stats_context[mod_id].is_initialized = 0;
|
||||
flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req);
|
||||
flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply);
|
||||
free(stats_context[mod_id].mutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "flexran_agent_ran_api.h"
|
||||
#include "s1ap_eNB_ue_context.h"
|
||||
#include "s1ap_eNB_management_procedures.h"
|
||||
|
||||
static inline int phy_is_present(mid_t mod_id, uint8_t cc_id) {
|
||||
return RC.eNB && RC.eNB[mod_id] && RC.eNB[mod_id][cc_id];
|
||||
@@ -3002,6 +3004,14 @@ int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index) {
|
||||
return ue_context_p->ue_context.e_rab[index].param.gtp_teid;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti)
|
||||
{
|
||||
if (!rrc_is_present(mod_id)) return 0;
|
||||
struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
|
||||
if (!ue_context_p) return -1;
|
||||
return ue_context_p->ue_context.eNB_ue_s1ap_id;
|
||||
}
|
||||
|
||||
/**************************** SLICING ****************************/
|
||||
int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
@@ -3470,6 +3480,195 @@ int flexran_set_ul_slice_scheduler(mid_t mod_id, int slice_idx, char *name) {
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].sched_cb != NULL;
|
||||
}
|
||||
|
||||
/************************** S1AP **************************/
|
||||
int flexran_get_s1ap_mme_pending(mid_t mod_id){
|
||||
if (!rrc_is_present(mod_id)) return -1;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return -1;
|
||||
return s1ap->s1ap_mme_pending_nb;
|
||||
}
|
||||
|
||||
int flexran_get_s1ap_mme_connected(mid_t mod_id){
|
||||
if (!rrc_is_present(mod_id)) return -1;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return -1;
|
||||
return s1ap->s1ap_mme_associated_nb;
|
||||
}
|
||||
|
||||
char* flexran_get_s1ap_enb_s1_ip(mid_t mod_id){
|
||||
if (!rrc_is_present(mod_id)) return NULL;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return NULL;
|
||||
if (s1ap->eNB_s1_ip.ipv4)
|
||||
return &s1ap->eNB_s1_ip.ipv4_address[0];
|
||||
if (s1ap->eNB_s1_ip.ipv6)
|
||||
return &s1ap->eNB_s1_ip.ipv6_address[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* flexran_get_s1ap_enb_name(mid_t mod_id){
|
||||
if (!rrc_is_present(mod_id)) return NULL;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return NULL;
|
||||
return s1ap->eNB_name;
|
||||
}
|
||||
|
||||
int flexran_get_s1ap_nb_mme(mid_t mod_id) {
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return 0;
|
||||
struct s1ap_eNB_mme_data_s *mme = NULL;
|
||||
int count = 0;
|
||||
RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int flexran_get_s1ap_nb_ue(mid_t mod_id) {
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return 0;
|
||||
struct s1ap_eNB_ue_context_s *ue = NULL;
|
||||
int count = 0;
|
||||
RB_FOREACH(ue, s1ap_ue_map, &s1ap->s1ap_ue_head) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int flexran_get_s1ap_mme_conf(mid_t mod_id, mid_t mme_index, Protocol__FlexS1apMme * mme_conf){
|
||||
if (!rrc_is_present(mod_id)) return -1;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return -1;
|
||||
|
||||
struct served_gummei_s *gummei_p = NULL;
|
||||
struct plmn_identity_s *served_plmn_p = NULL;
|
||||
struct served_group_id_s *group_id_p = NULL;
|
||||
struct mme_code_s *mme_code_p = NULL;
|
||||
int i = 0;
|
||||
Protocol__FlexGummei **served_gummeis;
|
||||
Protocol__FlexPlmn **requested_plmns;
|
||||
|
||||
struct s1ap_eNB_mme_data_s *mme = NULL;
|
||||
|
||||
RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head){
|
||||
if (mme_index == 0) break;
|
||||
mme_index--;
|
||||
}
|
||||
if (mme_index > 0) return -1;
|
||||
|
||||
if (mme->mme_s1_ip.ipv4) {
|
||||
mme_conf->s1_ip = (char*) &mme->mme_s1_ip.ipv4_address[0];
|
||||
} else if (mme->mme_s1_ip.ipv6) {
|
||||
mme_conf->s1_ip = (char*) &mme->mme_s1_ip.ipv6_address[0];
|
||||
}
|
||||
mme_conf->name = mme->mme_name;
|
||||
mme_conf->has_state = 1;
|
||||
mme_conf->state = mme->state;
|
||||
|
||||
mme_conf->n_served_gummeis = 0;
|
||||
STAILQ_FOREACH(gummei_p, &mme->served_gummei, next) {
|
||||
mme_conf->n_served_gummeis++;
|
||||
}
|
||||
if (mme_conf->n_served_gummeis > 0) {
|
||||
served_gummeis = calloc(mme_conf->n_served_gummeis, sizeof(Protocol__FlexGummei*));
|
||||
if(served_gummeis == NULL) return -1;
|
||||
|
||||
STAILQ_FOREACH(gummei_p, &mme->served_gummei, next) {
|
||||
served_plmn_p = STAILQ_FIRST(&gummei_p->served_plmns);
|
||||
group_id_p = STAILQ_FIRST(&gummei_p->served_group_ids);
|
||||
mme_code_p = STAILQ_FIRST(&gummei_p->mme_codes);
|
||||
|
||||
served_gummeis[i] = malloc(sizeof(Protocol__FlexGummei));
|
||||
if (!served_gummeis[i]) return -1;
|
||||
protocol__flex_gummei__init(served_gummeis[i]);
|
||||
served_gummeis[i]->plmn = malloc(sizeof(Protocol__FlexPlmn));
|
||||
if (!served_gummeis[i]->plmn) return -1;
|
||||
protocol__flex_plmn__init(served_gummeis[i]->plmn);
|
||||
|
||||
if (served_plmn_p) {
|
||||
served_gummeis[i]->plmn->has_mcc = 1;
|
||||
served_gummeis[i]->plmn->mcc = served_plmn_p->mcc;
|
||||
served_gummeis[i]->plmn->has_mnc = 1;
|
||||
served_gummeis[i]->plmn->mnc = served_plmn_p->mnc;
|
||||
served_gummeis[i]->plmn->has_mnc_length = 1;
|
||||
served_gummeis[i]->plmn->mnc_length = served_plmn_p-> mnc_digit_length;
|
||||
STAILQ_NEXT(served_plmn_p, next);
|
||||
}
|
||||
if (group_id_p) {
|
||||
served_gummeis[i]->has_mme_group_id = 1;
|
||||
served_gummeis[i]->mme_group_id = group_id_p->mme_group_id;
|
||||
STAILQ_NEXT(group_id_p, next);
|
||||
}
|
||||
if (mme_code_p){
|
||||
served_gummeis[i]->has_mme_code = 1;
|
||||
served_gummeis[i]->mme_code = mme_code_p->mme_code;
|
||||
STAILQ_NEXT(mme_code_p, next);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
mme_conf->served_gummeis = served_gummeis;
|
||||
}
|
||||
|
||||
// requested PLMNS
|
||||
mme_conf->n_requested_plmns = mme->broadcast_plmn_num;
|
||||
if (mme_conf->n_requested_plmns > 0){
|
||||
requested_plmns = calloc(mme_conf->n_requested_plmns, sizeof(Protocol__FlexPlmn*));
|
||||
if(requested_plmns == NULL) return -1;
|
||||
for(int i = 0; i < mme_conf->n_requested_plmns; i++) {
|
||||
requested_plmns[i] = malloc(sizeof(Protocol__FlexPlmn));
|
||||
if (!requested_plmns[i]) return -1;
|
||||
protocol__flex_plmn__init(requested_plmns[i]);
|
||||
requested_plmns[i]->mcc = s1ap->mcc[mme->broadcast_plmn_index[i]];
|
||||
requested_plmns[i]->has_mcc = 1;
|
||||
requested_plmns[i]->mnc = s1ap->mnc[mme->broadcast_plmn_index[i]];
|
||||
requested_plmns[i]->has_mnc = 1;
|
||||
requested_plmns[i]->mnc_length = s1ap->mnc_digit_length[mme->broadcast_plmn_index[i]];
|
||||
requested_plmns[i]->has_mnc_length = 1;
|
||||
}
|
||||
mme_conf->requested_plmns = requested_plmns;
|
||||
}
|
||||
|
||||
mme_conf->has_rel_capacity = 1;
|
||||
mme_conf->rel_capacity = mme->relative_mme_capacity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexran_get_s1ap_ue(mid_t mod_id, rnti_t rnti, Protocol__FlexS1apUe * ue_conf){
|
||||
if (!rrc_is_present(mod_id)) return -1;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return -1;
|
||||
|
||||
uint32_t enb_ue_s1ap_id = flexran_get_rrc_enb_ue_s1ap_id(mod_id, rnti);
|
||||
struct s1ap_eNB_ue_context_s *ue = NULL;
|
||||
RB_FOREACH(ue, s1ap_ue_map, &s1ap->s1ap_ue_head){
|
||||
if (ue->eNB_ue_s1ap_id == enb_ue_s1ap_id) break;
|
||||
}
|
||||
if (ue == NULL) return -1;
|
||||
|
||||
if (ue->mme_ref->mme_s1_ip.ipv4)
|
||||
ue_conf->mme_s1_ip = (char*) &ue->mme_ref->mme_s1_ip.ipv4_address[0];
|
||||
else if (ue->mme_ref->mme_s1_ip.ipv6)
|
||||
ue_conf->mme_s1_ip = (char*) &ue->mme_ref->mme_s1_ip.ipv6_address[0];
|
||||
|
||||
ue_conf->has_enb_ue_s1ap_id = 1;
|
||||
ue_conf->enb_ue_s1ap_id = ue->eNB_ue_s1ap_id;
|
||||
ue_conf->has_mme_ue_s1ap_id = 1;
|
||||
ue_conf->mme_ue_s1ap_id = ue->mme_ue_s1ap_id;
|
||||
|
||||
ue_conf->selected_plmn = malloc(sizeof(Protocol__FlexPlmn));
|
||||
if (!ue_conf->selected_plmn) return -1;
|
||||
protocol__flex_plmn__init(ue_conf->selected_plmn);
|
||||
|
||||
ue_conf->selected_plmn->has_mcc = 1;
|
||||
ue_conf->selected_plmn->mcc = s1ap->mcc[ue->selected_plmn_identity];
|
||||
ue_conf->selected_plmn->has_mnc = 1;
|
||||
ue_conf->selected_plmn->mnc = s1ap->mnc[ue->selected_plmn_identity];
|
||||
ue_conf->selected_plmn->has_mnc_length = 1;
|
||||
ue_conf->selected_plmn->mnc_length = s1ap->mnc_digit_length[ue->selected_plmn_identity];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************** General BS info ****************************/
|
||||
uint64_t flexran_get_bs_id(mid_t mod_id) {
|
||||
if (!rrc_is_present(mod_id)) return 0;
|
||||
@@ -3488,15 +3687,15 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps)
|
||||
case ngran_eNB_CU:
|
||||
case ngran_ng_eNB_CU:
|
||||
case ngran_gNB_CU:
|
||||
n_caps = 3;
|
||||
n_caps = 4;
|
||||
*caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability));
|
||||
AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n",
|
||||
n_caps * sizeof(Protocol__FlexBsCapability));
|
||||
(*caps)[0] = PROTOCOL__FLEX_BS_CAPABILITY__PDCP;
|
||||
(*caps)[1] = PROTOCOL__FLEX_BS_CAPABILITY__SDAP;
|
||||
(*caps)[2] = PROTOCOL__FLEX_BS_CAPABILITY__RRC;
|
||||
(*caps)[3] = PROTOCOL__FLEX_BS_CAPABILITY__S1AP;
|
||||
break;
|
||||
|
||||
case ngran_eNB_DU:
|
||||
case ngran_gNB_DU:
|
||||
n_caps = 5;
|
||||
@@ -3509,11 +3708,10 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps)
|
||||
(*caps)[3] = PROTOCOL__FLEX_BS_CAPABILITY__HIMAC;
|
||||
(*caps)[4] = PROTOCOL__FLEX_BS_CAPABILITY__RLC;
|
||||
break;
|
||||
|
||||
case ngran_eNB:
|
||||
case ngran_ng_eNB:
|
||||
case ngran_gNB:
|
||||
n_caps = 8;
|
||||
n_caps = 9;
|
||||
*caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability));
|
||||
AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n",
|
||||
n_caps * sizeof(Protocol__FlexBsCapability));
|
||||
@@ -3525,48 +3723,81 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps)
|
||||
(*caps)[5] = PROTOCOL__FLEX_BS_CAPABILITY__PDCP;
|
||||
(*caps)[6] = PROTOCOL__FLEX_BS_CAPABILITY__SDAP;
|
||||
(*caps)[7] = PROTOCOL__FLEX_BS_CAPABILITY__RRC;
|
||||
(*caps)[8] = PROTOCOL__FLEX_BS_CAPABILITY__S1AP;
|
||||
break;
|
||||
case ngran_eNB_MBMS_STA:
|
||||
AssertFatal(0, "MBMS STA not supported by FlexRAN!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return n_caps;
|
||||
}
|
||||
|
||||
uint16_t flexran_get_capabilities_mask(mid_t mod_id) {
|
||||
uint32_t flexran_get_capabilities_mask(mid_t mod_id) {
|
||||
if (!rrc_is_present(mod_id)) return 0;
|
||||
|
||||
uint16_t mask = 0;
|
||||
|
||||
uint32_t mask = 0;
|
||||
switch (RC.rrc[mod_id]->node_type) {
|
||||
case ngran_eNB_CU:
|
||||
case ngran_ng_eNB_CU:
|
||||
case ngran_gNB_CU:
|
||||
mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC);
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP);
|
||||
break;
|
||||
|
||||
case ngran_eNB_DU:
|
||||
case ngran_gNB_DU:
|
||||
mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC);
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC);
|
||||
break;
|
||||
|
||||
case ngran_eNB:
|
||||
case ngran_ng_eNB:
|
||||
case ngran_gNB:
|
||||
mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC);
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC)
|
||||
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP);
|
||||
break;
|
||||
case ngran_eNB_MBMS_STA:
|
||||
AssertFatal(0, "MBMS STA not supported by FlexRAN!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
size_t flexran_get_splits(mid_t mod_id, Protocol__FlexBsSplit **splits) {
|
||||
size_t n_splits = 0;
|
||||
*splits = NULL;
|
||||
if (rrc_is_present(mod_id) && !NODE_IS_MONOLITHIC(RC.rrc[mod_id]->node_type))
|
||||
n_splits++;
|
||||
if (NFAPI_MODE != NFAPI_MONOLITHIC)
|
||||
n_splits++;
|
||||
if (RC.ru && RC.ru[mod_id] && RC.ru[mod_id]->if_south != LOCAL_RF)
|
||||
n_splits++;
|
||||
if (n_splits == 0)
|
||||
return 0;
|
||||
|
||||
AssertFatal(n_splits < 3, "illegal number of splits (%lu)\n", n_splits);
|
||||
*splits = calloc(n_splits, sizeof(Protocol__FlexBsSplit));
|
||||
AssertFatal(*splits, "could not allocate Protocol__FlexBsSplit array\n");
|
||||
int n = 0;
|
||||
if (rrc_is_present(mod_id) && !NODE_IS_MONOLITHIC(RC.rrc[mod_id]->node_type))
|
||||
(*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__F1;
|
||||
if (NFAPI_MODE != NFAPI_MONOLITHIC)
|
||||
(*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__nFAPI;
|
||||
if (RC.ru && RC.ru[mod_id] && RC.ru[mod_id]->if_south == REMOTE_IF4p5)
|
||||
(*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__IF4p5;
|
||||
if (RC.ru && RC.ru[mod_id] && RC.ru[mod_id]->if_south == REMOTE_IF5)
|
||||
(*splits)[n++] = PROTOCOL__FLEX_BS_SPLIT__IF5;
|
||||
DevAssert(n == n_splits);
|
||||
return n_splits;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "RRC/LTE/rrc_eNB_UE_context.h"
|
||||
#include "PHY/phy_extern.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
|
||||
/****************************
|
||||
* get generic info from RAN
|
||||
@@ -651,6 +652,9 @@ int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index);
|
||||
/* Get the TEID at the SGW for UE */
|
||||
int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index);
|
||||
|
||||
/* gets the UEs S1AP ID at eNodeB, stored in RRC */
|
||||
uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti);
|
||||
|
||||
/************************** Slice configuration **************************/
|
||||
|
||||
/* Get the DL slice ID for a UE */
|
||||
@@ -803,6 +807,31 @@ char *flexran_get_ul_slice_scheduler(mid_t mod_id, int slice_idx);
|
||||
/* Set the scheduler name for a slice in UL */
|
||||
int flexran_set_ul_slice_scheduler(mid_t mod_id, int slice_idx, char *name);
|
||||
|
||||
/************************** S1AP **************************/
|
||||
/* Get the number of MMEs to be connected */
|
||||
int flexran_get_s1ap_mme_pending(mid_t mod_id);
|
||||
|
||||
/* Get the number of connected MMEs */
|
||||
int flexran_get_s1ap_mme_connected(mid_t mod_id);
|
||||
|
||||
/* Get the eNB S1AP IP address */
|
||||
char* flexran_get_s1ap_enb_s1_ip(mid_t mod_id);
|
||||
|
||||
/* Get the name of the eNB */
|
||||
char* flexran_get_s1ap_enb_name(mid_t mod_id);
|
||||
|
||||
/* Get the number of connected MMEs to this eNB */
|
||||
int flexran_get_s1ap_nb_mme(mid_t mod_id);
|
||||
|
||||
/* Get the number of connected UEs to this eNB */
|
||||
int flexran_get_s1ap_nb_ue(mid_t mod_id);
|
||||
|
||||
/* Get the S1AP MME conf */
|
||||
int flexran_get_s1ap_mme_conf(mid_t mod_id, mid_t mme_index, Protocol__FlexS1apMme * mme_conf);
|
||||
|
||||
/* Get the S1AP UE conf */
|
||||
int flexran_get_s1ap_ue(mid_t mod_id, rnti_t rnti, Protocol__FlexS1apUe * ue_conf);
|
||||
|
||||
/********************* general information *****************/
|
||||
/* get an ID for this BS (or part of a BS) */
|
||||
uint64_t flexran_get_bs_id(mid_t mod_id);
|
||||
@@ -814,4 +843,9 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps)
|
||||
|
||||
/* get the capabilities supported by the underlying network function as a bit
|
||||
* mask. */
|
||||
uint16_t flexran_get_capabilities_mask(mid_t mod_id);
|
||||
uint32_t flexran_get_capabilities_mask(mid_t mod_id);
|
||||
|
||||
/* get the splits used by the underlying network function,
|
||||
* return the number and stores list of this length in splits. If there are
|
||||
* zero capabilities, splits will be NULL */
|
||||
size_t flexran_get_splits(mid_t mod_id, Protocol__FlexBsSplit **splits);
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "flexran_agent_task_manager.h"
|
||||
#include "flexran_agent_common.c"
|
||||
#include "flexran_agent_common.h"
|
||||
|
||||
|
||||
/* Util macros */
|
||||
|
||||
@@ -21,187 +21,266 @@
|
||||
|
||||
/*! \file flexran_agent_timer.c
|
||||
* \brief FlexRAN Timer
|
||||
* \author shahab SHARIAT BAGHERI
|
||||
* \date 2017
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
/*
|
||||
* timer primitives
|
||||
* \author Robert Schmidt
|
||||
* \date 2019
|
||||
* \version 0.2
|
||||
*/
|
||||
|
||||
#include "flexran_agent_timer.h"
|
||||
#include "flexran_agent_extern.h"
|
||||
#include <pthread.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
//struct flexran_agent_map agent_map;
|
||||
flexran_agent_timer_instance_t timer_instance;
|
||||
int agent_timer_init = 0;
|
||||
err_code_t flexran_agent_init_timer(void) {
|
||||
LOG_I(FLEXRAN_AGENT, "init RB tree\n");
|
||||
#define MAX_NUM_TIMERS 10
|
||||
|
||||
if (!agent_timer_init) {
|
||||
RB_INIT(&timer_instance.flexran_agent_head);
|
||||
agent_timer_init = 1;
|
||||
typedef struct flexran_agent_timer_element_s {
|
||||
mid_t mod_id;
|
||||
xid_t xid; /* The id of the task as received by the controller message*/
|
||||
uint32_t sf;
|
||||
uint64_t next;
|
||||
flexran_agent_timer_callback_t cb;
|
||||
Protocol__FlexranMessage *msg;
|
||||
} flexran_agent_timer_element_t;
|
||||
|
||||
typedef struct flexran_agent_timer_extern_source_s {
|
||||
pthread_mutex_t mutex_sync;
|
||||
pthread_cond_t cond;
|
||||
int wait;
|
||||
} flexran_agent_timer_extern_source_t;
|
||||
|
||||
struct timesync {
|
||||
void *param_sync;
|
||||
void (*fsync)(void *);
|
||||
pthread_t thread;
|
||||
|
||||
uint64_t current;
|
||||
uint64_t next;
|
||||
|
||||
int timer_num;
|
||||
flexran_agent_timer_element_t *timer[MAX_NUM_TIMERS];
|
||||
pthread_mutex_t mutex_timer;
|
||||
|
||||
int exit;
|
||||
};
|
||||
struct timesync timesync[NUM_MAX_ENB];
|
||||
|
||||
int flexran_agent_timer_signal_init(struct timesync *sync);
|
||||
int flexran_agent_timer_source_setup(struct timesync *sync);
|
||||
void *flexran_agent_timer_thread(void *args);
|
||||
void flexran_agent_timer_remove_internal(struct timesync *sync, int index);
|
||||
void flexran_agent_timer_process(flexran_agent_timer_element_t *t);
|
||||
|
||||
|
||||
err_code_t flexran_agent_timer_init(mid_t mod_id) {
|
||||
struct timesync *sync = ×ync[mod_id];
|
||||
sync->current = 0;
|
||||
sync->next = 0;
|
||||
sync->timer_num = 0;
|
||||
for (int i = 0; i < MAX_NUM_TIMERS; ++i)
|
||||
sync->timer[i] = NULL;
|
||||
pthread_mutex_init(&sync->mutex_timer, NULL);
|
||||
sync->exit = 0;
|
||||
|
||||
/* if there is a MAC, we assume we can have a tick from the MAC interface
|
||||
* (external tick source). Otherwise, generate a tick internally via the
|
||||
* timerfd linux library. The init functions set everything up and the thread
|
||||
* will use whatever is available. */
|
||||
int (*init)(struct timesync *) = flexran_agent_get_mac_xface(mod_id) ?
|
||||
flexran_agent_timer_signal_init : flexran_agent_timer_source_setup;
|
||||
if (init(timesync) < 0
|
||||
|| pthread_create(&sync->thread, NULL, flexran_agent_timer_thread, sync) != 0) {
|
||||
sync->thread = 0;
|
||||
if (sync->param_sync)
|
||||
free(sync->param_sync);
|
||||
LOG_E(FLEXRAN_AGENT, "could not start timer thread\n");
|
||||
return TIMER_SETUP_FAILED;
|
||||
}
|
||||
|
||||
return PROTOCOL__FLEXRAN_ERR__NO_ERR;
|
||||
}
|
||||
|
||||
RB_GENERATE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer);
|
||||
void flexran_agent_timer_exit(mid_t mod_id) {
|
||||
timesync[mod_id].exit = 1;
|
||||
}
|
||||
|
||||
/* The timer_id might not be the best choice for the comparison */
|
||||
int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b) {
|
||||
if (a->timer_id < b->timer_id) return -1;
|
||||
void flexran_agent_timer_source_sync(void *sync) {
|
||||
int fd = *(int *)sync;
|
||||
uint64_t occ;
|
||||
int rc __attribute__((unused)) = read(fd, &occ, sizeof(occ));
|
||||
}
|
||||
|
||||
if (a->timer_id > b->timer_id) return 1;
|
||||
int flexran_agent_timer_source_setup(struct timesync *sync) {
|
||||
sync->param_sync = malloc(sizeof(int));
|
||||
if (!sync->param_sync)
|
||||
return -1;
|
||||
int fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
// equal timers
|
||||
const uint64_t period_ns = 1000000; // 1ms
|
||||
struct itimerspec t;
|
||||
t.it_interval.tv_sec = period_ns / 1000000000;
|
||||
t.it_interval.tv_nsec = period_ns % 1000000000;
|
||||
t.it_value.tv_sec = period_ns / 1000000000;
|
||||
t.it_value.tv_nsec = period_ns % 1000000000;
|
||||
int rc = timerfd_settime(fd, 0, &t, NULL);
|
||||
if (rc != 0)
|
||||
return -1;
|
||||
*(int *)sync->param_sync = fd;
|
||||
sync->fsync = flexran_agent_timer_source_sync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_create_timer(uint32_t interval_sec,
|
||||
uint32_t interval_usec,
|
||||
agent_id_t agent_id,
|
||||
instance_t instance,
|
||||
uint32_t timer_type,
|
||||
xid_t xid,
|
||||
void flexran_agent_timer_signal_sync(void *param_sync) {
|
||||
flexran_agent_timer_extern_source_t *sync = param_sync;
|
||||
pthread_mutex_lock(&sync->mutex_sync);
|
||||
while (sync->wait) {
|
||||
pthread_cond_wait(&sync->cond, &sync->mutex_sync);
|
||||
}
|
||||
sync->wait = 1;
|
||||
pthread_mutex_unlock(&sync->mutex_sync);
|
||||
}
|
||||
|
||||
int flexran_agent_timer_signal_init(struct timesync *sync) {
|
||||
flexran_agent_timer_extern_source_t *s = malloc(sizeof(flexran_agent_timer_extern_source_t));
|
||||
if (!s)
|
||||
return TIMER_SETUP_FAILED;
|
||||
if (pthread_mutex_init(&s->mutex_sync, NULL) < 0)
|
||||
return TIMER_SETUP_FAILED;
|
||||
if (pthread_cond_init(&s->cond, NULL) < 0)
|
||||
return TIMER_SETUP_FAILED;
|
||||
s->wait = 1;
|
||||
sync->param_sync = s;
|
||||
sync->fsync = flexran_agent_timer_signal_sync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexran_agent_timer_signal(mid_t mod_id) {
|
||||
flexran_agent_timer_extern_source_t *sync = timesync[mod_id].param_sync;
|
||||
pthread_mutex_lock(&sync->mutex_sync);
|
||||
sync->wait = 0;
|
||||
pthread_mutex_unlock(&sync->mutex_sync);
|
||||
pthread_cond_signal(&sync->cond);
|
||||
}
|
||||
|
||||
void *flexran_agent_timer_thread(void *args) {
|
||||
struct timesync *sync = args;
|
||||
while (1) {
|
||||
sync->fsync(sync->param_sync);
|
||||
if (sync->exit)
|
||||
break;
|
||||
|
||||
pthread_mutex_lock(&sync->mutex_timer);
|
||||
sync->current++;
|
||||
|
||||
if (sync->current < sync->next) {
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sync->timer_num; ++i) {
|
||||
flexran_agent_timer_element_t *t = sync->timer[i];
|
||||
if (sync->current == t->next) {
|
||||
flexran_agent_timer_process(t);
|
||||
t->next += t->sf;
|
||||
}
|
||||
if (sync->next == sync->current || t->next < sync->next)
|
||||
sync->next = t->next;
|
||||
}
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
}
|
||||
LOG_W(FLEXRAN_AGENT, "terminated timer thread\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void flexran_agent_timer_process(flexran_agent_timer_element_t *t) {
|
||||
Protocol__FlexranMessage *msg = t->cb(t->mod_id, t->msg);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
int size = 0;
|
||||
void *data = flexran_agent_pack_message(msg, &size);
|
||||
if (flexran_agent_msg_send(t->mod_id, FLEXRAN_AGENT_DEFAULT, data, size, 0) < 0)
|
||||
LOG_E(FLEXRAN_AGENT, "error while sending message for timer xid %d\n", t->xid);
|
||||
}
|
||||
|
||||
|
||||
err_code_t flexran_agent_create_timer(mid_t mod_id,
|
||||
uint32_t sf,
|
||||
flexran_agent_timer_type_t timer_type,
|
||||
xid_t xid,
|
||||
flexran_agent_timer_callback_t cb,
|
||||
void *timer_args,
|
||||
long *timer_id) {
|
||||
struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e));
|
||||
DevAssert(e != NULL);
|
||||
//uint32_t timer_id;
|
||||
int ret=-1;
|
||||
|
||||
if ((interval_sec == 0) && (interval_usec == 0 )) {
|
||||
free(e);
|
||||
Protocol__FlexranMessage *msg) {
|
||||
if (sf == 0)
|
||||
return TIMER_NULL;
|
||||
}
|
||||
if (cb == NULL)
|
||||
return TIMER_SETUP_FAILED;
|
||||
AssertFatal(timer_type != FLEXRAN_AGENT_TIMER_TYPE_ONESHOT,
|
||||
"one shot timer not yet implemented\n");
|
||||
|
||||
if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) {
|
||||
free(e);
|
||||
return TIMER_TYPE_INVALIDE;
|
||||
}
|
||||
|
||||
if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT) {
|
||||
ret = timer_setup(interval_sec,
|
||||
interval_usec,
|
||||
TASK_FLEXRAN_AGENT,
|
||||
instance,
|
||||
TIMER_ONE_SHOT,
|
||||
timer_args,
|
||||
timer_id);
|
||||
|
||||
e->type = TIMER_ONE_SHOT;
|
||||
} else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ) {
|
||||
ret = timer_setup(interval_sec,
|
||||
interval_usec,
|
||||
TASK_FLEXRAN_AGENT,
|
||||
instance,
|
||||
TIMER_PERIODIC,
|
||||
timer_args,
|
||||
timer_id);
|
||||
e->type = TIMER_PERIODIC;
|
||||
}
|
||||
|
||||
if (ret < 0 ) {
|
||||
free(e);
|
||||
flexran_agent_timer_element_t *t = malloc(sizeof(flexran_agent_timer_element_t));
|
||||
if (!t) {
|
||||
LOG_E(FLEXRAN_AGENT, "no memory for new timer %d\n", xid);
|
||||
return TIMER_SETUP_FAILED;
|
||||
}
|
||||
t->mod_id = mod_id;
|
||||
t->xid = xid;
|
||||
t->sf = sf;
|
||||
t->cb = cb;
|
||||
t->msg = msg;
|
||||
|
||||
e->agent_id = agent_id;
|
||||
e->instance = instance;
|
||||
e->state = FLEXRAN_AGENT_TIMER_STATE_ACTIVE;
|
||||
e->timer_id = *timer_id;
|
||||
e->xid = xid;
|
||||
e->timer_args = timer_args;
|
||||
e->cb = cb;
|
||||
/*element should be a real pointer*/
|
||||
RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e);
|
||||
LOG_I(FLEXRAN_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n",
|
||||
e->timer_id, e->agent_id, e->instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_destroy_timer(long timer_id) {
|
||||
struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id);
|
||||
|
||||
if (e != NULL ) {
|
||||
RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e);
|
||||
flexran_agent_destroy_flexran_message(e->timer_args->msg);
|
||||
free(e);
|
||||
struct timesync *sync = ×ync[mod_id];
|
||||
pthread_mutex_lock(&sync->mutex_timer);
|
||||
if (sync->timer_num >= MAX_NUM_TIMERS) {
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
LOG_E(FLEXRAN_AGENT, "maximum number of timers (%d) reached while adding timer %d\n",
|
||||
sync->timer_num, xid);
|
||||
free(t);
|
||||
return TIMER_SETUP_FAILED;
|
||||
}
|
||||
|
||||
if (timer_remove(timer_id) < 0 )
|
||||
goto error;
|
||||
|
||||
/* TODO check that xid does not exist? */
|
||||
t->next = sync->current + 1;
|
||||
if (sync->next <= sync->current || t->next < sync->next)
|
||||
sync->next = t->next;
|
||||
sync->timer[sync->timer_num] = t;
|
||||
sync->timer_num++;
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
LOG_D(FLEXRAN_AGENT, "added new timer xid %d for agent %d\n", xid, mod_id);
|
||||
return 0;
|
||||
error:
|
||||
LOG_E(FLEXRAN_AGENT, "timer can't be removed\n");
|
||||
return TIMER_REMOVED_FAILED ;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid) {
|
||||
struct flexran_agent_timer_element_s *e = NULL;
|
||||
long timer_id;
|
||||
RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) {
|
||||
if (e->xid == xid) {
|
||||
timer_id = e->timer_id;
|
||||
RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e);
|
||||
flexran_agent_destroy_flexran_message(e->timer_args->msg);
|
||||
free(e);
|
||||
err_code_t flexran_agent_destroy_timers(mid_t mod_id) {
|
||||
struct timesync *sync = ×ync[mod_id];
|
||||
pthread_mutex_lock(&sync->mutex_timer);
|
||||
for (int i = sync->timer_num - 1; i < 0; --i) {
|
||||
flexran_agent_timer_remove_internal(sync, i);
|
||||
}
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (timer_remove(timer_id) < 0 ) {
|
||||
goto error;
|
||||
}
|
||||
err_code_t flexran_agent_destroy_timer(mid_t mod_id, xid_t xid) {
|
||||
struct timesync *sync = ×ync[mod_id];
|
||||
pthread_mutex_lock(&sync->mutex_timer);
|
||||
for (int i = 0; i < sync->timer_num; ++i) {
|
||||
if (sync->timer[i]->xid == xid) {
|
||||
flexran_agent_timer_remove_internal(sync, i);
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
LOG_E(FLEXRAN_AGENT, "timer can't be removed\n");
|
||||
return TIMER_REMOVED_FAILED ;
|
||||
pthread_mutex_unlock(&sync->mutex_timer);
|
||||
LOG_E(FLEXRAN_AGENT, "could not find timer %d\n", xid);
|
||||
return TIMER_ELEMENT_NOT_FOUND;
|
||||
}
|
||||
|
||||
err_code_t flexran_agent_destroy_timers(void) {
|
||||
struct flexran_agent_timer_element_s *e = NULL;
|
||||
RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) {
|
||||
RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e);
|
||||
timer_remove(e->timer_id);
|
||||
flexran_agent_destroy_flexran_message(e->timer_args->msg);
|
||||
free(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexran_agent_sleep_until(struct timespec *ts, int delay) {
|
||||
ts->tv_nsec += delay;
|
||||
|
||||
if(ts->tv_nsec >= 1000*1000*1000) {
|
||||
ts->tv_nsec -= 1000*1000*1000;
|
||||
ts->tv_sec++;
|
||||
}
|
||||
|
||||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL);
|
||||
}
|
||||
|
||||
|
||||
err_code_t flexran_agent_stop_timer(long timer_id) {
|
||||
struct flexran_agent_timer_element_s *e=NULL;
|
||||
struct flexran_agent_timer_element_s search;
|
||||
memset(&search, 0, sizeof(struct flexran_agent_timer_element_s));
|
||||
search.timer_id = timer_id;
|
||||
e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search);
|
||||
|
||||
if (e != NULL ) {
|
||||
e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED;
|
||||
}
|
||||
|
||||
timer_remove(timer_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct flexran_agent_timer_element_s *get_timer_entry(long timer_id) {
|
||||
struct flexran_agent_timer_element_s search;
|
||||
memset(&search, 0, sizeof(struct flexran_agent_timer_element_s));
|
||||
search.timer_id = timer_id;
|
||||
return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search);
|
||||
/* this function assumes that the timer lock is held */
|
||||
void flexran_agent_timer_remove_internal(struct timesync *sync, int index) {
|
||||
LOG_I(FLEXRAN_AGENT, "remove timer xid %d (index %d) for agent %d\n",
|
||||
sync->timer[index]->xid, index, sync->timer[index]->mod_id);
|
||||
flexran_agent_destroy_flexran_message(sync->timer[index]->msg);
|
||||
free(sync->timer[index]);
|
||||
for (int i = index + 1; i < sync->timer_num; ++i)
|
||||
sync->timer[i - 1] = sync->timer[i];
|
||||
sync->timer_num--;
|
||||
sync->timer[sync->timer_num] = NULL;
|
||||
}
|
||||
|
||||
@@ -26,107 +26,45 @@
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#ifndef _FLEXRAN_AGENT_TIMER_
|
||||
#define _FLEXRAN_AGENT_TIMER_
|
||||
|
||||
#include "flexran_agent_common.h"
|
||||
#include "flexran_agent_common_internal.h"
|
||||
#include "flexran_agent_extern.h"
|
||||
#include "flexran_agent_defs.h"
|
||||
|
||||
|
||||
# include "tree.h"
|
||||
# include "intertask_interface.h"
|
||||
|
||||
|
||||
|
||||
/*******************
|
||||
* timer primitves
|
||||
*******************/
|
||||
|
||||
#define TIMER_NULL -1
|
||||
#define TIMER_TYPE_INVALIDE -2
|
||||
#define TIMER_SETUP_FAILED -3
|
||||
#define TIMER_REMOVED_FAILED -4
|
||||
#define TIMER_ELEMENT_NOT_FOUND -5
|
||||
|
||||
typedef enum {
|
||||
FLEXRAN_AGENT_TIMER_TYPE_ONESHOT,
|
||||
FLEXRAN_AGENT_TIMER_TYPE_PERIODIC,
|
||||
} flexran_agent_timer_type_t;
|
||||
|
||||
/* Type of the callback executed when the timer expired */
|
||||
typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*);
|
||||
typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(
|
||||
mid_t mod_id, const Protocol__FlexranMessage *msg);
|
||||
|
||||
err_code_t flexran_agent_timer_init(mid_t mod_id);
|
||||
void flexran_agent_timer_exit(mid_t mod_id);
|
||||
|
||||
typedef struct flexran_agent_timer_args_s{
|
||||
mid_t mod_id;
|
||||
Protocol__FlexranMessage *msg;
|
||||
} flexran_agent_timer_args_t;
|
||||
/* Signals next subframe for FlexRAN timers */
|
||||
void flexran_agent_timer_signal(mid_t mod_id);
|
||||
|
||||
|
||||
typedef struct flexran_agent_timer_element_s{
|
||||
RB_ENTRY(flexran_agent_timer_element_s) entry;
|
||||
|
||||
agent_id_t agent_id;
|
||||
instance_t instance;
|
||||
|
||||
flexran_agent_timer_type_t type;
|
||||
flexran_agent_timer_state_t state;
|
||||
|
||||
uint32_t interval_sec;
|
||||
uint32_t interval_usec;
|
||||
|
||||
long timer_id; /* Timer id returned by the timer API*/
|
||||
xid_t xid; /*The id of the task as received by the controller
|
||||
message*/
|
||||
|
||||
flexran_agent_timer_callback_t cb;
|
||||
flexran_agent_timer_args_t *timer_args;
|
||||
|
||||
} flexran_agent_timer_element_t;
|
||||
|
||||
typedef struct flexran_agent_timer_instance_s{
|
||||
RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head;
|
||||
}flexran_agent_timer_instance_t;
|
||||
|
||||
|
||||
err_code_t flexran_agent_init_timer(void);
|
||||
|
||||
/* Create a timer for some agent related event with id xid. Will store the id
|
||||
of the generated timer in timer_id */
|
||||
err_code_t flexran_agent_create_timer(uint32_t interval_sec,
|
||||
uint32_t interval_usec,
|
||||
agent_id_t agent_id,
|
||||
instance_t instance,
|
||||
uint32_t timer_type,
|
||||
xid_t xid,
|
||||
flexran_agent_timer_callback_t cb,
|
||||
void* timer_args,
|
||||
long *timer_id);
|
||||
/* Create a timer for some agent related event with id xid. */
|
||||
err_code_t flexran_agent_create_timer(mid_t mod_id,
|
||||
uint32_t sf,
|
||||
flexran_agent_timer_type_t timer_type,
|
||||
xid_t xid,
|
||||
flexran_agent_timer_callback_t cb,
|
||||
Protocol__FlexranMessage *msg);
|
||||
|
||||
/* Destroy all existing timers */
|
||||
err_code_t flexran_agent_destroy_timers(void);
|
||||
|
||||
/* Destroy the timer with the given timer_id */
|
||||
err_code_t flexran_agent_destroy_timer(long timer_id);
|
||||
err_code_t flexran_agent_destroy_timers(mid_t mod_id);
|
||||
|
||||
/* Destroy the timer for task with id xid */
|
||||
err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid);
|
||||
err_code_t flexran_agent_destroy_timer(mid_t mod_id, xid_t xid);
|
||||
|
||||
/* Stop a timer */
|
||||
err_code_t flexran_agent_stop_timer(long timer_id);
|
||||
|
||||
/* Restart the given timer */
|
||||
err_code_t flexran_agent_restart_timer(long *timer_id);
|
||||
|
||||
/* Find the timer with the given timer_id */
|
||||
struct flexran_agent_timer_element_s * get_timer_entry(long timer_id);
|
||||
|
||||
/* Obtain the protocol message stored in the given expired timer */
|
||||
Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args);
|
||||
|
||||
/* Comparator function comparing two timers. Decides the ordering of the timers */
|
||||
int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b);
|
||||
|
||||
/*Specify a delay in nanoseconds to timespec and sleep until then*/
|
||||
void flexran_agent_sleep_until(struct timespec *ts, int delay);
|
||||
|
||||
/* RB_PROTOTYPE is for .h files */
|
||||
RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer);
|
||||
#endif /* _FLEXRAN_AGENT_TIMER_ */
|
||||
|
||||
Reference in New Issue
Block a user