Commit 4c83925f authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/service-models-integration' into integration_2023_w37

parents f66d995d fec1396f
[submodule "openair2/E2AP/flexric"]
path = openair2/E2AP/flexric
url = https://gitlab.eurecom.fr/mosaic5g/flexric.git
branch = remotes/origin/mir_dev
branch = remotes/origin/service-models-integration
......@@ -15,3 +15,4 @@ add_library(e2_ran_func_cust STATIC
../../flexric/src/util/time_now_us.c
)
target_link_libraries(e2_ran_func_cust PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs)
#include "ran_func_gtp.h"
#include "../../flexric/test/rnd/fill_rnd_data_gtp.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_gtp.h"
#include <assert.h>
static
const int mod_id = 0;
void read_gtp_sm(void * data)
{
assert(data != NULL);
gtp_ind_data_t* gtp = (gtp_ind_data_t*)(data);
fill_gtp_ind_data(gtp);
//fill_gtp_ind_data(gtp);
gtp->msg.tstamp = time_now_us();
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
size_t num_ues = 0;
UE_iterator(UE_info->list, ue) {
if (ue)
num_ues += 1;
}
gtp->msg.len = num_ues;
if(gtp->msg.len > 0){
gtp->msg.ngut = calloc(gtp->msg.len, sizeof(gtp_ngu_t_stats_t) );
assert(gtp->msg.ngut != NULL);
}
size_t i = 0;
UE_iterator(UE_info->list, UE)
{
uint16_t const rnti = UE->rnti;
struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context_by_rnti(RC.nrrrc[mod_id], rnti);
if (ue_context_p != NULL) {
gtp->msg.ngut[i].rnti = ue_context_p->ue_context.rnti;
int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions;
if (nb_pdu_session > 0) {
int nb_pdu_idx = nb_pdu_session - 1;
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3;
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3;
// TODO: one PDU session has multiple QoS Flow
int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos;
if (nb_qos_flow > 0) {
gtp->msg.ngut[i].qfi = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.qos[nb_qos_flow - 1].qfi;
}
}
} else {
LOG_W(NR_RRC,"rrc_gNB_get_ue_context return NULL\n");
// if (gtp->msg.ngut != NULL) free(gtp->msg.ngut);
}
i++;
}
}
void read_gtp_setup_sm(void* data)
......@@ -21,4 +65,3 @@ sm_ag_if_ans_t write_ctrl_gtp_sm(void const* src)
assert(src != NULL);
assert(0 !=0 && "Not supported");
}
#ifndef RAN_FUNC_SM_GTP_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_GTP_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
#include "common/ran_context.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
void read_gtp_sm(void*);
......
#include "ran_func_mac.h"
#include "../../flexric/test/rnd/fill_rnd_data_mac.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_mac.h"
#include <assert.h>
static
const int mod_id = 0;
void read_mac_sm(void* data)
{
assert(data != NULL);
mac_ind_data_t* mac = (mac_ind_data_t*)data;
fill_mac_ind_data(mac);
//fill_mac_ind_data(mac);
mac->msg.tstamp = time_now_us();
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
size_t num_ues = 0;
UE_iterator(UE_info->list, ue) {
if (ue)
num_ues += 1;
}
mac->msg.len_ue_stats = num_ues;
if(mac->msg.len_ue_stats > 0){
mac->msg.ue_stats = calloc(mac->msg.len_ue_stats, sizeof(mac_ue_stats_impl_t));
assert(mac->msg.ue_stats != NULL && "Memory exhausted" );
}
size_t i = 0; //TODO
UE_iterator(UE_info->list, UE) {
const NR_UE_sched_ctrl_t* sched_ctrl = &UE->UE_sched_ctrl;
mac_ue_stats_impl_t* rd = &mac->msg.ue_stats[i];
rd->frame = RC.nrmac[mod_id]->frame;
rd->slot = RC.nrmac[mod_id]->slot;
rd->dl_aggr_tbs = UE->mac_stats.dl.total_bytes;
rd->ul_aggr_tbs = UE->mac_stats.ul.total_bytes;
if (is_xlsch_in_slot(RC.nrmac[mod_id]->dlsch_slot_bitmap[rd->slot / 64], rd->slot)) {
rd->dl_curr_tbs = UE->mac_stats.dl.current_bytes;
rd->dl_sched_rb = UE->mac_stats.dl.current_rbs;
}
if (is_xlsch_in_slot(RC.nrmac[mod_id]->ulsch_slot_bitmap[rd->slot / 64], rd->slot)) {
rd->ul_curr_tbs = UE->mac_stats.ul.current_bytes;
rd->ul_sched_rb = sched_ctrl->sched_pusch.rbSize;
}
rd->rnti = UE->rnti;
rd->dl_aggr_prb = UE->mac_stats.dl.total_rbs;
rd->ul_aggr_prb = UE->mac_stats.ul.total_rbs;
rd->dl_aggr_retx_prb = UE->mac_stats.dl.total_rbs_retx;
rd->ul_aggr_retx_prb = UE->mac_stats.ul.total_rbs_retx;
rd->dl_aggr_bytes_sdus = UE->mac_stats.dl.lc_bytes[3];
rd->ul_aggr_bytes_sdus = UE->mac_stats.ul.lc_bytes[3];
rd->dl_aggr_sdus = UE->mac_stats.dl.num_mac_sdu;
rd->ul_aggr_sdus = UE->mac_stats.ul.num_mac_sdu;
rd->pusch_snr = (float) sched_ctrl->pusch_snrx10 / 10; //: float = -64;
rd->pucch_snr = (float) sched_ctrl->pucch_snrx10 / 10; //: float = -64;
rd->wb_cqi = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb;
rd->dl_mcs1 = sched_ctrl->dl_bler_stats.mcs;
rd->dl_bler = sched_ctrl->dl_bler_stats.bler;
rd->ul_mcs1 = sched_ctrl->ul_bler_stats.mcs;
rd->ul_bler = sched_ctrl->ul_bler_stats.bler;
rd->dl_mcs2 = 0;
rd->ul_mcs2 = 0;
rd->phr = sched_ctrl->ph;
const uint32_t bufferSize = sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes;
rd->bsr = bufferSize;
const size_t numDLHarq = 4;
rd->dl_num_harq = numDLHarq;
for (uint8_t j = 0; j < numDLHarq; ++j)
rd->dl_harq[j] = UE->mac_stats.dl.rounds[j];
rd->dl_harq[numDLHarq] = UE->mac_stats.dl.errors;
const size_t numUlHarq = 4;
rd->ul_num_harq = numUlHarq;
for (uint8_t j = 0; j < numUlHarq; ++j)
rd->ul_harq[j] = UE->mac_stats.ul.rounds[j];
rd->ul_harq[numUlHarq] = UE->mac_stats.ul.errors;
++i;
}
}
void read_mac_setup_sm(void* data)
......
#ifndef SM_MAC_READ_WRITE_AGENT_H
#define SM_MAC_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
#include "common/ran_context.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
void read_mac_sm(void*);
......
#include "ran_func_pdcp.h"
#include "../../flexric/test/rnd/fill_rnd_data_pdcp.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_pdcp.h"
#include <assert.h>
static
const int mod_id = 0;
static
uint32_t num_act_rb(NR_UEs_t* UE_info)
{
assert(UE_info!= NULL);
uint32_t act_rb = 0;
UE_iterator(UE_info->list, UE) {
uint16_t const rnti = UE->rnti;
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_rlc_statistics_t rlc = {0};
const int srb_flag = 0;
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc);
if(rc) ++act_rb;
}
}
return act_rb;
}
void read_pdcp_sm(void* data)
{
assert(data != NULL);
//assert(data->type == PDCP_STATS_V0);
pdcp_ind_data_t* pdcp = (pdcp_ind_data_t*)data;
fill_pdcp_ind_data(pdcp);
//fill_pdcp_ind_data(pdcp);
// TODO: Need to improve, not good
if (NODE_IS_CU(RC.nrrrc[mod_id]->node_type)) {
uint32_t act_rb = 0;
struct rrc_gNB_ue_context_s *ue_context_p1 = NULL;
RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[mod_id]->rrc_ue_head) {
uint16_t const rnti = ue_context_p1->ue_context.rnti;
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(rnti, srb_flag, rb_id, &rb_pdcp);
if(rc) ++act_rb;
}
}
pdcp->msg.tstamp = time_now_us();
pdcp->msg.len = act_rb;
if (pdcp->msg.len > 0) {
pdcp->msg.rb = calloc(pdcp->msg.len, sizeof(pdcp_radio_bearer_stats_t));
assert(pdcp->msg.rb != NULL && "Memory exhausted!");
}
size_t i = 0;
struct rrc_gNB_ue_context_s *ue_context_p2 = NULL;
RB_FOREACH(ue_context_p2, rrc_nr_ue_tree_s, &RC.nrrrc[mod_id]->rrc_ue_head) {
// TODO: Need to handel multiple UEs
uint16_t const rnti = ue_context_p2->ue_context.rnti;
for (size_t rb_id = 1; rb_id < 6; ++rb_id) {
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(rnti, srb_flag, rb_id, &rb_pdcp);
if (!rc) continue;
pdcp_radio_bearer_stats_t *rd = &pdcp->msg.rb[i];
rd->txpdu_pkts = rb_pdcp.txpdu_pkts; /* aggregated number of tx packets */
rd->txpdu_bytes = rb_pdcp.txpdu_bytes; /* aggregated bytes of tx packets */
rd->txpdu_sn = rb_pdcp.txpdu_sn; /* current sequence number of last tx packet (or TX_NEXT) */
rd->rxpdu_pkts = rb_pdcp.rxpdu_pkts; /* aggregated number of rx packets */
rd->rxpdu_bytes = rb_pdcp.rxpdu_bytes; /* aggregated bytes of rx packets */
rd->rxpdu_sn = rb_pdcp.rxpdu_sn; /* current sequence number of last rx packet (or RX_NEXT) */
rd->rxpdu_oo_pkts = rb_pdcp.rxpdu_oo_pkts; /* aggregated number of out-of-order rx pkts (or RX_REORD) */
rd->rxpdu_oo_bytes = rb_pdcp.rxpdu_oo_bytes; /* aggregated amount of out-of-order rx bytes */
rd->rxpdu_dd_pkts = rb_pdcp.rxpdu_dd_pkts; /* aggregated number of duplicated discarded packets (or dropped packets because of other reasons such as integrity failure) (or RX_DELIV) */
rd->rxpdu_dd_bytes = rb_pdcp.rxpdu_dd_bytes; /* aggregated amount of discarded packets' bytes */
rd->rxpdu_ro_count = rb_pdcp.rxpdu_ro_count; /* this state variable indicates the COUNT value following the COUNT value associated with the PDCP Data PDU which triggered t-Reordering. (RX_REORD) */
rd->txsdu_pkts = rb_pdcp.txsdu_pkts; /* number of SDUs delivered */
rd->txsdu_bytes = rb_pdcp.txsdu_bytes; /* number of bytes of SDUs delivered */
rd->rxsdu_pkts = rb_pdcp.rxsdu_pkts; /* number of SDUs received */
rd->rxsdu_bytes = rb_pdcp.rxsdu_bytes; /* number of bytes of SDUs received */
rd->rnti = rnti;
rd->mode = rb_pdcp.mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */
rd->rbid = rb_id;
++i;
}
}
} else {
//assert(0!=0 && "Calling PDCP");
// for the moment and while we don't have a split base station, we use the
// MAC structures to obtain the RNTIs which we use to query the PDCP
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
uint32_t const act_rb = num_act_rb(UE_info);
pdcp->msg.tstamp = time_now_us();
pdcp->msg.len = act_rb;
if (pdcp->msg.len > 0) {
pdcp->msg.rb = calloc(pdcp->msg.len, sizeof(pdcp_radio_bearer_stats_t));
assert(pdcp->msg.rb != NULL && "Memory exhausted!");
}
size_t i = 0;
UE_iterator(UE_info->list, UE)
{
const int rnti = UE->rnti;
for (size_t rb_id = 1; rb_id < 6; ++rb_id) {
nr_pdcp_statistics_t rb_pdcp = {0};
const int srb_flag = 0;
const bool rc = nr_pdcp_get_statistics(rnti, srb_flag, rb_id, &rb_pdcp);
if (!rc) continue;
pdcp_radio_bearer_stats_t *rd = &pdcp->msg.rb[i];
rd->txpdu_pkts = rb_pdcp.txpdu_pkts; /* aggregated number of tx packets */
rd->txpdu_bytes = rb_pdcp.txpdu_bytes; /* aggregated bytes of tx packets */
rd->txpdu_sn = rb_pdcp.txpdu_sn; /* current sequence number of last tx packet (or TX_NEXT) */
rd->rxpdu_pkts = rb_pdcp.rxpdu_pkts; /* aggregated number of rx packets */
rd->rxpdu_bytes = rb_pdcp.rxpdu_bytes; /* aggregated bytes of rx packets */
rd->rxpdu_sn = rb_pdcp.rxpdu_sn; /* current sequence number of last rx packet (or RX_NEXT) */
rd->rxpdu_oo_pkts = rb_pdcp.rxpdu_oo_pkts; /* aggregated number of out-of-order rx pkts (or RX_REORD) */
rd->rxpdu_oo_bytes = rb_pdcp.rxpdu_oo_bytes; /* aggregated amount of out-of-order rx bytes */
rd->rxpdu_dd_pkts = rb_pdcp.rxpdu_dd_pkts; /* aggregated number of duplicated discarded packets (or dropped packets because of other reasons such as integrity failure) (or RX_DELIV) */
rd->rxpdu_dd_bytes = rb_pdcp.rxpdu_dd_bytes; /* aggregated amount of discarded packets' bytes */
rd->rxpdu_ro_count = rb_pdcp.rxpdu_ro_count; /* this state variable indicates the COUNT value following the COUNT value associated with the PDCP Data PDU which triggered t-Reordering. (RX_REORD) */
rd->txsdu_pkts = rb_pdcp.txsdu_pkts; /* number of SDUs delivered */
rd->txsdu_bytes = rb_pdcp.txsdu_bytes; /* number of bytes of SDUs delivered */
rd->rxsdu_pkts = rb_pdcp.rxsdu_pkts; /* number of SDUs received */
rd->rxsdu_bytes = rb_pdcp.rxsdu_bytes; /* number of bytes of SDUs received */
rd->rnti = rnti;
rd->mode = rb_pdcp.mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */
rd->rbid = rb_id;
++i;
}
}
}
}
void read_pdcp_setup_sm(void* data)
......
#ifndef RAN_FUNC_SM_PDCP_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_PDCP_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
#include "common/ran_context.h"
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
void read_pdcp_sm(void*);
......
#include <assert.h>
#include "ran_func_rlc.h"
#include "../../flexric/test/rnd/fill_rnd_data_rlc.h"
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_rlc.h"
static
const int mod_id = 0;
static
uint32_t num_act_rb(NR_UEs_t* const UE_info)
{
assert(UE_info!= NULL);
uint32_t act_rb = 0;
UE_iterator(UE_info->list, UE) {
uint16_t const rnti = UE->rnti;
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_rlc_statistics_t rlc = {0};
const int srb_flag = 0;
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc);
if(rc) ++act_rb;
}
}
return act_rb;
}
static
void active_avg_to_tx(NR_UEs_t* const UE_info)
{
assert(UE_info!= NULL);
UE_iterator(UE_info->list, UE) {
uint16_t const rnti = UE->rnti;
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_rlc_statistics_t rlc = {0};
const int srb_flag = 0;
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc);
if(rc) nr_rlc_activate_avg_time_to_tx(rnti, rb_id+3, 1); // rb_id (DRB ID) mapping to logical channel
}
}
}
void read_rlc_sm(void* data)
{
......@@ -7,7 +45,94 @@ void read_rlc_sm(void* data)
// assert(data->type == RLC_STATS_V0);
rlc_ind_data_t* rlc = (rlc_ind_data_t*)data;
fill_rlc_ind_data(rlc);
//fill_rlc_ind_data(rlc);
// use MAC structures to get RNTIs
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
uint32_t const act_rb = num_act_rb(UE_info);
//assert(0!=0 && "Read RLC called");
// activate the rlc to calculate the average tx time
active_avg_to_tx(UE_info);
rlc->msg.len = act_rb;
if(rlc->msg.len > 0){
rlc->msg.rb = calloc(rlc->msg.len, sizeof(rlc_radio_bearer_stats_t));
assert(rlc->msg.rb != NULL && "Memory exhausted");
}
rlc->msg.tstamp = time_now_us();
uint32_t i = 0;
UE_iterator(UE_info->list, UE) {
uint16_t const rnti = UE->rnti;
//for every LC ID
for(int rb_id = 1; rb_id < 6; ++rb_id ){
nr_rlc_statistics_t rb_rlc = {0};
const int srb_flag = 0;
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rb_rlc);
if(!rc) continue;
rlc_radio_bearer_stats_t* sm_rb = &rlc->msg.rb[i];
/* TX */
sm_rb->txpdu_pkts = rb_rlc.txpdu_pkts;
sm_rb->txpdu_bytes = rb_rlc.txpdu_bytes; /* aggregated amount of transmitted bytes in RLC PDUs */
/* TODO? */
/* (TO BE DISCUSSED) HOL delay of the packet to be transmitted (RLC delay + MAC delay) */
// sm_rb->txpdu_wt_ms += rb_rlc.txsdu_avg_time_to_tx;
sm_rb->txpdu_dd_pkts = rb_rlc.txpdu_dd_pkts; /* aggregated number of dropped or discarded tx packets by RLC */
sm_rb->txpdu_dd_bytes = rb_rlc.txpdu_dd_bytes; /* aggregated amount of bytes dropped or discarded tx packets by RLC */
sm_rb->txpdu_retx_pkts = rb_rlc.txpdu_retx_pkts; /* aggregated number of tx pdus/pkts to be re-transmitted (only applicable to RLC AM) */
sm_rb->txpdu_retx_bytes = rb_rlc.txpdu_retx_bytes; /* aggregated amount of bytes to be re-transmitted (only applicable to RLC AM) */
sm_rb->txpdu_segmented = rb_rlc.txpdu_segmented; /* aggregated number of segmentations */
sm_rb->txpdu_status_pkts = rb_rlc.txpdu_status_pkts; /* aggregated number of tx status pdus/pkts (only applicable to RLC AM) */
sm_rb->txpdu_status_bytes = rb_rlc.txpdu_status_bytes; /* aggregated amount of tx status bytes (only applicable to RLC AM) */
sm_rb->txbuf_occ_bytes = rb_rlc.txbuf_occ_bytes; /* (IMPLEMENTED) transmitting bytes currently in buffer */
sm_rb->txbuf_occ_pkts = rb_rlc.txbuf_occ_pkts; /* current tx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */
/* RX */
sm_rb->rxpdu_pkts = rb_rlc.rxpdu_pkts; /* aggregated number of received RLC PDUs */
sm_rb->rxpdu_bytes = rb_rlc.rxpdu_bytes; /* amount of bytes received by the RLC */
sm_rb->rxpdu_dup_pkts = rb_rlc.rxpdu_dup_pkts; /* aggregated number of duplicate packets */
sm_rb->rxpdu_dup_bytes = rb_rlc.rxpdu_dup_bytes; /* aggregated amount of duplicated bytes */
sm_rb->rxpdu_dd_pkts = rb_rlc.rxpdu_dd_pkts; /* aggregated number of rx packets dropped or discarded by RLC */
sm_rb->rxpdu_dd_bytes = rb_rlc.rxpdu_dd_bytes; /* aggregated amount of rx bytes dropped or discarded by RLC */
sm_rb->rxpdu_ow_pkts = rb_rlc.rxpdu_ow_pkts; /* aggregated number of out of window received RLC pdu */
sm_rb->rxpdu_ow_bytes = rb_rlc.rxpdu_ow_bytes; /* aggregated number of out of window bytes received RLC pdu */
sm_rb->rxpdu_status_pkts = rb_rlc.rxpdu_status_pkts; /* aggregated number of rx status pdus/pkts (only applicable to RLC AM) */
sm_rb->rxpdu_status_bytes = rb_rlc.rxpdu_status_bytes; /* aggregated amount of rx status bytes (only applicable to RLC AM) */
sm_rb->rxbuf_occ_bytes = rb_rlc.rxbuf_occ_bytes; /* (IMPLEMENTED) received bytes currently in buffer */
sm_rb->rxbuf_occ_pkts = rb_rlc.rxbuf_occ_pkts; /* current rx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */
/* TX */
sm_rb->txsdu_pkts = rb_rlc.txsdu_pkts; /* number of SDUs delivered */
sm_rb->txsdu_bytes = rb_rlc.txsdu_bytes; /* (UPDATED) number of SDUs bytes successfully transmitted so far (counter) */
sm_rb->txsdu_avg_time_to_tx = rb_rlc.txsdu_avg_time_to_tx; /* (100ms-windowed) per-packet sojourn (SDU to PDU) in microseconds */
sm_rb->txsdu_wt_us = rb_rlc.txsdu_wt_us; /* HOL delay of the current radio bearer */
/* RX */
sm_rb->rxsdu_pkts = rb_rlc.rxsdu_pkts; /* number of SDUs received */
sm_rb->rxsdu_bytes = rb_rlc.rxsdu_bytes; /* (UPDATED) number of SDUs bytes arrived so far (counter) */
sm_rb->rxsdu_dd_pkts = rb_rlc.rxsdu_dd_pkts; /* number of dropped or discarded SDUs */
sm_rb->rxsdu_dd_bytes = rb_rlc.rxsdu_dd_bytes; /* number of bytes of SDUs dropped or discarded */
sm_rb->mode = rb_rlc.mode; /* 0: RLC AM, 1: RLC UM, 2: RLC TM */
sm_rb->rnti = rnti;
sm_rb->rbid = rb_id;
LOG_D(RLC, "[E2-AGENT] SDU Goodput & HOL-waittime/200ms-sojourn: %lu/%lu (bytes) & %u/%f (microsecs);\n\
Current Buffer: received %u, transmitting %u (bytes).\n",
sm_rb->txsdu_bytes, sm_rb->rxsdu_bytes, sm_rb->txsdu_wt_us, sm_rb->txsdu_avg_time_to_tx,
sm_rb->rxbuf_occ_bytes, sm_rb->txbuf_occ_bytes);
++i;
}
}
}
void read_rlc_setup_sm(void* data)
......
#ifndef RAN_FUNC_SM_RLC_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_RLC_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
#include "common/ran_context.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
void read_rlc_sm(void*);
......
#ifndef RAN_FUNC_SM_SLICE_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_SLICE_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_slice_sm(void*);
......
#ifndef RAN_FUNC_SM_TC_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_TC_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_tc_sm(void*);
......
......@@ -5,3 +5,5 @@ add_library(e2_ran_func_oran STATIC
../../flexric/test/rnd/fill_rnd_data_kpm.c
../../flexric/test/rnd/fill_rnd_data_rc.c
)
target_link_libraries(e2_ran_func_oran PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs)
#ifndef RAN_FUNC_SM_KPM_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_KPM_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_kpm_sm(void*);
......
#ifndef RAN_FUNC_SM_RAN_CTRL_READ_WRITE_AGENT_H
#define RAN_FUNC_SM_RAN_CTRL_READ_WRITE_AGENT_H
#include "../../flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
void read_rc_sm(void *);
......
#include "init_ran_func.h"
#include "../flexric/src/agent/e2_agent_api.h"
#include "CUSTOMIZED/ran_func_mac.h"
#include "CUSTOMIZED/ran_func_rlc.h"
#include "CUSTOMIZED/ran_func_pdcp.h"
......
......@@ -11,7 +11,7 @@ Please see [NOTICE](NOTICE.md) file for third party software that is included in
# Overview
This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 agent, with FlexRIC, O-RAN compliant nearRT-RIC.
This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 agent, and FlexRIC, O-RAN compliant nearRT-RIC.
# 1. Installation
......@@ -82,7 +82,7 @@ git submodule update
```bash
git clone https://gitlab.eurecom.fr/mosaic5g/flexric flexric
cd flexric/
git checkout d3ff879135d036632d7938c2085dbf4577759225
git checkout 8ee3aca107a9da8ccf425e623bed18cd40a31fa1
```
### 2.2.2 Build FlexRIC
......@@ -95,16 +95,35 @@ mkdir build && cd build && cmake .. && make -j8
sudo make install
```
By default the service model libraries will be installed in the path /usr/local/lib/flexric while the configuration file in `/usr/local/etc/flexric`.
By default the service model libraries will be installed in the path `/usr/local/lib/flexric` while the configuration file in `/usr/local/etc/flexric`.
* Note: currently, only xApp KPM v03.00 and RC v01.03 (xapp_kpm_rc) is supported to communicate with the integrated E2 agent in OAI. If you are interested in custom SMs (MAC, RLC, PDCP, GTP, TC and SLICE), please follow the instructions at https://gitlab.eurecom.fr/mosaic5g/flexric.
Available SMs in this version are:
* KPM v03.00 (xapp_kpm_moni)
* GTP (xapp_gtp_moni)
* MAC + RLC + PDCP (xapp_mac_rlc_pdcp_moni)
If you are interested in TC and SLICE SMs, please follow the instructions at https://gitlab.eurecom.fr/mosaic5g/flexric.
# 3. Start the process
In order to configure E2 agent, please, add the following block in the configuration file:
```bash
e2_agent = {
near_ric_ip_addr = "127.0.0.1";
sm_dir = "/usr/local/lib/flexric/"
}
```
* start the gNB
```bash
cd oai/cmake_targets/ran_build/build
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim --sa --rfsimulator.serveraddr server
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa -E
```
* if CU-DU split is used, start the gNB as follows
```bash
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
sudo ./nr-softmodem -O <path_to_cu_conf_file> --rfsim --sa -E
```
* start the nrUE
......@@ -119,8 +138,24 @@ cd flexric
./build/examples/ric/nearRT-RIC
```
* start the KPM+RC xApp
* start the KPM xApp
```bash
cd flexric
./build/examples/xApp/c/kpm_rc/xapp_kpm_rc
./build/examples/xApp/c/monitor/xapp_kpm_moni
```
* start the GTP xApp
```bash
cd flexric
./build/examples/xApp/c/monitor/xapp_gtp_moni
```
* start the (MAC + RLC + PDCP) xApp
```bash
cd flexric
./build/examples/xApp/c/monitor/xapp_mac_rlc_pdcp_moni
```
# Optional - Multiple UEs
If you are interested in having multiple UEs in rfsim mode, please, follow the instructions at https://gitlab.eurecom.fr/oaiworkshop/summerworkshop2023/-/tree/main/ran#multiple-ues.
flexric @ 8ee3aca1
Subproject commit d3ff879135d036632d7938c2085dbf4577759225
Subproject commit 8ee3aca107a9da8ccf425e623bed18cd40a31fa1
......@@ -36,10 +36,36 @@ static void nr_rlc_entity_get_stats(
nr_rlc_statistics_t *out)
{
// printf("Stats from the RLC entity asked\n");
uint64_t time_now = time_average_now();
*out = entity->stats;
// Get the correct HOL RLC-SDU
nr_rlc_sdu_segment_t* sdu;
if (entity->stats.mode == NR_RLC_AM) {
nr_rlc_entity_am_t* am_entity = (nr_rlc_entity_am_t *) entity;
if (am_entity->retransmit_list != NULL) {
sdu = am_entity->retransmit_list;
} else {
sdu = am_entity->tx_list;
}
} else if (entity->stats.mode == NR_RLC_UM) {
nr_rlc_entity_um_t* um_entity = (nr_rlc_entity_um_t *) entity;
sdu = um_entity->tx_list;
} else {
nr_rlc_entity_tm_t* tm_entity = (nr_rlc_entity_tm_t *) entity;
sdu = tm_entity->tx_list;
}
// Compute HOL waittime, make sure that segmented packets don't have 'zero' time-of-arrival
if (sdu != NULL) {
out->txsdu_wt_us = time_now - sdu->sdu->time_of_arrival;
} else {
// No HOL packets --> wait-time == 0
out->txsdu_wt_us = 0;
}
if (entity->avg_time_is_on)
out->txsdu_avg_time_to_tx = time_average_get_average(entity->txsdu_avg_time_to_tx,
time_average_now());
out->txsdu_avg_time_to_tx = time_average_get_average(entity->txsdu_avg_time_to_tx, time_now);
else
out->txsdu_avg_time_to_tx = 0;
}
......@@ -99,7 +125,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_am(
ret->common.set_time = nr_rlc_entity_am_set_time;
ret->common.discard_sdu = nr_rlc_entity_am_discard_sdu;
ret->common.reestablishment = nr_rlc_entity_am_reestablishment;
ret->common.delete = nr_rlc_entity_am_delete;
ret->common.delete_entity = nr_rlc_entity_am_delete;
ret->common.available_tx_space = nr_rlc_entity_am_available_tx_space;
ret->common.get_stats = nr_rlc_entity_get_stats;
......@@ -112,8 +138,11 @@ nr_rlc_entity_t *new_nr_rlc_entity_am(
ret->common.stats.mode = NR_RLC_AM;
ret->common.stats.rxsdu_bytes = 0; // init default arrivals (SDU) counter
ret->common.stats.txsdu_bytes = 0; // init default transmits (SDU) counter
/* let's take average over the last 100 milliseconds
* initial_size of 1024 is arbitrary
* initial_size of 1024 (packets) is arbitrary
*/
ret->common.txsdu_avg_time_to_tx = time_average_new(100 * 1000, 1024);
......@@ -158,7 +187,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_um(
ret->common.set_time = nr_rlc_entity_um_set_time;
ret->common.discard_sdu = nr_rlc_entity_um_discard_sdu;
ret->common.reestablishment = nr_rlc_entity_um_reestablishment;
ret->common.delete = nr_rlc_entity_um_delete;
ret->common.delete_entity = nr_rlc_entity_um_delete;
ret->common.available_tx_space = nr_rlc_entity_um_available_tx_space;
ret->common.get_stats = nr_rlc_entity_get_stats;
......@@ -198,7 +227,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_tm(
ret->common.set_time = nr_rlc_entity_tm_set_time;
ret->common.discard_sdu = nr_rlc_entity_tm_discard_sdu;
ret->common.reestablishment = nr_rlc_entity_tm_reestablishment;
ret->common.delete = nr_rlc_entity_tm_delete;
ret->common.delete_entity = nr_rlc_entity_tm_delete;
ret->common.available_tx_space = nr_rlc_entity_tm_available_tx_space;
ret->common.get_stats = nr_rlc_entity_get_stats;
......
......@@ -41,8 +41,7 @@ typedef struct {
/* TX */
uint32_t txpdu_pkts; /* aggregated number of transmitted RLC PDUs */
uint32_t txpdu_bytes; /* aggregated amount of transmitted bytes in RLC PDUs */
/* TODO? */
uint32_t txpdu_wt_ms; /* aggregated head-of-line tx packet waiting time to be transmitted (i.e. send to the MAC layer) */
uint32_t txpdu_wt_ms; /* TODO: aggregated head-of-line tx packet waiting time to be transmitted (i.e. send to the MAC layer) */
uint32_t txpdu_dd_pkts; /* aggregated number of dropped or discarded tx packets by RLC */
uint32_t txpdu_dd_bytes; /* aggregated amount of bytes dropped or discarded tx packets by RLC */
uint32_t txpdu_retx_pkts; /* aggregated number of tx pdus/pkts to be re-transmitted (only applicable to RLC AM) */
......@@ -50,10 +49,8 @@ typedef struct {
uint32_t txpdu_segmented; /* aggregated number of segmentations */
uint32_t txpdu_status_pkts; /* aggregated number of tx status pdus/pkts (only applicable to RLC AM) */
uint32_t txpdu_status_bytes; /* aggregated amount of tx status bytes (only applicable to RLC AM) */
/* TODO? */
uint32_t txbuf_occ_bytes; /* current tx buffer occupancy in terms of amount of bytes (average: NOT IMPLEMENTED) */
/* TODO? */
uint32_t txbuf_occ_pkts; /* current tx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */
uint32_t txbuf_occ_bytes; /* (IMPLEMENTED) transmitting bytes currently in buffer */
uint32_t txbuf_occ_pkts; /* TODO: current tx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */
/* txbuf_wd_ms: the time window for which the txbuf occupancy value is obtained - NOT IMPLEMENTED */
/* RX */
......@@ -70,31 +67,28 @@ typedef struct {
/* rxpdu_rotout_ms: flag indicating rx reordering timeout in ms - NOT IMPLEMENTED */
/* rxpdu_potout_ms: flag indicating the poll retransmit time out in ms - NOT IMPLEMENTED */
/* rxpdu_sptout_ms: flag indicating status prohibit timeout in ms - NOT IMPLEMENTED */
/* TODO? */
uint32_t rxbuf_occ_bytes; /* current rx buffer occupancy in terms of amount of bytes (average: NOT IMPLEMENTED) */
/* TODO? */
uint32_t rxbuf_occ_pkts; /* current rx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */
uint32_t rxbuf_occ_bytes; /* (IMPLEMENTED) received bytes currently in buffer */
uint32_t rxbuf_occ_pkts; /* TODO: current rx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */
/* SDU stats */
/* TX */
uint32_t txsdu_pkts; /* number of SDUs delivered */
uint32_t txsdu_bytes; /* number of bytes of SDUs delivered */
uint64_t txsdu_bytes; /* (UPDATED) number of SDUs bytes successfully transmitted so far (counter) */
/* Average time for an SDU to be passed to MAC:
* Actually measures the time it takes for THE FULL SDU to be passed to MAC FOR THE FIRST TIME.
* Since the MAC schedules in advance, it does not measure the time of
* transmission over the air, just the time to reach the MAC layer.
* => to control it, 'txsdu_wt_us' that measures the current HOL-delay is added.
*/
double txsdu_avg_time_to_tx; /* (100ms-windowed) per-packet sojourn (SDU to PDU) in microseconds */
uint32_t txsdu_wt_us; /* HOL delay of the current radio bearer, in microseconds */
/* RX */
uint32_t rxsdu_pkts; /* number of SDUs received */
uint32_t rxsdu_bytes; /* number of bytes of SDUs received */
uint64_t rxsdu_bytes; /* (UPDATED) number of SDUs bytes arrived so far (counter) */
uint32_t rxsdu_dd_pkts; /* number of dropped or discarded SDUs */
uint32_t rxsdu_dd_bytes; /* number of bytes of SDUs dropped or discarded */
/* Average time for an SDU to be passed to MAC.
* Actually measures the time it takes for any part of an SDU to be
* passed to MAC for the first time, that is: the first TX of (part of) the
* SDU.
* Since the MAC schedules in advance, it does not measure the time of
* transmission over the air, just the time to reach the MAC layer.
*/
double txsdu_avg_time_to_tx;
} nr_rlc_statistics_t;
typedef struct {
......@@ -119,7 +113,7 @@ typedef struct nr_rlc_entity_t {
void (*reestablishment)(struct nr_rlc_entity_t *entity);
void (*delete)(struct nr_rlc_entity_t *entity);
void (*delete_entity)(struct nr_rlc_entity_t *entity);
int (*available_tx_space)(struct nr_rlc_entity_t *entity);
......
......@@ -224,7 +224,8 @@ static void reassemble_and_deliver(nr_rlc_entity_am_t *entity, int sn)
sdu, so);
entity->common.stats.txsdu_pkts++;
entity->common.stats.txsdu_bytes += so;
/* AM 'txsdu_bytes' now only count successfully transmitted bytes */
// entity->common.stats.txsdu_bytes += so;
}
static void reception_actions(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *pdu)
......@@ -551,6 +552,8 @@ process_wait_list_head:
end_wait_list = prev_wait_list;
if (nr_rlc_free_sdu_segment(cur_wait_list)) {
entity->tx_size -= sdu_size;
// Wait-ACK: count as successfully transmitted bytes
entity->common.stats.txsdu_bytes += sdu_size;
entity->common.sdu_successful_delivery(
entity->common.sdu_successful_delivery_data,
(nr_rlc_entity_t *)entity, upper_layer_id);
......@@ -614,6 +617,8 @@ process_retransmit_list_head:
+ cur->size;
if (nr_rlc_free_sdu_segment(cur)) {
entity->tx_size -= sdu_size;
// Retransmit-ACK: count as successfully transmitted bytes
entity->common.stats.txsdu_bytes += sdu_size;
entity->common.sdu_successful_delivery(
entity->common.sdu_successful_delivery_data,
(nr_rlc_entity_t *)entity, upper_layer_id);
......@@ -671,6 +676,8 @@ lists_over:
end_wait_list = prev_wait_list;
if (nr_rlc_free_sdu_segment(cur_wait_list)) {
entity->tx_size -= sdu_size;
// Wait-NACK done: count as successfully transmitted bytes
entity->common.stats.txsdu_bytes += sdu_size;
entity->common.sdu_successful_delivery(
entity->common.sdu_successful_delivery_data,
(nr_rlc_entity_t *)entity, upper_layer_id);
......@@ -692,6 +699,8 @@ lists_over:
+ cur->size;
if (nr_rlc_free_sdu_segment(cur)) {
entity->tx_size -= sdu_size;
// Retransmit-NACK done: count as successfully transmitted bytes
entity->common.stats.txsdu_bytes += sdu_size;
entity->common.sdu_successful_delivery(
entity->common.sdu_successful_delivery_data,
(nr_rlc_entity_t *)entity, upper_layer_id);
......@@ -1685,11 +1694,11 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size)
entity->common.stats.txpdu_pkts++;
entity->common.stats.txpdu_bytes += ret_size;
if (sdu->sdu->time_of_arrival) {
/* No need to 'zero' time-of-arrival;
Segmented packets do need to be duplicated in time-sensitive use cases */
if (entity->common.avg_time_is_on) {
uint64_t time_now = time_average_now();
uint64_t waited_time = time_now - sdu->sdu->time_of_arrival;
/* set time_of_arrival to 0 so as to update stats only once */
sdu->sdu->time_of_arrival = 0;
time_average_add(entity->common.txsdu_avg_time_to_tx, time_now, waited_time);
}
......@@ -1747,7 +1756,6 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity,
nr_rlc_sdu_segment_t *sdu;
entity->common.stats.rxsdu_pkts++;
entity->common.stats.rxsdu_bytes += size;
if (size > NR_SDU_MAX) {
LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n",
......@@ -1771,6 +1779,8 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity,
}
entity->tx_size += size;
// SDU received: Count as arrival bytes
entity->common.stats.rxsdu_bytes += size;
sdu = nr_rlc_new_sdu(buffer, size, sdu_id);
......@@ -1965,6 +1975,10 @@ void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id)
+ cur->size;
entity->tx_size -= cur->sdu->size;
/* Uncomment to assert if SDU are ever discarded */
// assert(0 != 0 && "[RLC-TRAP] SDU discard should never be reached!");
nr_rlc_free_sdu_segment(cur);
}
......
......@@ -79,11 +79,11 @@ static int generate_tx_pdu(nr_rlc_entity_tm_t *entity, char *buffer, int size)
entity->common.stats.txpdu_pkts++;
entity->common.stats.txpdu_bytes += size;
if (sdu->sdu->time_of_arrival) {
/* No need to 'zero' time-of-arrival;
Segmented packets do need to be duplicated in time-sensitive use cases */
if (entity->common.avg_time_is_on) {
uint64_t time_now = time_average_now();
uint64_t waited_time = time_now - sdu->sdu->time_of_arrival;
/* set time_of_arrival to 0 so as to update stats only once */
sdu->sdu->time_of_arrival = 0;
time_average_add(entity->common.txsdu_avg_time_to_tx, time_now, waited_time);
}
......
......@@ -521,11 +521,11 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size)
entity->common.stats.txpdu_pkts++;
entity->common.stats.txpdu_bytes += size;
if (sdu->sdu->time_of_arrival) {
/* No need to 'zero' time-of-arrival;
Segmented packets do need to be duplicated in time-sensitive use cases */
if (entity->common.avg_time_is_on) {
uint64_t time_now = time_average_now();
uint64_t waited_time = time_now - sdu->sdu->time_of_arrival;
/* set time_of_arrival to 0 so as to update stats only once */
sdu->sdu->time_of_arrival = 0;
time_average_add(entity->common.txsdu_avg_time_to_tx, time_now, waited_time);
}
......
......@@ -919,13 +919,13 @@ rlc_op_status_t rrc_rlc_config_req (
ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ctxt_pP->rntiMaybeUEid);
if (srb_flagP) {
if (ue->srb[rb_idP-1] != NULL) {
ue->srb[rb_idP-1]->delete(ue->srb[rb_idP-1]);
ue->srb[rb_idP-1]->delete_entity(ue->srb[rb_idP-1]);
ue->srb[rb_idP-1] = NULL;
} else
LOG_W(RLC, "removing non allocated SRB %ld, do nothing\n", rb_idP);
} else {
if (ue->drb[rb_idP-1] != NULL) {
ue->drb[rb_idP-1]->delete(ue->drb[rb_idP-1]);
ue->drb[rb_idP-1]->delete_entity(ue->drb[rb_idP-1]);
ue->drb[rb_idP-1] = NULL;
} else
LOG_W(RLC, "removing non allocated DRB %ld, do nothing\n", rb_idP);
......@@ -1072,6 +1072,12 @@ const bool nr_rlc_get_statistics(
if (rb != NULL) {
rb->get_stats(rb, out);
ret = true;
// Patch buffer status using OAI results (no need to change anything in the RB)
// rb->set_time(rb, nr_rlc_current_time);
nr_rlc_entity_buffer_status_t oai_stat = rb->buffer_status(rb, 1000*1000);
out->rxbuf_occ_bytes = oai_stat.status_size;
out->txbuf_occ_bytes = oai_stat.tx_size + oai_stat.retx_size;
} else {
ret = false;
}
......
......@@ -35,6 +35,8 @@
#include "NR_RadioBearerConfig.h"
#include "NR_CellGroupConfig.h"
#include "openair2/RRC/NR/nr_rrc_proto.h"
#include "nr_rlc_ue_manager.h"
struct NR_RLC_Config;
struct NR_LogicalChannelConfig;
......@@ -67,3 +69,5 @@ void nr_rlc_activate_srb0(int rnti, struct gNB_MAC_INST_s *mac, void *rawUE,
const uint8_t *sdu,
sdu_size_t sdu_len,
void *rawUE));
const bool nr_rlc_get_statistics(int rnti, int srb_flag, int rb_id, nr_rlc_statistics_t *out);
......@@ -128,16 +128,16 @@ void nr_rlc_manager_remove_ue(nr_rlc_ue_manager_t *_m, int rnti)
if (ue->srb0 != NULL) {
/* deliver_sdu_data for srb0 is allocated, needs a free() */
free(ue->srb0->deliver_sdu_data);
ue->srb0->delete(ue->srb0);
ue->srb0->delete_entity(ue->srb0);
}
for (j = 0; j < 3; j++)
if (ue->srb[j] != NULL)
ue->srb[j]->delete(ue->srb[j]);
ue->srb[j]->delete_entity(ue->srb[j]);
for (j = 0; j < MAX_DRBS_PER_UE; j++)
if (ue->drb[j] != NULL)
ue->drb[j]->delete(ue->drb[j]);
ue->drb[j]->delete_entity(ue->drb[j]);
free(ue);
......
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