Commit a87220d3 authored by Robert Schmidt's avatar Robert Schmidt

Add S1AP control module for FlexRAN with status monitoring support

parent 44fdb23f
......@@ -923,6 +923,7 @@ include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PHY")
include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC")
include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC")
include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP")
include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/S1AP")
include_directories("${OPENAIR2_DIR}/UTIL/OSA")
include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc")
include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc")
......@@ -1016,6 +1017,7 @@ add_library(FLEXRAN_AGENT
${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.c
${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c
${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/S1AP/flexran_agent_s1ap.c
${OPENAIR2_DIR}/ENB_APP/flexran_agent.c
${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c
${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c
......
/*
* 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];
}
/*
* 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
/*
* 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
......@@ -355,13 +355,6 @@ message flex_s1ap_mme {
optional uint32 rel_capacity = 6; // Relative MME capacity, TS23.401
}
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
}
enum flex_mme_state {
FLMMES_DISCONNECTED = 0;
FLMMES_WAITING = 1;
......
......@@ -100,7 +100,6 @@ message flex_ue_config {
optional uint32 ul_slice_id = 32;
// Configuration about RRC measurements
optional flex_measurement_info info = 33;
optional uint32 enb_ue_s1ap_id = 34; // S1AP ID on eNodeB side
}
message flex_lc_ue_config {
......@@ -109,10 +108,9 @@ message flex_lc_ue_config {
}
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;
repeated flex_s1ap_ue ue = 6;
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;
}
......@@ -75,6 +75,7 @@ enum flex_bs_capability {
PDCP = 5;
SDAP = 6;
RRC = 7;
S1AP = 8;
}
enum flex_bs_split {
......
......@@ -310,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
......
......@@ -177,8 +177,8 @@ int flexran_agent_start(mid_t mod_id)
/* 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" : "",
......@@ -187,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);
......@@ -210,6 +211,11 @@ 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
*/
......
......@@ -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"
......@@ -339,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);
......@@ -757,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));
......
......@@ -116,6 +116,7 @@ typedef int32_t err_code_t;
#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,
......
......@@ -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"
......@@ -324,6 +325,14 @@ int flexran_agent_stats_reply(mid_t enb_id,
goto error;
}
/* 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;
}
......@@ -523,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)
......
......@@ -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,13 +3687,14 @@ 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:
......@@ -3511,7 +3711,7 @@ size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps)
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));
......@@ -3523,26 +3723,27 @@ 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__RRC)
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP);
break;
case ngran_eNB_DU:
case ngran_gNB_DU:
......@@ -3562,9 +3763,11 @@ uint16_t flexran_get_capabilities_mask(mid_t mod_id) {
| (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__RRC)
| (1 << PROTOCOL__FLEX_BS_CAPABILITY__S1AP);
break;
case ngran_eNB_MBMS_STA:
AssertFatal(0, "MBMS STA not supported by FlexRAN!\n");
break;
}
......
......@@ -652,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 */
......@@ -804,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);
......@@ -815,7 +843,7 @@ 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
......
......@@ -124,7 +124,9 @@ static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
s1ap_mme_data_p->assoc_id = -1;
s1ap_mme_data_p->broadcast_plmn_num = broadcast_plmn_num;
memcpy(&s1ap_mme_data_p->mme_s1_ip,
mme_ip_address,
sizeof(*mme_ip_address));
for (int i = 0; i < broadcast_plmn_num; ++i)
s1ap_mme_data_p->broadcast_plmn_index[i] = broadcast_plmn_index[i];
......@@ -193,6 +195,10 @@ void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *
new_instance->eNB_id = s1ap_register_eNB->eNB_id;
new_instance->cell_type = s1ap_register_eNB->cell_type;
new_instance->tac = s1ap_register_eNB->tac;
memcpy(&new_instance->eNB_s1_ip,
&s1ap_register_eNB->enb_ip_address,
sizeof(s1ap_register_eNB->enb_ip_address));
for (int i = 0; i < s1ap_register_eNB->num_plmn; i++) {
new_instance->mcc[i] = s1ap_register_eNB->mcc[i];
......
......@@ -124,6 +124,9 @@ typedef struct s1ap_eNB_mme_data_s {
/* This is the optional name provided by the MME */
char *mme_name;
/* MME S1AP IP address */
net_ip_address_t mme_s1_ip;
/* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max
* number of 8 RATs but in our case only one is used. The LTE related pool
* configuration is included on the first place in the list.
......@@ -200,6 +203,9 @@ typedef struct s1ap_eNB_instance_s {
/* Tracking area code */
uint16_t tac;
/* eNB S1AP IP address */
net_ip_address_t eNB_s1_ip;
/* Mobile Country Code
* Mobile Network Code
*/
......
......@@ -1468,7 +1468,7 @@ int s1ap_eNB_path_switch_req(instance_t instance,
break;
}
} while(1);
ue_context_p->mme_ue_s1ap_id = path_switch_req_p->mme_ue_s1ap_id;
/* Prepare the S1AP message to encode */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment