mac,optimization: use rnti memory pool to create mac::ue objects

master
Francisco 4 years ago committed by Francisco Paisana
parent fd1d73666c
commit 7e77da6a15

@ -209,8 +209,7 @@ class mac_interface_rrc
{ {
public: public:
/* Provides cell configuration including SIB periodicity, etc. */ /* Provides cell configuration including SIB periodicity, etc. */
virtual int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) = 0; virtual int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) = 0;
virtual void reset() = 0;
/* Manages UE configuration context */ /* Manages UE configuration context */
virtual int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) = 0; virtual int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) = 0;

@ -14,6 +14,7 @@
#define SRSENB_MAC_H #define SRSENB_MAC_H
#include "sched.h" #include "sched.h"
#include "srsenb/hdr/common/rnti_pool.h"
#include "srsenb/hdr/stack/mac/schedulers/sched_time_rr.h" #include "srsenb/hdr/stack/mac/schedulers/sched_time_rr.h"
#include "srsran/adt/circular_map.h" #include "srsran/adt/circular_map.h"
#include "srsran/adt/pool/batch_mem_pool.h" #include "srsran/adt/pool/batch_mem_pool.h"
@ -73,8 +74,7 @@ public:
/******** Interface from RRC (RRC -> MAC) ****************/ /******** Interface from RRC (RRC -> MAC) ****************/
/* Provides cell configuration including SIB periodicity, etc. */ /* Provides cell configuration including SIB periodicity, etc. */
int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) override; int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) override;
void reset() override;
/* Manages UE scheduling context */ /* Manages UE scheduling context */
int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override; int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override;
@ -107,11 +107,9 @@ public:
private: private:
static const uint32_t cfi = 3; static const uint32_t cfi = 3;
bool check_ue_exists(uint16_t rnti); bool check_ue_active(uint16_t rnti);
uint16_t allocate_rnti();
uint16_t allocate_ue(); uint16_t allocate_ue();
bool is_valid_rnti_unprotected(uint16_t rnti);
std::mutex rnti_mutex;
srslog::basic_logger& logger; srslog::basic_logger& logger;
@ -140,12 +138,9 @@ private:
sched_interface::dl_pdu_mch_t mch = {}; sched_interface::dl_pdu_mch_t mch = {};
/* Map of active UEs */ /* Map of active UEs */
rnti_map_t<std::unique_ptr<ue> > ue_db; static const uint16_t FIRST_RNTI = 0x46;
std::map<uint16_t, std::unique_ptr<ue> > ues_to_rem; rnti_map_t<unique_rnti_ptr<ue> > ue_db;
uint16_t last_rnti = 70; std::atomic<uint16_t> ue_counter;
srsran::static_blocking_queue<std::unique_ptr<ue>, 32> ue_pool; ///< Pool of pre-allocated UE objects
void prealloc_ue(uint32_t nof_ue);
uint8_t* assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint8_t* assemble_rar(sched_interface::dl_sched_rar_grant_t* grants,
uint32_t enb_cc_idx, uint32_t enb_cc_idx,

@ -142,6 +142,8 @@ public:
uint32_t set_ta_us(float ta_us) { return ta_fsm.push_value(ta_us); }; uint32_t set_ta_us(float ta_us) { return ta_fsm.push_value(ta_us); };
void tic(); void tic();
void trigger_padding(int lcid); void trigger_padding(int lcid);
void set_active(bool active) { active_state.store(active, std::memory_order_relaxed); }
bool is_active() const { return active_state.load(std::memory_order_relaxed); }
uint8_t* generate_pdu(uint32_t ue_cc_idx, uint8_t* generate_pdu(uint32_t ue_cc_idx,
uint32_t harq_pid, uint32_t harq_pid,
@ -189,6 +191,8 @@ private:
uint32_t last_tti = 0; uint32_t last_tti = 0;
uint32_t nof_failures = 0; uint32_t nof_failures = 0;
std::atomic<bool> active_state{true};
uint32_t phr_counter = 0; uint32_t phr_counter = 0;
uint32_t dl_cqi_counter = 0; uint32_t dl_cqi_counter = 0;
uint32_t dl_ri_counter = 0; uint32_t dl_ri_counter = 0;

@ -48,13 +48,9 @@ bool mac::init(const mac_args_t& args_,
rrc_interface_mac* rrc) rrc_interface_mac* rrc)
{ {
started = false; started = false;
phy_h = phy;
if (not phy or not rlc) { rlc_h = rlc;
return false; rrc_h = rrc;
}
phy_h = phy;
rlc_h = rlc;
rrc_h = rrc;
args = args_; args = args_;
cells = cells_; cells = cells_;
@ -74,8 +70,6 @@ bool mac::init(const mac_args_t& args_,
srsran_softbuffer_tx_init(&cc.rar_softbuffer_tx, args.nof_prb); srsran_softbuffer_tx_init(&cc.rar_softbuffer_tx, args.nof_prb);
} }
reset();
// Initiate common pool of softbuffers // Initiate common pool of softbuffers
uint32_t nof_prb = args.nof_prb; uint32_t nof_prb = args.nof_prb;
auto init_softbuffers = [nof_prb](void* ptr) { auto init_softbuffers = [nof_prb](void* ptr) {
@ -85,9 +79,6 @@ bool mac::init(const mac_args_t& args_,
softbuffer_pool.reset(new srsran::background_obj_pool<ue_cc_softbuffers>( softbuffer_pool.reset(new srsran::background_obj_pool<ue_cc_softbuffers>(
8, 8, args.nof_prealloc_ues, init_softbuffers, recycle_softbuffers)); 8, 8, args.nof_prealloc_ues, init_softbuffers, recycle_softbuffers));
// Pre-alloc UE objects for first attaching users
prealloc_ue(10);
detected_rachs.resize(cells.size()); detected_rachs.resize(cells.size());
started = true; started = true;
@ -108,21 +99,9 @@ void mac::stop()
srsran_softbuffer_tx_free(&cc.pcch_softbuffer_tx); srsran_softbuffer_tx_free(&cc.pcch_softbuffer_tx);
srsran_softbuffer_tx_free(&cc.rar_softbuffer_tx); srsran_softbuffer_tx_free(&cc.rar_softbuffer_tx);
} }
ue_pool.stop();
} }
} }
// Implement Section 5.9
void mac::reset()
{
logger.info("Resetting MAC");
last_rnti = 70;
/* Setup scheduler */
scheduler.reset();
}
void mac::start_pcap(srsran::mac_pcap* pcap_) void mac::start_pcap(srsran::mac_pcap* pcap_)
{ {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
@ -148,11 +127,12 @@ void mac::start_pcap_net(srsran::mac_pcap_net* pcap_net_)
* RLC interface * RLC interface
* *
*******************************************************/ *******************************************************/
int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue)
{ {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
int ret = -1; int ret = -1;
if (ue_db.contains(rnti)) { if (check_ue_active(rnti)) {
if (rnti != SRSRAN_MRNTI) { if (rnti != SRSRAN_MRNTI) {
ret = scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue); ret = scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
} else { } else {
@ -163,34 +143,20 @@ int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint
} }
ret = 0; ret = 0;
} }
} else {
logger.error("User rnti=0x%x not found", rnti);
} }
return ret; return ret;
} }
int mac::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg) int mac::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg)
{ {
int ret = -1;
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (ue_db.contains(rnti)) { return check_ue_active(rnti) ? scheduler.bearer_ue_cfg(rnti, lc_id, *cfg) : -1;
ret = scheduler.bearer_ue_cfg(rnti, lc_id, *cfg);
} else {
logger.error("User rnti=0x%x not found", rnti);
}
return ret;
} }
int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id) int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id)
{ {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
int ret = -1; return check_ue_active(rnti) ? scheduler.bearer_ue_rem(rnti, lc_id) : -1;
if (ue_db.contains(rnti)) {
ret = scheduler.bearer_ue_rem(rnti, lc_id);
} else {
logger.error("User rnti=0x%x not found", rnti);
}
return ret;
} }
void mac::phy_config_enabled(uint16_t rnti, bool enabled) void mac::phy_config_enabled(uint16_t rnti, bool enabled)
@ -202,14 +168,10 @@ void mac::phy_config_enabled(uint16_t rnti, bool enabled)
int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg)
{ {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_active(rnti)) {
auto it = ue_db.find(rnti);
ue* ue_ptr = nullptr;
if (it == ue_db.end()) {
logger.error("User rnti=0x%x not found", rnti);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
ue_ptr = it->second.get(); ue* ue_ptr = ue_db[rnti].get();
// Start TA FSM in UE entity // Start TA FSM in UE entity
ue_ptr->start_ta(); ue_ptr->start_ta();
@ -227,10 +189,9 @@ int mac::ue_rem(uint16_t rnti)
{ {
// Remove UE from the perspective of L2/L3 // Remove UE from the perspective of L2/L3
{ {
srsran::rwlock_write_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (ue_db.contains(rnti)) { if (check_ue_active(rnti)) {
ues_to_rem[rnti] = std::move(ue_db[rnti]); ue_db[rnti]->set_active(false);
ue_db.erase(rnti);
} else { } else {
logger.error("User rnti=0x%x not found", rnti); logger.error("User rnti=0x%x not found", rnti);
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -242,7 +203,8 @@ int mac::ue_rem(uint16_t rnti)
// Note: Let any pending retx ACK to arrive, so that PHY recognizes rnti // Note: Let any pending retx ACK to arrive, so that PHY recognizes rnti
task_sched.defer_callback(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS, [this, rnti]() { task_sched.defer_callback(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS, [this, rnti]() {
phy_h->rem_rnti(rnti); phy_h->rem_rnti(rnti);
ues_to_rem.erase(rnti); srsran::rwlock_write_guard lock(rwlock);
ue_db.erase(rnti);
logger.info("User rnti=0x%x removed from MAC/PHY", rnti); logger.info("User rnti=0x%x removed from MAC/PHY", rnti);
}); });
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
@ -259,11 +221,7 @@ int mac::ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_c
// Schedule ConRes Msg4 // Schedule ConRes Msg4
scheduler.dl_mac_buffer_state(crnti, (uint32_t)srsran::dl_sch_lcid::CON_RES_ID); scheduler.dl_mac_buffer_state(crnti, (uint32_t)srsran::dl_sch_lcid::CON_RES_ID);
} }
int ret = ue_cfg(crnti, cfg); return ue_cfg(crnti, cfg);
if (ret != SRSRAN_SUCCESS) {
return ret;
}
return ret;
} }
int mac::cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg_) int mac::cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg_)
@ -313,7 +271,7 @@ int mac::ack_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t
logger.set_context(tti_rx); logger.set_context(tti_rx);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -330,7 +288,7 @@ int mac::crc_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t
logger.set_context(tti_rx); logger.set_context(tti_rx);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -352,7 +310,7 @@ int mac::push_pdu(uint32_t tti_rx,
{ {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -380,8 +338,10 @@ int mac::push_pdu(uint32_t tti_rx,
(int)pdu->size()); (int)pdu->size());
auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) { auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (ue_db.contains(rnti)) { if (check_ue_active(rnti)) {
ue_db[rnti]->process_pdu(std::move(pdu), ul_nof_prbs); ue_db[rnti]->process_pdu(std::move(pdu), ul_nof_prbs);
} else {
logger.debug("Discarding PDU rnti=0x%x", rnti);
} }
}; };
auto ret = stack_task_queue.try_push(std::bind(process_pdu_task, std::move(pdu))); auto ret = stack_task_queue.try_push(std::bind(process_pdu_task, std::move(pdu)));
@ -396,7 +356,7 @@ int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_v
logger.set_context(tti); logger.set_context(tti);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -411,7 +371,7 @@ int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi
logger.set_context(tti); logger.set_context(tti);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -426,7 +386,7 @@ int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi
logger.set_context(tti); logger.set_context(tti);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -441,7 +401,7 @@ int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr
logger.set_context(tti_rx); logger.set_context(tti_rx);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -454,13 +414,13 @@ int mac::ta_info(uint32_t tti, uint16_t rnti, float ta_us)
{ {
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
uint32_t nof_ta_count = ue_db[rnti]->set_ta_us(ta_us); uint32_t nof_ta_count = ue_db[rnti]->set_ta_us(ta_us);
if (nof_ta_count) { if (nof_ta_count > 0) {
scheduler.dl_mac_buffer_state(rnti, (uint32_t)srsran::dl_sch_lcid::TA_CMD, nof_ta_count); return scheduler.dl_mac_buffer_state(rnti, (uint32_t)srsran::dl_sch_lcid::TA_CMD, nof_ta_count);
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -470,65 +430,64 @@ int mac::sr_detected(uint32_t tti, uint16_t rnti)
logger.set_context(tti); logger.set_context(tti);
srsran::rwlock_read_guard lock(rwlock); srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_exists(rnti)) { if (not check_ue_active(rnti)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
return scheduler.ul_sr_info(tti, rnti); return scheduler.ul_sr_info(tti, rnti);
} }
uint16_t mac::allocate_rnti() bool mac::is_valid_rnti_unprotected(uint16_t rnti)
{ {
std::lock_guard<std::mutex> lock(rnti_mutex); if (not started) {
logger.info("RACH ignored as eNB is being shutdown");
// Assign a c-rnti return false;
uint16_t rnti = last_rnti++;
if (last_rnti >= 60000) {
last_rnti = 70;
} }
if (ue_db.full()) {
return rnti; logger.warning("Maximum number of connected UEs %zd connected to the eNB. Ignoring PRACH", SRSENB_MAX_UES);
return false;
}
if (not ue_db.has_space(rnti)) {
logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti);
return false;
}
return true;
} }
uint16_t mac::allocate_ue() uint16_t mac::allocate_ue()
{ {
ue* inserted_ue = nullptr; ue* inserted_ue = nullptr;
uint16_t rnti = SRSRAN_INVALID_RNTI;
do { do {
// Get pre-allocated UE object // Assign new RNTI
std::unique_ptr<ue> ue_ptr; rnti = FIRST_RNTI + (ue_counter.fetch_add(1, std::memory_order_relaxed) % 60000);
if (not ue_pool.try_pop(ue_ptr)) {
logger.error("UE pool empty. Ignoring RACH attempt.");
return SRSRAN_INVALID_RNTI;
}
uint16_t rnti = ue_ptr->get_rnti();
// Add UE to map // Pre-check if rnti is valid
{ {
srsran::rwlock_write_guard lock(rwlock); srsran::rwlock_read_guard read_lock(rwlock);
if (not started) { if (not is_valid_rnti_unprotected(rnti)) {
logger.info("RACH ignored as eNB is being shutdown"); continue;
return SRSRAN_INVALID_RNTI;
}
if (ue_db.size() >= SRSENB_MAX_UES) {
logger.warning("Maximum number of connected UEs %zd connected to the eNB. Ignoring PRACH", SRSENB_MAX_UES);
return SRSRAN_INVALID_RNTI;
}
auto ret = ue_db.insert(rnti, std::move(ue_ptr));
if (ret) {
inserted_ue = ret.value()->second.get();
} else {
logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti);
} }
} }
// Allocate one new UE object in advance // Allocate and initialize UE object
srsran::get_background_workers().push_task([this]() { prealloc_ue(1); }); unique_rnti_ptr<ue> ue_ptr = make_rnti_obj<ue>(
rnti, rnti, args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get());
// Add UE to rnti map
srsran::rwlock_write_guard rw_lock(rwlock);
if (not is_valid_rnti_unprotected(rnti)) {
continue;
}
auto ret = ue_db.insert(rnti, std::move(ue_ptr));
if (ret.has_value()) {
inserted_ue = ret.value()->second.get();
} else {
logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti);
}
} while (inserted_ue == nullptr); } while (inserted_ue == nullptr);
// RNTI allocation was successful
uint16_t rnti = inserted_ue->get_rnti();
// Set PCAP if available // Set PCAP if available
if (pcap != nullptr) { if (pcap != nullptr) {
inserted_ue->start_pcap(pcap); inserted_ue->start_pcap(pcap);
@ -614,18 +573,6 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx
}); });
} }
void mac::prealloc_ue(uint32_t nof_ue)
{
for (uint32_t i = 0; i < nof_ue; i++) {
std::unique_ptr<ue> ptr = std::unique_ptr<ue>(new ue(
allocate_rnti(), args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get()));
if (not ue_pool.try_push(std::move(ptr))) {
logger.info("Cannot preallocate more UEs as pool is full");
return;
}
}
}
int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list)
{ {
if (!started) { if (!started) {
@ -1045,15 +992,13 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_,
} }
// Internal helper function, caller must hold UE DB rwlock // Internal helper function, caller must hold UE DB rwlock
bool mac::check_ue_exists(uint16_t rnti) bool mac::check_ue_active(uint16_t rnti)
{ {
if (not ue_db.contains(rnti)) { if (not ue_db.contains(rnti)) {
if (not ues_to_rem.count(rnti)) { logger.error("User rnti=0x%x not found", rnti);
logger.error("User rnti=0x%x not found", rnti);
}
return false; return false;
} }
return true; return ue_db[rnti]->is_active();
} }
} // namespace srsenb } // namespace srsenb

@ -28,7 +28,6 @@ class mac_dummy : public mac_interface_rrc
{ {
public: public:
int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) override { return 0; } int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) override { return 0; }
void reset() override {}
int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override { return 0; } int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override { return 0; }
int ue_rem(uint16_t rnti) override { return 0; } int ue_rem(uint16_t rnti) override { return 0; }
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) override { return 0; } int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) override { return 0; }

Loading…
Cancel
Save