|
|
|
@ -48,10 +48,6 @@ bool mac::init(const mac_args_t& args_,
|
|
|
|
|
rrc_interface_mac* rrc)
|
|
|
|
|
{
|
|
|
|
|
started = false;
|
|
|
|
|
|
|
|
|
|
if (not phy or not rlc) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
phy_h = phy;
|
|
|
|
|
rlc_h = rlc;
|
|
|
|
|
rrc_h = rrc;
|
|
|
|
@ -74,8 +70,6 @@ bool mac::init(const mac_args_t& args_,
|
|
|
|
|
srsran_softbuffer_tx_init(&cc.rar_softbuffer_tx, args.nof_prb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reset();
|
|
|
|
|
|
|
|
|
|
// Initiate common pool of softbuffers
|
|
|
|
|
uint32_t nof_prb = args.nof_prb;
|
|
|
|
|
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>(
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
started = true;
|
|
|
|
@ -108,21 +99,9 @@ void mac::stop()
|
|
|
|
|
srsran_softbuffer_tx_free(&cc.pcch_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_)
|
|
|
|
|
{
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
@ -148,11 +127,12 @@ void mac::start_pcap_net(srsran::mac_pcap_net* pcap_net_)
|
|
|
|
|
* RLC interface
|
|
|
|
|
*
|
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
int ret = -1;
|
|
|
|
|
if (ue_db.contains(rnti)) {
|
|
|
|
|
if (check_ue_active(rnti)) {
|
|
|
|
|
if (rnti != SRSRAN_MRNTI) {
|
|
|
|
|
ret = scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
|
|
|
|
|
} else {
|
|
|
|
@ -163,34 +143,20 @@ int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint
|
|
|
|
|
}
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
logger.error("User rnti=0x%x not found", rnti);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
if (ue_db.contains(rnti)) {
|
|
|
|
|
ret = scheduler.bearer_ue_cfg(rnti, lc_id, *cfg);
|
|
|
|
|
} else {
|
|
|
|
|
logger.error("User rnti=0x%x not found", rnti);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
return check_ue_active(rnti) ? scheduler.bearer_ue_cfg(rnti, lc_id, *cfg) : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id)
|
|
|
|
|
{
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
int ret = -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;
|
|
|
|
|
return check_ue_active(rnti) ? scheduler.bearer_ue_rem(rnti, lc_id) : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
auto it = ue_db.find(rnti);
|
|
|
|
|
ue* ue_ptr = nullptr;
|
|
|
|
|
if (it == ue_db.end()) {
|
|
|
|
|
logger.error("User rnti=0x%x not found", rnti);
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
ue_ptr = it->second.get();
|
|
|
|
|
ue* ue_ptr = ue_db[rnti].get();
|
|
|
|
|
|
|
|
|
|
// Start TA FSM in UE entity
|
|
|
|
|
ue_ptr->start_ta();
|
|
|
|
@ -227,10 +189,9 @@ int mac::ue_rem(uint16_t rnti)
|
|
|
|
|
{
|
|
|
|
|
// Remove UE from the perspective of L2/L3
|
|
|
|
|
{
|
|
|
|
|
srsran::rwlock_write_guard lock(rwlock);
|
|
|
|
|
if (ue_db.contains(rnti)) {
|
|
|
|
|
ues_to_rem[rnti] = std::move(ue_db[rnti]);
|
|
|
|
|
ue_db.erase(rnti);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
if (check_ue_active(rnti)) {
|
|
|
|
|
ue_db[rnti]->set_active(false);
|
|
|
|
|
} else {
|
|
|
|
|
logger.error("User rnti=0x%x not found", rnti);
|
|
|
|
|
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
|
|
|
|
|
task_sched.defer_callback(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS, [this, 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);
|
|
|
|
|
});
|
|
|
|
|
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
|
|
|
|
|
scheduler.dl_mac_buffer_state(crnti, (uint32_t)srsran::dl_sch_lcid::CON_RES_ID);
|
|
|
|
|
}
|
|
|
|
|
int ret = ue_cfg(crnti, cfg);
|
|
|
|
|
if (ret != SRSRAN_SUCCESS) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
return ue_cfg(crnti, 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);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
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);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -352,7 +310,7 @@ int mac::push_pdu(uint32_t tti_rx,
|
|
|
|
|
{
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -380,8 +338,10 @@ int mac::push_pdu(uint32_t tti_rx,
|
|
|
|
|
(int)pdu->size());
|
|
|
|
|
auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) {
|
|
|
|
|
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);
|
|
|
|
|
} else {
|
|
|
|
|
logger.debug("Discarding PDU rnti=0x%x", rnti);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
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);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
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);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
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);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
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);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t nof_ta_count = ue_db[rnti]->set_ta_us(ta_us);
|
|
|
|
|
if (nof_ta_count) {
|
|
|
|
|
scheduler.dl_mac_buffer_state(rnti, (uint32_t)srsran::dl_sch_lcid::TA_CMD, nof_ta_count);
|
|
|
|
|
if (nof_ta_count > 0) {
|
|
|
|
|
return scheduler.dl_mac_buffer_state(rnti, (uint32_t)srsran::dl_sch_lcid::TA_CMD, nof_ta_count);
|
|
|
|
|
}
|
|
|
|
|
return SRSRAN_SUCCESS;
|
|
|
|
|
}
|
|
|
|
@ -470,65 +430,64 @@ int mac::sr_detected(uint32_t tti, uint16_t rnti)
|
|
|
|
|
logger.set_context(tti);
|
|
|
|
|
srsran::rwlock_read_guard lock(rwlock);
|
|
|
|
|
|
|
|
|
|
if (not check_ue_exists(rnti)) {
|
|
|
|
|
if (not check_ue_active(rnti)) {
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
// Assign a c-rnti
|
|
|
|
|
uint16_t rnti = last_rnti++;
|
|
|
|
|
if (last_rnti >= 60000) {
|
|
|
|
|
last_rnti = 70;
|
|
|
|
|
if (not started) {
|
|
|
|
|
logger.info("RACH ignored as eNB is being shutdown");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rnti;
|
|
|
|
|
if (ue_db.full()) {
|
|
|
|
|
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()
|
|
|
|
|
{
|
|
|
|
|
ue* inserted_ue = nullptr;
|
|
|
|
|
uint16_t rnti = SRSRAN_INVALID_RNTI;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
// Get pre-allocated UE object
|
|
|
|
|
std::unique_ptr<ue> ue_ptr;
|
|
|
|
|
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();
|
|
|
|
|
// Assign new RNTI
|
|
|
|
|
rnti = FIRST_RNTI + (ue_counter.fetch_add(1, std::memory_order_relaxed) % 60000);
|
|
|
|
|
|
|
|
|
|
// Add UE to map
|
|
|
|
|
// Pre-check if rnti is valid
|
|
|
|
|
{
|
|
|
|
|
srsran::rwlock_write_guard lock(rwlock);
|
|
|
|
|
if (not started) {
|
|
|
|
|
logger.info("RACH ignored as eNB is being shutdown");
|
|
|
|
|
return SRSRAN_INVALID_RNTI;
|
|
|
|
|
srsran::rwlock_read_guard read_lock(rwlock);
|
|
|
|
|
if (not is_valid_rnti_unprotected(rnti)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocate and initialize UE object
|
|
|
|
|
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) {
|
|
|
|
|
if (ret.has_value()) {
|
|
|
|
|
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
|
|
|
|
|
srsran::get_background_workers().push_task([this]() { prealloc_ue(1); });
|
|
|
|
|
|
|
|
|
|
} while (inserted_ue == nullptr);
|
|
|
|
|
|
|
|
|
|
// RNTI allocation was successful
|
|
|
|
|
uint16_t rnti = inserted_ue->get_rnti();
|
|
|
|
|
|
|
|
|
|
// Set PCAP if available
|
|
|
|
|
if (pcap != nullptr) {
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
bool mac::check_ue_exists(uint16_t rnti)
|
|
|
|
|
bool mac::check_ue_active(uint16_t rnti)
|
|
|
|
|
{
|
|
|
|
|
if (not ue_db.contains(rnti)) {
|
|
|
|
|
if (not ues_to_rem.count(rnti)) {
|
|
|
|
|
logger.error("User rnti=0x%x not found", rnti);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
return ue_db[rnti]->is_active();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace srsenb
|
|
|
|
|